a2acalling 0.6.74 → 0.6.75
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.
- package/.a2a-manifest.json +2 -2
- package/.c8rc.json +16 -0
- package/.node-version +1 -0
- package/.serena/project.yml +126 -0
- package/ARCHITECTURE.md +11 -0
- package/CONVENTIONS.md +9 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +146 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/index.html +131 -0
- package/coverage/src/index.js.html +313 -0
- package/coverage/src/lib/agent-card.js.html +418 -0
- package/coverage/src/lib/call-monitor.js.html +700 -0
- package/coverage/src/lib/callbook.js.html +1183 -0
- package/coverage/src/lib/claude-subagent.js.html +2173 -0
- package/coverage/src/lib/client.js.html +2134 -0
- package/coverage/src/lib/config.js.html +1525 -0
- package/coverage/src/lib/conversation-driver.js.html +1909 -0
- package/coverage/src/lib/conversations.js.html +2575 -0
- package/coverage/src/lib/crypto.js.html +424 -0
- package/coverage/src/lib/dashboard-events.js.html +724 -0
- package/coverage/src/lib/disclosure.js.html +2461 -0
- package/coverage/src/lib/external-ip.js.html +718 -0
- package/coverage/src/lib/index.html +506 -0
- package/coverage/src/lib/invite-host.js.html +754 -0
- package/coverage/src/lib/local-request.js.html +292 -0
- package/coverage/src/lib/logger.js.html +2116 -0
- package/coverage/src/lib/openclaw-integration.js.html +1102 -0
- package/coverage/src/lib/pid-file.js.html +394 -0
- package/coverage/src/lib/port-scanner.js.html +334 -0
- package/coverage/src/lib/prompt-template.js.html +1150 -0
- package/coverage/src/lib/runtime-adapter.js.html +2188 -0
- package/coverage/src/lib/summarizer.js.html +553 -0
- package/coverage/src/lib/summary-formatter.js.html +589 -0
- package/coverage/src/lib/summary-prompt.js.html +694 -0
- package/coverage/src/lib/tokens.js.html +2689 -0
- package/coverage/src/lib/turn-timeout.js.html +241 -0
- package/coverage/src/lib/update-checker.js.html +364 -0
- package/coverage/src/lib/update-manager.js.html +1024 -0
- package/coverage/src/routes/a2a.js.html +3724 -0
- package/coverage/src/routes/callbook.js.html +511 -0
- package/coverage/src/routes/dashboard.js.html +4819 -0
- package/coverage/src/routes/index.html +146 -0
- package/coverage/src/server.js.html +3622 -0
- package/coverage/tmp/coverage-1605378-1772576706365-0.json +1 -0
- package/coverage/tmp/coverage-1605384-1772576607459-0.json +1 -0
- package/coverage/tmp/coverage-1605410-1772576631155-0.json +1 -0
- package/coverage/tmp/coverage-1606942-1772576636869-0.json +1 -0
- package/coverage/tmp/coverage-1607004-1772576637454-0.json +1 -0
- package/coverage/tmp/coverage-1607044-1772576637876-0.json +1 -0
- package/coverage/tmp/coverage-1607096-1772576638356-0.json +1 -0
- package/coverage/tmp/coverage-1607145-1772576638777-0.json +1 -0
- package/coverage/tmp/coverage-1607201-1772576639277-0.json +1 -0
- package/coverage/tmp/coverage-1607247-1772576639755-0.json +1 -0
- package/coverage/tmp/coverage-1607317-1772576640083-0.json +1 -0
- package/coverage/tmp/coverage-1607381-1772576640465-0.json +1 -0
- package/coverage/tmp/coverage-1607446-1772576640868-0.json +1 -0
- package/coverage/tmp/coverage-1607501-1772576641662-0.json +1 -0
- package/coverage/tmp/coverage-1607534-1772576641565-0.json +1 -0
- package/coverage/tmp/coverage-1607627-1772576641871-0.json +1 -0
- package/coverage/tmp/coverage-1607665-1772576642172-0.json +1 -0
- package/coverage/tmp/coverage-1607714-1772576642577-0.json +1 -0
- package/coverage/tmp/coverage-1607788-1772576643466-0.json +1 -0
- package/coverage/tmp/coverage-1607924-1772576644678-0.json +1 -0
- package/coverage/tmp/coverage-1607978-1772576645154-0.json +1 -0
- package/coverage/tmp/coverage-1608035-1772576645564-0.json +1 -0
- package/coverage/tmp/coverage-1608106-1772576645967-0.json +1 -0
- package/coverage/tmp/coverage-1608179-1772576648656-0.json +1 -0
- package/coverage/tmp/coverage-1608196-1772576647367-0.json +1 -0
- package/coverage/tmp/coverage-1608217-1772576648557-0.json +1 -0
- package/coverage/tmp/coverage-1608256-1772576651378-0.json +1 -0
- package/coverage/tmp/coverage-1608265-1772576650058-0.json +1 -0
- package/coverage/tmp/coverage-1608289-1772576651358-0.json +1 -0
- package/coverage/tmp/coverage-1608591-1772576660465-0.json +1 -0
- package/coverage/tmp/coverage-1608648-1772576659272-0.json +1 -0
- package/coverage/tmp/coverage-1608665-1772576660374-0.json +1 -0
- package/coverage/tmp/coverage-1608677-1772576661268-0.json +1 -0
- package/coverage/tmp/coverage-1608684-1772576663968-0.json +1 -0
- package/coverage/tmp/coverage-1608692-1772576662575-0.json +1 -0
- package/coverage/tmp/coverage-1608701-1772576663873-0.json +1 -0
- package/coverage/tmp/coverage-1608718-1772576666674-0.json +1 -0
- package/coverage/tmp/coverage-1608725-1772576665463-0.json +1 -0
- package/coverage/tmp/coverage-1608738-1772576666577-0.json +1 -0
- package/coverage/tmp/coverage-1608753-1772576669664-0.json +1 -0
- package/coverage/tmp/coverage-1608763-1772576668275-0.json +1 -0
- package/coverage/tmp/coverage-1608771-1772576669563-0.json +1 -0
- package/coverage/tmp/coverage-1608828-1772576676574-0.json +1 -0
- package/coverage/tmp/coverage-1609244-1772576675272-0.json +1 -0
- package/coverage/tmp/coverage-1609342-1772576676478-0.json +1 -0
- package/coverage/tmp/coverage-1609450-1772576686954-0.json +1 -0
- package/coverage/tmp/coverage-1609841-1772576685466-0.json +1 -0
- package/coverage/tmp/coverage-1609925-1772576686855-0.json +1 -0
- package/coverage/tmp/coverage-1610399-1772576692469-0.json +1 -0
- package/coverage/tmp/coverage-1611283-1772576703062-0.json +1 -0
- package/coverage/tmp/coverage-1611294-1772576703755-0.json +1 -0
- package/docs/plans/2026-03-03-a2a-91-macos-packaging-plan.md +144 -0
- package/docs/signing-setup.md +49 -0
- package/native/macos/certs/appldevcert.cer +0 -0
- package/native/macos/src-tauri/binaries/.gitkeep +0 -0
- package/native/macos/src-tauri/capabilities/default.json +11 -1
- package/native/macos/src-tauri/entitlements.plist +14 -0
- package/native/macos/src-tauri/src/discovery.rs +14 -3
- package/native/macos/src-tauri/src/health.rs +4 -0
- package/native/macos/src-tauri/src/lib.rs +52 -11
- package/native/macos/src-tauri/src/server.rs +262 -26
- package/native/macos/src-tauri/tauri.conf.json +13 -4
- package/package.json +7 -2
- package/pkg.config.json +14 -0
- package/scripts/build-standalone.sh +106 -0
- package/scripts/smoke-test-standalone.sh +101 -0
- package/scripts/sync-version.sh +28 -0
- package/scripts/verify-app-bundle.sh +34 -0
- package/.maestro/inbox/release-workflow-spam.md +0 -25
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# A2A-91: macOS App Packaging Plan
|
|
2
|
+
|
|
3
|
+
## Executive Summary
|
|
4
|
+
|
|
5
|
+
A2A Callbook currently exists as a Tauri v2 wrapper (`native/macos/`) that discovers a separately-running Node.js server via port scanning. To distribute a self-contained macOS app, we need to bundle the Node.js Express server as a Tauri sidecar binary, add code signing + notarization, and set up CI/CD for automated builds.
|
|
6
|
+
|
|
7
|
+
**Recommended approach**: Tauri v2 + `@yao-pkg/pkg` sidecar (pragmatic today), with migration path to Node.js SEA as it matures.
|
|
8
|
+
|
|
9
|
+
**App Store verdict**: Not viable. Node.js uses V8 JIT which conflicts with Apple's sandbox requirements. Direct DMG distribution with Developer ID signing + notarization is the correct path.
|
|
10
|
+
|
|
11
|
+
## Current State
|
|
12
|
+
|
|
13
|
+
| Aspect | Status |
|
|
14
|
+
|--------|--------|
|
|
15
|
+
| Tauri v2 shell | Working (v0.1.0) — menus, tray, deep links, SSE notifications |
|
|
16
|
+
| Server integration | External discovery only (`which a2a` + port scan) |
|
|
17
|
+
| Code signing | Not configured |
|
|
18
|
+
| Notarization | Not configured |
|
|
19
|
+
| Distribution | Unsigned `.app` + `.dmg` via GitHub Releases |
|
|
20
|
+
| CI/CD | `tauri-build.yml` exists but no signing secrets |
|
|
21
|
+
|
|
22
|
+
## Architecture Decision
|
|
23
|
+
|
|
24
|
+
### Why Tauri + Sidecar (not Electron)
|
|
25
|
+
|
|
26
|
+
| Factor | Tauri + Sidecar | Electron |
|
|
27
|
+
|--------|----------------|----------|
|
|
28
|
+
| App size | ~95MB | ~150MB |
|
|
29
|
+
| Memory | ~80MB | ~300MB |
|
|
30
|
+
| Existing code | Keep all Rust code | Rewrite from scratch |
|
|
31
|
+
| Native feel | WebKit (system) | Chromium (bundled) |
|
|
32
|
+
| Risk | Medium (new sidecar pipeline) | High (full rewrite) |
|
|
33
|
+
|
|
34
|
+
Tauri is already working. The incremental cost of adding a sidecar is far lower than an Electron migration.
|
|
35
|
+
|
|
36
|
+
### Why @yao-pkg/pkg (not Node.js SEA today)
|
|
37
|
+
|
|
38
|
+
- **pkg** auto-extracts native `.node` addons (better-sqlite3) — SEA requires manual `process.dlopen()` shims
|
|
39
|
+
- Tauri's official sidecar-nodejs guide recommends pkg
|
|
40
|
+
- Migration to Node.js SEA is straightforward once `--build-sea` stabilizes (Node 25.5+)
|
|
41
|
+
|
|
42
|
+
### Why not App Store
|
|
43
|
+
|
|
44
|
+
Node.js embeds V8 JIT. Apple's Guideline 2.5.2 restricts JIT in sandboxed apps. The `com.apple.security.cs.allow-jit` entitlement exists but requires justification and has no precedent for Tauri+Node.js apps. Direct DMG distribution with notarization is the proven path.
|
|
45
|
+
|
|
46
|
+
## Implementation Phases
|
|
47
|
+
|
|
48
|
+
### Phase 1: Standalone Node.js Binary (Core)
|
|
49
|
+
|
|
50
|
+
Create a build pipeline that compiles the Express server + better-sqlite3 into a single executable using `@yao-pkg/pkg`.
|
|
51
|
+
|
|
52
|
+
**Key challenges:**
|
|
53
|
+
- better-sqlite3 native addon must be compiled for the exact Node.js version pkg embeds
|
|
54
|
+
- Universal binary support (aarch64 + x86_64) requires two pkg builds + `lipo`
|
|
55
|
+
- The standalone binary must respect `A2A_CONFIG_DIR` and all existing env vars
|
|
56
|
+
|
|
57
|
+
**Deliverables:**
|
|
58
|
+
- `scripts/build-standalone.sh` — compiles server into standalone binary
|
|
59
|
+
- Verification: binary starts, serves dashboard, handles calls in `A2A_RUNTIME=test`
|
|
60
|
+
|
|
61
|
+
### Phase 2: Tauri Sidecar Integration
|
|
62
|
+
|
|
63
|
+
Replace the current `which a2a` server discovery in `server.rs` with Tauri's sidecar API.
|
|
64
|
+
|
|
65
|
+
**Changes:**
|
|
66
|
+
- Place pkg output in `src-tauri/binaries/a2a-server-{target-triple}`
|
|
67
|
+
- Add `externalBin` to `tauri.conf.json`
|
|
68
|
+
- Rewrite `server.rs` to use `app.shell().sidecar("a2a-server")` instead of `which`
|
|
69
|
+
- Update `discovery.rs` to check sidecar health before falling back to external
|
|
70
|
+
- Add graceful shutdown: send SIGTERM to sidecar on app quit
|
|
71
|
+
|
|
72
|
+
### Phase 3: Code Signing + Notarization
|
|
73
|
+
|
|
74
|
+
Set up Apple Developer ID signing and notarization for Gatekeeper compliance.
|
|
75
|
+
|
|
76
|
+
**Requirements:**
|
|
77
|
+
- Apple Developer Program membership ($99/year)
|
|
78
|
+
- Developer ID Application certificate
|
|
79
|
+
- App-specific password or App Store Connect API key
|
|
80
|
+
|
|
81
|
+
**Changes:**
|
|
82
|
+
- Add signing identity to `tauri.conf.json` `bundle.macOS.signingIdentity`
|
|
83
|
+
- Create entitlements plist (network access, JIT for V8)
|
|
84
|
+
- Add GitHub Actions secrets for signing credentials
|
|
85
|
+
- Notarization via `xcrun notarytool` (Tauri handles this automatically when env vars are set)
|
|
86
|
+
|
|
87
|
+
### Phase 4: CI/CD Pipeline
|
|
88
|
+
|
|
89
|
+
Automate the full build → sign → notarize → release pipeline.
|
|
90
|
+
|
|
91
|
+
**Changes:**
|
|
92
|
+
- Update `tauri-build.yml` to:
|
|
93
|
+
1. Build standalone Node.js binary (pkg)
|
|
94
|
+
2. Place in `src-tauri/binaries/`
|
|
95
|
+
3. Build universal Tauri app (`--target universal-apple-darwin`)
|
|
96
|
+
4. Sign + notarize
|
|
97
|
+
5. Upload `.dmg` to GitHub Release
|
|
98
|
+
- Add version sync between `package.json` and `tauri.conf.json`
|
|
99
|
+
|
|
100
|
+
### Phase 5: Server Lifecycle Management
|
|
101
|
+
|
|
102
|
+
The self-contained app should fully manage the A2A server lifecycle.
|
|
103
|
+
|
|
104
|
+
**Changes:**
|
|
105
|
+
- Start sidecar on app launch, stop on quit
|
|
106
|
+
- Restart on crash (with backoff)
|
|
107
|
+
- Port allocation: pick available port, pass to sidecar via args
|
|
108
|
+
- Show server status in tray icon (connected/disconnected already exists)
|
|
109
|
+
- Log sidecar stdout/stderr for debugging
|
|
110
|
+
|
|
111
|
+
### Phase 6: Testing Infrastructure
|
|
112
|
+
|
|
113
|
+
Add automated testing for the packaging pipeline.
|
|
114
|
+
|
|
115
|
+
**Changes:**
|
|
116
|
+
- Smoke test: build standalone binary, verify it starts and responds to `/api/a2a/status`
|
|
117
|
+
- Integration test: build full `.app`, verify sidecar spawns correctly
|
|
118
|
+
- CI matrix: test on macOS 12 (Monterey), 13 (Ventura), 14 (Sonoma), 15 (Sequoia)
|
|
119
|
+
|
|
120
|
+
## Resource Estimates
|
|
121
|
+
|
|
122
|
+
| Item | Cost | Recurrence |
|
|
123
|
+
|------|------|------------|
|
|
124
|
+
| Apple Developer Program | $99 | Annual |
|
|
125
|
+
| GitHub Actions macOS runner | ~$0.08/min | Per build |
|
|
126
|
+
| Developer time (Phases 1-6) | ~40-60 hours | One-time |
|
|
127
|
+
|
|
128
|
+
## Risk Register
|
|
129
|
+
|
|
130
|
+
| Risk | Likelihood | Impact | Mitigation |
|
|
131
|
+
|------|-----------|--------|------------|
|
|
132
|
+
| better-sqlite3 version mismatch with pkg | Medium | High | Pin Node.js version, test in CI |
|
|
133
|
+
| Apple notarization rejection | Low | High | Entitlements plist, hardened runtime |
|
|
134
|
+
| pkg deprecation (community fork) | Medium | Medium | Migration path to Node.js SEA ready |
|
|
135
|
+
| V8 JIT blocked by future macOS | Low | High | Monitor Apple policy; sql.js (Wasm) fallback for SQLite |
|
|
136
|
+
|
|
137
|
+
## Migration Path to Node.js SEA
|
|
138
|
+
|
|
139
|
+
When Node.js SEA `--build-sea` reaches stability (currently 1.1 as of Node 25.5):
|
|
140
|
+
1. Replace `@yao-pkg/pkg` with `node --build-sea`
|
|
141
|
+
2. Add esbuild bundling step (pkg handles this; SEA needs it explicit)
|
|
142
|
+
3. Add `process.dlopen()` shim for better-sqlite3
|
|
143
|
+
4. Update `scripts/build-standalone.sh`
|
|
144
|
+
5. No Tauri changes needed — sidecar interface is the same
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# macOS Signing & Notarization Setup (A2A-94)
|
|
2
|
+
|
|
3
|
+
This document describes the required Apple credentials for signed, notarized macOS release artifacts.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Apple Developer Program membership (active)
|
|
8
|
+
- Developer ID Application certificate for your team
|
|
9
|
+
- Access to GitHub repository secrets for this project
|
|
10
|
+
|
|
11
|
+
## 1) Create a Developer ID Application certificate
|
|
12
|
+
|
|
13
|
+
1. Open Apple Developer portal → Certificates, IDs & Profiles.
|
|
14
|
+
2. Create a new **Developer ID Application** certificate.
|
|
15
|
+
3. Export the certificate + private key from Keychain as `.p12`.
|
|
16
|
+
4. Protect the `.p12` export with a strong password.
|
|
17
|
+
|
|
18
|
+
## 2) Create GitHub Actions secrets
|
|
19
|
+
|
|
20
|
+
Upload the following repository secrets:
|
|
21
|
+
|
|
22
|
+
- `APPLE_CERTIFICATE`: base64-encoded `.p12` archive
|
|
23
|
+
- `APPLE_CERTIFICATE_PASSWORD`: password used for `.p12` export
|
|
24
|
+
- `APPLE_SIGNING_IDENTITY`: exact certificate identity string
|
|
25
|
+
- `APPLE_ID`: Apple account email used for notarization
|
|
26
|
+
- `APPLE_PASSWORD`: app-specific password for notarization
|
|
27
|
+
- `APPLE_TEAM_ID`: Apple Developer Team ID
|
|
28
|
+
|
|
29
|
+
Example identity format:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
Developer ID Application: Your Name (TEAMID)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 3) Validate the release output
|
|
36
|
+
|
|
37
|
+
The macOS build workflow verifies all three checks before publishing artifacts:
|
|
38
|
+
|
|
39
|
+
- `codesign --verify --deep --strict` on the `.app`
|
|
40
|
+
- `spctl --assess --type execute` on the `.app`
|
|
41
|
+
- `xcrun stapler validate` on the `.dmg`
|
|
42
|
+
|
|
43
|
+
A release is considered valid only when all checks pass.
|
|
44
|
+
|
|
45
|
+
## Security notes
|
|
46
|
+
|
|
47
|
+
- Never commit `.p12`, `.cer`, or private key material.
|
|
48
|
+
- Keep certificate exports in a local, encrypted store only.
|
|
49
|
+
- Rotate Apple app-specific passwords if they are exposed.
|
|
Binary file
|
|
File without changes
|
|
@@ -11,6 +11,16 @@
|
|
|
11
11
|
"notification:allow-request-permission",
|
|
12
12
|
"notification:allow-notify",
|
|
13
13
|
"deep-link:default",
|
|
14
|
-
"window-state:default"
|
|
14
|
+
"window-state:default",
|
|
15
|
+
{
|
|
16
|
+
"identifier": "shell:allow-execute",
|
|
17
|
+
"allow": [
|
|
18
|
+
{
|
|
19
|
+
"name": "binaries/a2a-server",
|
|
20
|
+
"sidecar": true,
|
|
21
|
+
"args": true
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
15
25
|
]
|
|
16
26
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>com.apple.security.cs.allow-jit</key>
|
|
6
|
+
<true/>
|
|
7
|
+
<key>com.apple.security.network.client</key>
|
|
8
|
+
<true/>
|
|
9
|
+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
|
10
|
+
<true/>
|
|
11
|
+
<key>com.apple.security.cs.disable-library-validation</key>
|
|
12
|
+
<true/>
|
|
13
|
+
</dict>
|
|
14
|
+
</plist>
|
|
@@ -139,11 +139,22 @@ async fn probe_port(port: u16) -> bool {
|
|
|
139
139
|
false
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
/// Discover the running a2a server
|
|
143
|
-
|
|
142
|
+
/// Discover the running a2a server.
|
|
143
|
+
/// If `sidecar_port` is provided, check it first before config/scan fallback.
|
|
144
|
+
pub async fn discover_server(sidecar_port: Option<u16>) -> DiscoveryResult {
|
|
145
|
+
// 0. Check sidecar port first (highest priority)
|
|
146
|
+
if let Some(port) = sidecar_port {
|
|
147
|
+
if probe_port(port).await {
|
|
148
|
+
return DiscoveryResult {
|
|
149
|
+
port: Some(port),
|
|
150
|
+
source: "sidecar".to_string(),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
144
155
|
let config_ports = read_config_ports();
|
|
145
156
|
|
|
146
|
-
// 1. Try config-derived ports
|
|
157
|
+
// 1. Try config-derived ports
|
|
147
158
|
for &port in &config_ports {
|
|
148
159
|
if probe_port(port).await {
|
|
149
160
|
return DiscoveryResult {
|
|
@@ -18,6 +18,10 @@ pub fn set_connected(port: u16) {
|
|
|
18
18
|
CONNECTED.store(true, Ordering::Relaxed);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
pub fn set_disconnected() {
|
|
22
|
+
CONNECTED.store(false, Ordering::Relaxed);
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
/// Start background health check loop — emits "server-status" events
|
|
22
26
|
pub fn start_health_monitor(app: tauri::AppHandle) {
|
|
23
27
|
tauri::async_runtime::spawn(async move {
|
|
@@ -9,8 +9,13 @@ mod notifications;
|
|
|
9
9
|
mod server;
|
|
10
10
|
|
|
11
11
|
#[tauri::command]
|
|
12
|
-
async fn discover_server() -> Result<discovery::DiscoveryResult, String> {
|
|
13
|
-
let
|
|
12
|
+
async fn discover_server(app: tauri::AppHandle) -> Result<discovery::DiscoveryResult, String> {
|
|
13
|
+
let sidecar_port = app
|
|
14
|
+
.try_state::<server::SidecarState>()
|
|
15
|
+
.map(|state| state.port())
|
|
16
|
+
.filter(|&p| p > 0);
|
|
17
|
+
|
|
18
|
+
let result = discovery::discover_server(sidecar_port).await;
|
|
14
19
|
if let Some(port) = result.port {
|
|
15
20
|
health::set_connected(port);
|
|
16
21
|
}
|
|
@@ -18,8 +23,19 @@ async fn discover_server() -> Result<discovery::DiscoveryResult, String> {
|
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
#[tauri::command]
|
|
21
|
-
fn start_server() -> Result<server::StartResult, String> {
|
|
22
|
-
Ok(server::
|
|
26
|
+
fn start_server(app: tauri::AppHandle) -> Result<server::StartResult, String> {
|
|
27
|
+
Ok(server::start_sidecar(&app))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#[tauri::command]
|
|
31
|
+
fn restart_server(app: tauri::AppHandle) -> Result<server::StartResult, String> {
|
|
32
|
+
let result = server::restart_sidecar(&app);
|
|
33
|
+
if result.success {
|
|
34
|
+
if let Some(port) = result.port {
|
|
35
|
+
health::set_connected(port);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
Ok(result)
|
|
23
39
|
}
|
|
24
40
|
|
|
25
41
|
fn build_menu(app: &tauri::AppHandle) -> tauri::Result<Menu<tauri::Wry>> {
|
|
@@ -45,9 +61,10 @@ fn build_menu(app: &tauri::AppHandle) -> tauri::Result<Menu<tauri::Wry>> {
|
|
|
45
61
|
let logs = MenuItem::with_id(app, "tab-logs", "Logs", true, Some("CmdOrCtrl+5"))?;
|
|
46
62
|
let sep2 = PredefinedMenuItem::separator(app)?;
|
|
47
63
|
let refresh = MenuItem::with_id(app, "refresh", "Refresh", true, Some("CmdOrCtrl+R"))?;
|
|
64
|
+
let restart = MenuItem::with_id(app, "restart-server", "Restart Server", true, None::<&str>)?;
|
|
48
65
|
|
|
49
66
|
let view_menu = Submenu::with_items(app, "View", true, &[
|
|
50
|
-
&contacts, &calls, &settings, &invites, &logs, &sep2, &refresh,
|
|
67
|
+
&contacts, &calls, &settings, &invites, &logs, &sep2, &refresh, &restart,
|
|
51
68
|
])?;
|
|
52
69
|
|
|
53
70
|
// Edit menu (standard macOS)
|
|
@@ -74,7 +91,8 @@ pub fn run() {
|
|
|
74
91
|
.plugin(tauri_plugin_notification::init())
|
|
75
92
|
.plugin(tauri_plugin_deep_link::init())
|
|
76
93
|
.plugin(tauri_plugin_window_state::Builder::new().build())
|
|
77
|
-
.
|
|
94
|
+
.manage(server::SidecarState::new())
|
|
95
|
+
.invoke_handler(tauri::generate_handler![discover_server, start_server, restart_server])
|
|
78
96
|
.setup(|app| {
|
|
79
97
|
let menu = build_menu(app.handle())?;
|
|
80
98
|
app.set_menu(menu)?;
|
|
@@ -96,6 +114,15 @@ pub fn run() {
|
|
|
96
114
|
}
|
|
97
115
|
None
|
|
98
116
|
}
|
|
117
|
+
"restart-server" => {
|
|
118
|
+
let result = server::restart_sidecar(&app_handle);
|
|
119
|
+
if result.success {
|
|
120
|
+
if let Some(port) = result.port {
|
|
121
|
+
health::set_connected(port);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
None
|
|
125
|
+
}
|
|
99
126
|
_ => None,
|
|
100
127
|
};
|
|
101
128
|
|
|
@@ -107,6 +134,14 @@ pub fn run() {
|
|
|
107
134
|
}
|
|
108
135
|
});
|
|
109
136
|
|
|
137
|
+
// Start the bundled A2A server sidecar
|
|
138
|
+
let start_result = server::start_sidecar(app.handle());
|
|
139
|
+
if start_result.success {
|
|
140
|
+
if let Some(port) = start_result.port {
|
|
141
|
+
health::set_connected(port);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
110
145
|
// Start background health monitor
|
|
111
146
|
health::start_health_monitor(app.handle().clone());
|
|
112
147
|
|
|
@@ -173,13 +208,19 @@ pub fn run() {
|
|
|
173
208
|
.build(tauri::generate_context!())
|
|
174
209
|
.expect("error building A2A Callbook");
|
|
175
210
|
|
|
176
|
-
// Cmd+W hides window instead of quitting
|
|
211
|
+
// Cmd+W hides window instead of quitting; kill sidecar on exit
|
|
177
212
|
app.run(|app_handle, event| {
|
|
178
|
-
|
|
179
|
-
api
|
|
180
|
-
|
|
181
|
-
let
|
|
213
|
+
match &event {
|
|
214
|
+
RunEvent::WindowEvent { label, event: WindowEvent::CloseRequested { api, .. }, .. } => {
|
|
215
|
+
api.prevent_close();
|
|
216
|
+
if let Some(window) = app_handle.get_webview_window(label) {
|
|
217
|
+
let _ = window.hide();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
RunEvent::Exit => {
|
|
221
|
+
server::kill_sidecar(app_handle);
|
|
182
222
|
}
|
|
223
|
+
_ => {}
|
|
183
224
|
}
|
|
184
225
|
});
|
|
185
226
|
}
|