a2acalling 0.6.44 → 0.6.45
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/README.md +26 -0
- package/bin/cli.js +47 -0
- package/docs/plans/2026-02-16-a2a-callbook-macos-app.md +1660 -0
- package/docs/plans/2026-02-16-e2e-test-prompt-sequence.md +1812 -0
- package/native/macos/index.html +172 -0
- package/native/macos/package.json +8 -0
- package/native/macos/src-tauri/Cargo.toml +23 -0
- package/native/macos/src-tauri/build.rs +3 -0
- package/native/macos/src-tauri/capabilities/default.json +16 -0
- package/native/macos/src-tauri/icons/128x128.png +0 -0
- package/native/macos/src-tauri/icons/128x128@2x.png +0 -0
- package/native/macos/src-tauri/icons/32x32.png +0 -0
- package/native/macos/src-tauri/icons/icon.icns +0 -0
- package/native/macos/src-tauri/icons/tray-connected.png +0 -0
- package/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
- package/native/macos/src-tauri/src/discovery.rs +86 -0
- package/native/macos/src-tauri/src/health.rs +64 -0
- package/native/macos/src-tauri/src/lib.rs +185 -0
- package/native/macos/src-tauri/src/main.rs +6 -0
- package/native/macos/src-tauri/src/notifications.rs +101 -0
- package/native/macos/src-tauri/src/server.rs +67 -0
- package/native/macos/src-tauri/tauri.conf.json +48 -0
- package/package.json +1 -1
- package/scripts/postinstall.js +49 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
use serde::Serialize;
|
|
2
|
+
use std::process::Command;
|
|
3
|
+
|
|
4
|
+
#[derive(Debug, Serialize)]
|
|
5
|
+
pub struct StartResult {
|
|
6
|
+
pub success: bool,
|
|
7
|
+
pub message: String,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/// Find the `a2a` CLI binary
|
|
11
|
+
fn find_a2a_binary() -> Option<String> {
|
|
12
|
+
// Check common locations
|
|
13
|
+
let candidates = [
|
|
14
|
+
"a2a", // In PATH
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
for candidate in &candidates {
|
|
18
|
+
let result = Command::new("which")
|
|
19
|
+
.arg(candidate)
|
|
20
|
+
.output();
|
|
21
|
+
|
|
22
|
+
if let Ok(output) = result {
|
|
23
|
+
if output.status.success() {
|
|
24
|
+
let path = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
25
|
+
if !path.is_empty() {
|
|
26
|
+
return Some(path);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
None
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Start the a2a server as a detached process
|
|
36
|
+
pub fn start_server() -> StartResult {
|
|
37
|
+
let binary = match find_a2a_binary() {
|
|
38
|
+
Some(b) => b,
|
|
39
|
+
None => {
|
|
40
|
+
return StartResult {
|
|
41
|
+
success: false,
|
|
42
|
+
message: "Could not find 'a2a' CLI. Is a2acalling installed? Run: npm install -g a2acalling".to_string(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
let port = crate::discovery::read_config_port().unwrap_or(3001);
|
|
48
|
+
let port_str = port.to_string();
|
|
49
|
+
|
|
50
|
+
let result = Command::new(&binary)
|
|
51
|
+
.args(["server", "--port", &port_str])
|
|
52
|
+
.stdout(std::process::Stdio::null())
|
|
53
|
+
.stderr(std::process::Stdio::null())
|
|
54
|
+
.stdin(std::process::Stdio::null())
|
|
55
|
+
.spawn();
|
|
56
|
+
|
|
57
|
+
match result {
|
|
58
|
+
Ok(_child) => StartResult {
|
|
59
|
+
success: true,
|
|
60
|
+
message: format!("Server starting on port {}...", port),
|
|
61
|
+
},
|
|
62
|
+
Err(err) => StartResult {
|
|
63
|
+
success: false,
|
|
64
|
+
message: format!("Failed to start server: {}", err),
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json",
|
|
3
|
+
"productName": "A2A Callbook",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"identifier": "com.openclaw.a2a-callbook",
|
|
6
|
+
"build": {
|
|
7
|
+
"frontendDist": "../index.html"
|
|
8
|
+
},
|
|
9
|
+
"app": {
|
|
10
|
+
"windows": [
|
|
11
|
+
{
|
|
12
|
+
"title": "A2A Callbook",
|
|
13
|
+
"width": 1024,
|
|
14
|
+
"height": 720,
|
|
15
|
+
"minWidth": 480,
|
|
16
|
+
"minHeight": 600,
|
|
17
|
+
"resizable": true
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"security": {
|
|
21
|
+
"dangerousRemoteUrlAccess": [
|
|
22
|
+
{ "url": "http://127.0.0.1:**" },
|
|
23
|
+
{ "url": "http://localhost:**" }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"bundle": {
|
|
28
|
+
"active": true,
|
|
29
|
+
"targets": ["dmg", "app"],
|
|
30
|
+
"icon": [
|
|
31
|
+
"icons/32x32.png",
|
|
32
|
+
"icons/128x128.png",
|
|
33
|
+
"icons/128x128@2x.png",
|
|
34
|
+
"icons/icon.icns"
|
|
35
|
+
],
|
|
36
|
+
"macOS": {
|
|
37
|
+
"minimumSystemVersion": "12.0",
|
|
38
|
+
"frameworks": []
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"plugins": {
|
|
42
|
+
"deep-link": {
|
|
43
|
+
"desktop": {
|
|
44
|
+
"schemes": ["a2a"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -43,7 +43,56 @@ const result = spawnSync(process.execPath, [cliPath, 'quickstart'], {
|
|
|
43
43
|
|
|
44
44
|
if (result.error) {
|
|
45
45
|
// Don't fail the install — the agent will get onboarding when it runs `a2a`.
|
|
46
|
+
installMacOSApp();
|
|
46
47
|
process.exit(0);
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
installMacOSApp();
|
|
49
51
|
process.exit(result.status || 0);
|
|
52
|
+
|
|
53
|
+
// Download and install the native macOS app from GitHub Releases
|
|
54
|
+
function installMacOSApp() {
|
|
55
|
+
const os = require('os');
|
|
56
|
+
const fs = require('fs');
|
|
57
|
+
|
|
58
|
+
if (os.platform() !== 'darwin') return;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const version = require('../package.json').version;
|
|
62
|
+
const appDir = path.join(os.homedir(), 'Applications');
|
|
63
|
+
const appPath = path.join(appDir, 'A2A Callbook.app');
|
|
64
|
+
|
|
65
|
+
// Skip if already installed at same version
|
|
66
|
+
const plistPath = path.join(appPath, 'Contents', 'Info.plist');
|
|
67
|
+
if (fs.existsSync(plistPath)) {
|
|
68
|
+
try {
|
|
69
|
+
const plist = fs.readFileSync(plistPath, 'utf8');
|
|
70
|
+
if (plist.includes(version)) {
|
|
71
|
+
return; // Same version already installed
|
|
72
|
+
}
|
|
73
|
+
} catch (_) {}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const tarUrl = `https://github.com/onthegonow/a2a_calling/releases/download/v${version}/A2A-Callbook-${version}.app.tar.gz`;
|
|
77
|
+
const tmpFile = path.join(os.tmpdir(), `a2a-callbook-${version}.tar.gz`);
|
|
78
|
+
|
|
79
|
+
// Download
|
|
80
|
+
const { execFileSync } = require('child_process');
|
|
81
|
+
execFileSync('curl', ['-sL', '-o', tmpFile, tarUrl], { timeout: 30000 });
|
|
82
|
+
|
|
83
|
+
if (!fs.existsSync(tmpFile) || fs.statSync(tmpFile).size < 1000) {
|
|
84
|
+
return; // Download failed or too small — skip silently
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Ensure ~/Applications exists
|
|
88
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
89
|
+
|
|
90
|
+
// Extract
|
|
91
|
+
execFileSync('tar', ['-xzf', tmpFile, '-C', appDir], { timeout: 15000 });
|
|
92
|
+
|
|
93
|
+
// Cleanup
|
|
94
|
+
try { fs.unlinkSync(tmpFile); } catch (_) {}
|
|
95
|
+
} catch (_) {
|
|
96
|
+
// Silently fail — native app is optional
|
|
97
|
+
}
|
|
98
|
+
}
|