a2acalling 0.6.52 → 0.6.54
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/.claude/commands/a2a-call.md +26 -0
- package/.claude/commands/a2a-contacts.md +31 -0
- package/.claude/commands/a2a-invite.md +33 -0
- package/.claude/commands/a2a-setup.md +30 -0
- package/.claude/commands/a2a-status.md +24 -0
- package/CLAUDE-INSTALL.md +154 -0
- package/README.md +1 -0
- package/bin/cli.js +83 -7
- package/docs/protocol.md +6 -5
- package/native/macos/index.html +24 -12
- package/native/macos/package-lock.json +232 -0
- package/native/macos/src-tauri/src/discovery.rs +100 -13
- package/native/macos/src-tauri/src/server.rs +4 -1
- package/package.json +1 -1
- package/scripts/install-skills.js +40 -5
- package/scripts/postinstall.js +153 -30
- package/src/dashboard/public/app.js +2 -0
- package/src/dashboard/public/index.html +1 -0
- package/src/lib/claude-subagent.js +100 -27
- package/src/lib/config.js +11 -0
- package/src/lib/conversation-driver.js +11 -2
- package/src/lib/disclosure.js +89 -13
- package/src/lib/runtime-adapter.js +42 -15
- package/src/lib/tokens.js +18 -0
- package/src/routes/a2a.js +4 -0
- package/src/routes/dashboard.js +9 -1
- package/src/server.js +42 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Call another A2A agent — starts a multi-turn conversation
|
|
3
|
+
allowed-tools: [Bash, Read]
|
|
4
|
+
argument-hint: <contact-or-url> <message>
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Call an A2A agent. This starts a multi-turn agent-to-agent conversation.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/a2a-call Alice "Hello! My owner wants to discuss the project."
|
|
13
|
+
/a2a-call a2a://host.com/fed_abc123 "Reaching out about collaboration"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Instructions
|
|
17
|
+
|
|
18
|
+
Run the following command with the user's arguments:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
a2a call $ARGUMENTS
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If the call succeeds, summarize the conversation outcome for the user.
|
|
25
|
+
If it fails with "not onboarded", tell the user to run `/a2a-setup` first.
|
|
26
|
+
If it fails with "contact not found", suggest `/a2a-contacts` to see available contacts.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: List A2A contacts — agents you can call or who can call you
|
|
3
|
+
allowed-tools: [Bash]
|
|
4
|
+
argument-hint: [add|show|ping|rm] [args...]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Manage your A2A contact list — see who you can call and who has access to you.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/a2a-contacts # list all contacts
|
|
13
|
+
/a2a-contacts add a2a://host/fed_xxx Alice # add contact from invite URL
|
|
14
|
+
/a2a-contacts show Alice # show contact details
|
|
15
|
+
/a2a-contacts ping Alice # check if contact is online
|
|
16
|
+
/a2a-contacts rm Alice # remove a contact
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Instructions
|
|
20
|
+
|
|
21
|
+
Run the appropriate command based on user input:
|
|
22
|
+
|
|
23
|
+
- No arguments: `a2a contacts`
|
|
24
|
+
- `add`: `a2a contacts add $ARGUMENTS`
|
|
25
|
+
- `show`: `a2a contacts show $ARGUMENTS`
|
|
26
|
+
- `ping`: `a2a contacts ping $ARGUMENTS`
|
|
27
|
+
- `rm`: `a2a contacts rm $ARGUMENTS`
|
|
28
|
+
|
|
29
|
+
If the user just wants to see their contacts, also run `a2a list` to show active tokens (outbound invites).
|
|
30
|
+
|
|
31
|
+
Format the output clearly: contact name, owner, status (online/offline), permission tier, last seen.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create an A2A invite token to share with another agent
|
|
3
|
+
allowed-tools: [Bash]
|
|
4
|
+
argument-hint: [name] [--tier public|friends|family] [--expires 7d]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Create an A2A federation token and display the invite URL for sharing.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/a2a-invite Alice --tier friends --expires 7d
|
|
13
|
+
/a2a-invite "Bob's Agent" --tier public
|
|
14
|
+
/a2a-invite # interactive — uses defaults
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Instructions
|
|
18
|
+
|
|
19
|
+
Parse the user's arguments and run:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
a2a create $ARGUMENTS
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If no arguments provided, run `a2a create` with no flags (interactive mode).
|
|
26
|
+
|
|
27
|
+
After success, display the invite URL prominently and explain:
|
|
28
|
+
1. The URL format: `a2a://<hostname>/<token>`
|
|
29
|
+
2. Share this URL with the other agent's owner
|
|
30
|
+
3. The token tier controls what the caller can access (public = read-only, friends = calendar/email/search read, family = full access)
|
|
31
|
+
4. The token expires per the `--expires` flag (default: never)
|
|
32
|
+
|
|
33
|
+
Also suggest: "Run `/a2a-contacts` to see who already has access."
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Set up A2A Calling — onboard, start server, configure agent
|
|
3
|
+
allowed-tools: [Bash, Read, Write]
|
|
4
|
+
argument-hint: [--force]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Set up or reset your A2A Calling installation. Runs onboarding, starts the server, and configures your agent.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/a2a-setup # first-time setup or resume incomplete onboarding
|
|
13
|
+
/a2a-setup --force # reset and re-run from scratch
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Instructions
|
|
17
|
+
|
|
18
|
+
1. Check if already onboarded: `a2a config --show`
|
|
19
|
+
2. If not onboarded (or `--force`): run `a2a quickstart $ARGUMENTS`
|
|
20
|
+
3. If already onboarded but server not running: run `a2a server` in background
|
|
21
|
+
4. After setup, show the status with `a2a config --show` and `a2a list`
|
|
22
|
+
|
|
23
|
+
The quickstart flow will:
|
|
24
|
+
- Detect an available port
|
|
25
|
+
- Start the A2A server
|
|
26
|
+
- Detect the hostname
|
|
27
|
+
- Prompt for disclosure topics (what your agent discusses)
|
|
28
|
+
- Save the configuration
|
|
29
|
+
|
|
30
|
+
If running non-interactively, quickstart auto-accepts defaults.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Check A2A server status, active conversations, and agent health
|
|
3
|
+
allowed-tools: [Bash, Read]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Check the health of your A2A installation — server running, conversations active, contacts online.
|
|
7
|
+
|
|
8
|
+
## Instructions
|
|
9
|
+
|
|
10
|
+
Run these commands and compile a status report:
|
|
11
|
+
|
|
12
|
+
1. **Config:** `a2a config --show`
|
|
13
|
+
2. **Active tokens:** `a2a list`
|
|
14
|
+
3. **Contacts:** `a2a contacts`
|
|
15
|
+
4. **Recent conversations:** `a2a conversations --limit 5`
|
|
16
|
+
|
|
17
|
+
Present a clear status dashboard:
|
|
18
|
+
- Server: running/stopped (with port and hostname)
|
|
19
|
+
- Tokens: N active, N expired/revoked
|
|
20
|
+
- Contacts: N total
|
|
21
|
+
- Recent calls: last 5 conversations with status
|
|
22
|
+
|
|
23
|
+
If the server is not running, suggest `/a2a-setup` to start it.
|
|
24
|
+
If not onboarded, suggest `/a2a-setup` for first-time setup.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# A2A Calling — Installed Package Context
|
|
2
|
+
|
|
3
|
+
This file is automatically installed by the `a2acalling` package to give Claude Code
|
|
4
|
+
immediate context after `npm install`. It describes what A2A Calling is, how to get
|
|
5
|
+
started, and the full CLI reference — so you never need to grep source code.
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
After installing `a2acalling`, the FIRST thing to do is run onboarding:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
a2a quickstart
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This is the single entry point for all setup. It will:
|
|
16
|
+
1. Detect an available port (prefers 80, falls back to 3001+)
|
|
17
|
+
2. Start the A2A server
|
|
18
|
+
3. Detect the hostname
|
|
19
|
+
4. Prompt for disclosure topics (what your agent discusses with callers)
|
|
20
|
+
5. On macOS, offer to install the native Callbook app
|
|
21
|
+
6. Save configuration to `~/.config/openclaw/a2a-config.json`
|
|
22
|
+
|
|
23
|
+
If onboarding was already completed, re-run with `--force`:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
a2a quickstart --force
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Native macOS App (A2A Callbook)
|
|
30
|
+
|
|
31
|
+
On macOS, a native desktop app is available. It provides a dashboard GUI for managing
|
|
32
|
+
calls, contacts, tokens, and logs.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
a2a app install # Download and install from GitHub releases
|
|
36
|
+
a2a app status # Check if installed, show version and path
|
|
37
|
+
a2a app uninstall # Remove from ~/Applications
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
After install, the app lives at `~/Applications/A2A Callbook.app`. You can also
|
|
41
|
+
open the dashboard in a browser:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
a2a gui # Open dashboard in browser (or native app if installed)
|
|
45
|
+
a2a gui --tab logs # Open specific tab: contacts|calls|logs|settings|invites
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Full CLI Reference
|
|
49
|
+
|
|
50
|
+
### Token Management
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
a2a create --name "AgentName" --owner "OwnerName" --expires 7d --permissions friends
|
|
54
|
+
# Options:
|
|
55
|
+
# --name, -n Token/agent name
|
|
56
|
+
# --owner, -o Owner name
|
|
57
|
+
# --expires, -e 1h, 1d, 7d, 30d, never (default: 1d)
|
|
58
|
+
# --permissions, -p public, friends, family (default: public)
|
|
59
|
+
# --disclosure, -d public, minimal, none (default: minimal)
|
|
60
|
+
# --notify all, summary, none (default: all)
|
|
61
|
+
# --max-calls Maximum invocations (default: 100)
|
|
62
|
+
# --topics Custom topics (comma-separated)
|
|
63
|
+
# --tools Custom tool allowlist (comma-separated)
|
|
64
|
+
# --link, -l Auto-link to contact name
|
|
65
|
+
|
|
66
|
+
a2a list # List active tokens
|
|
67
|
+
a2a revoke <token_id> # Revoke a token
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Contacts
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
a2a contacts # List all contacts (shows permission badges)
|
|
74
|
+
a2a contacts add <url> --name "Alice" --owner "Alice Chen"
|
|
75
|
+
a2a contacts show <name> # Show contact details + linked token
|
|
76
|
+
a2a contacts edit <name> # Edit contact metadata
|
|
77
|
+
a2a contacts link <name> <token_id> # Link a token to a contact
|
|
78
|
+
a2a contacts ping <name> # Ping contact, update status
|
|
79
|
+
a2a contacts rm <name> # Remove contact
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Calling
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
a2a call <contact|url> "<message>" # Multi-turn call (default: 8-25 turns)
|
|
86
|
+
a2a call Alice "Hello!" # Call by contact name
|
|
87
|
+
a2a call a2a://host/fed_xxx "Hi" # Call by invite URL
|
|
88
|
+
a2a call Alice "Quick q" --single # One-shot (single turn)
|
|
89
|
+
# --min-turns N Minimum turns before close (default: 8)
|
|
90
|
+
# --max-turns N Maximum turns (default: 25)
|
|
91
|
+
|
|
92
|
+
a2a ping <url> # Check if agent is reachable
|
|
93
|
+
a2a status <url> # Get remote A2A status
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Conversations
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
a2a conversations # List all conversations
|
|
100
|
+
# --contact Filter by contact
|
|
101
|
+
# --status Filter: active, concluded, timeout
|
|
102
|
+
# --limit Max results (default: 20)
|
|
103
|
+
a2a conversations show <id> # Show conversation with messages
|
|
104
|
+
a2a conversations end <id> # End and summarize conversation
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Server & Setup
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
a2a quickstart # First-time setup (port, hostname, disclosure)
|
|
111
|
+
# --port, -p Preferred port (default: 80, fallback: 3001+)
|
|
112
|
+
# --force Reset and re-run from scratch
|
|
113
|
+
# --submit '<json>' Submit disclosure JSON
|
|
114
|
+
|
|
115
|
+
a2a server --port 3001 # Start server manually
|
|
116
|
+
a2a config --show # Show current configuration
|
|
117
|
+
a2a status # Show local server status
|
|
118
|
+
a2a gui # Open dashboard GUI
|
|
119
|
+
a2a app install # Install native macOS app
|
|
120
|
+
a2a setup # Auto setup (gateway-aware)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Maintenance
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
a2a update # Update to latest version
|
|
127
|
+
a2a update --check # Check for updates without installing
|
|
128
|
+
a2a skills # Install Claude Code + Codex skill files
|
|
129
|
+
a2a uninstall --force # Stop server and remove config/DB
|
|
130
|
+
a2a version # Show installed version
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Permission Tiers
|
|
134
|
+
|
|
135
|
+
| Tier | Default Capabilities |
|
|
136
|
+
|------|---------------------|
|
|
137
|
+
| `public` | `context-read` |
|
|
138
|
+
| `friends` | `context-read`, `calendar.read`, `email.read`, `search` |
|
|
139
|
+
| `family` | `context-read`, `calendar`, `email`, `search`, `tools`, `memory` |
|
|
140
|
+
|
|
141
|
+
## Disclosure Levels
|
|
142
|
+
|
|
143
|
+
| Level | Behavior |
|
|
144
|
+
|-------|----------|
|
|
145
|
+
| `public` | Agent shares freely within tier boundaries |
|
|
146
|
+
| `minimal` | Direct answers only, no volunteered context |
|
|
147
|
+
| `none` | Confirms capability, provides no information |
|
|
148
|
+
|
|
149
|
+
## Key Paths
|
|
150
|
+
|
|
151
|
+
- Config: `~/.config/openclaw/a2a-config.json`
|
|
152
|
+
- Disclosure: `~/.config/openclaw/a2a-disclosure.json`
|
|
153
|
+
- Native app: `~/Applications/A2A Callbook.app` (macOS only)
|
|
154
|
+
- Dashboard: `http://127.0.0.1:<port>/dashboard/`
|
package/README.md
CHANGED
|
@@ -149,6 +149,7 @@ Customize tiers in `~/.config/openclaw/a2a-config.json`:
|
|
|
149
149
|
"tiers": {
|
|
150
150
|
"friends": {
|
|
151
151
|
"topics": ["chat", "web", "files", "calendar"],
|
|
152
|
+
"allowed_tools": ["Bash(readonly)", "Read", "Grep", "Glob", "WebSearch", "WebFetch"],
|
|
152
153
|
"disclosure": "minimal"
|
|
153
154
|
}
|
|
154
155
|
}
|
package/bin/cli.js
CHANGED
|
@@ -646,6 +646,22 @@ async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
|
|
|
646
646
|
return tierData.topics.map(t => String(t && t.topic || '').trim()).filter(Boolean);
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
+
// Helper to extract allowed tools per tier from the disclosure manifest.
|
|
650
|
+
function getTierTools(tierData) {
|
|
651
|
+
if (!tierData || !Array.isArray(tierData.allowed_tools)) return [];
|
|
652
|
+
const seen = new Set();
|
|
653
|
+
const out = [];
|
|
654
|
+
for (const tool of tierData.allowed_tools) {
|
|
655
|
+
const cleaned = String(tool || '').trim();
|
|
656
|
+
if (!cleaned) continue;
|
|
657
|
+
const key = cleaned.toLowerCase();
|
|
658
|
+
if (seen.has(key)) continue;
|
|
659
|
+
seen.add(key);
|
|
660
|
+
out.push(cleaned);
|
|
661
|
+
}
|
|
662
|
+
return out;
|
|
663
|
+
}
|
|
664
|
+
|
|
649
665
|
const tiersData = manifest.tiers || {};
|
|
650
666
|
|
|
651
667
|
// Derive goals from disclosure objectives (used in tier config and token creation)
|
|
@@ -659,19 +675,32 @@ async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
|
|
|
659
675
|
: ['grow-network', 'find-collaborators', 'build-in-public'];
|
|
660
676
|
|
|
661
677
|
try {
|
|
662
|
-
|
|
678
|
+
const publicTools = getTierTools(tiersData.public);
|
|
679
|
+
const friendsTools = [...publicTools, ...getTierTools(tiersData.friends)];
|
|
680
|
+
const familyTools = [...friendsTools, ...getTierTools(tiersData.family)];
|
|
681
|
+
|
|
682
|
+
const publicTierPatch = {
|
|
663
683
|
topics: getTierTopics(tiersData.public),
|
|
664
684
|
goals: tokenGoals,
|
|
665
685
|
disclosure: 'minimal'
|
|
666
|
-
}
|
|
667
|
-
|
|
686
|
+
};
|
|
687
|
+
if (publicTools.length > 0) publicTierPatch.allowed_tools = publicTools;
|
|
688
|
+
|
|
689
|
+
const friendsTierPatch = {
|
|
668
690
|
topics: [...getTierTopics(tiersData.public), ...getTierTopics(tiersData.friends)],
|
|
669
691
|
disclosure: 'standard'
|
|
670
|
-
}
|
|
671
|
-
|
|
692
|
+
};
|
|
693
|
+
if (friendsTools.length > 0) friendsTierPatch.allowed_tools = friendsTools;
|
|
694
|
+
|
|
695
|
+
const familyTierPatch = {
|
|
672
696
|
topics: [...getTierTopics(tiersData.public), ...getTierTopics(tiersData.friends), ...getTierTopics(tiersData.family)],
|
|
673
697
|
disclosure: 'full'
|
|
674
|
-
}
|
|
698
|
+
};
|
|
699
|
+
if (familyTools.length > 0) familyTierPatch.allowed_tools = familyTools;
|
|
700
|
+
|
|
701
|
+
config.setTier('public', publicTierPatch);
|
|
702
|
+
config.setTier('friends', friendsTierPatch);
|
|
703
|
+
config.setTier('family', familyTierPatch);
|
|
675
704
|
} catch (err) {
|
|
676
705
|
console.error(` Warning: could not sync tier config: ${err.message}`);
|
|
677
706
|
}
|
|
@@ -702,6 +731,7 @@ async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
|
|
|
702
731
|
const hostname = config.getAgent().hostname || process.env.A2A_HOSTNAME || 'localhost';
|
|
703
732
|
|
|
704
733
|
const publicTopics = getTierTopics(tiersData.public);
|
|
734
|
+
const publicTools = getTierTools(tiersData.public);
|
|
705
735
|
|
|
706
736
|
const { token } = store.create({
|
|
707
737
|
name: agentName,
|
|
@@ -712,6 +742,7 @@ async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
|
|
|
712
742
|
maxCalls: null,
|
|
713
743
|
allowedTopics: publicTopics,
|
|
714
744
|
allowedGoals: tokenGoals,
|
|
745
|
+
allowedTools: publicTools.length > 0 ? publicTools : null,
|
|
715
746
|
notify: 'all'
|
|
716
747
|
});
|
|
717
748
|
|
|
@@ -725,6 +756,33 @@ async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
|
|
|
725
756
|
console.log(` Disclosure: ${MANIFEST_FILE}`);
|
|
726
757
|
console.log(` Invite: ${inviteUrl}\n`);
|
|
727
758
|
|
|
759
|
+
// Native app install should be part of the onboarding tail on macOS so users
|
|
760
|
+
// don't end up launching the app before a2a setup is complete.
|
|
761
|
+
if (os.platform() === 'darwin' && !findNativeApp()) {
|
|
762
|
+
if (isInteractiveShell()) {
|
|
763
|
+
const installNow = await promptYesNo('Install the native macOS app? [Y/n] ');
|
|
764
|
+
if (installNow) {
|
|
765
|
+
const result = installNativeMacApp({ force: false, quiet: false });
|
|
766
|
+
if (result.success) {
|
|
767
|
+
if (result.reason === 'already_current') {
|
|
768
|
+
console.log(`Native app already installed at current version (${result.version}).`);
|
|
769
|
+
console.log(`Path: ${result.appPath}\n`);
|
|
770
|
+
} else {
|
|
771
|
+
console.log(`Native app installed (v${result.version}).`);
|
|
772
|
+
console.log(`Path: ${result.appPath}\n`);
|
|
773
|
+
}
|
|
774
|
+
} else {
|
|
775
|
+
console.warn(`Native app install failed: ${result.error || 'unknown error'}`);
|
|
776
|
+
console.warn('You can retry with: a2a app install\n');
|
|
777
|
+
}
|
|
778
|
+
} else {
|
|
779
|
+
console.log('You can install the native app later with: a2a app install\n');
|
|
780
|
+
}
|
|
781
|
+
} else {
|
|
782
|
+
console.log('Install the native macOS app with: a2a app install\n');
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
728
786
|
return true;
|
|
729
787
|
}
|
|
730
788
|
|
|
@@ -787,6 +845,7 @@ const commands = {
|
|
|
787
845
|
|
|
788
846
|
// Get tier from --tier or --permissions flag
|
|
789
847
|
const tier = args.flags.tier || args.flags.t || args.flags.permissions || args.flags.p || 'public';
|
|
848
|
+
const configTier = config.getTiers?.()[tier] || {};
|
|
790
849
|
|
|
791
850
|
// Get owner from flag or config
|
|
792
851
|
const configAgent = config.getAgent() || {};
|
|
@@ -807,6 +866,9 @@ const commands = {
|
|
|
807
866
|
|
|
808
867
|
// Get objectives from disclosure
|
|
809
868
|
const objectives = tierTopics.objectives || [];
|
|
869
|
+
const allowedTools = args.flags.tools
|
|
870
|
+
? String(args.flags.tools).split(',').map(t => t.trim()).filter(Boolean)
|
|
871
|
+
: (Array.isArray(configTier.allowed_tools) ? configTier.allowed_tools : null);
|
|
810
872
|
const timeoutMsRaw = args.flags['timeout-ms'] || args.flags.timeout_ms;
|
|
811
873
|
const timeoutMs = timeoutMsRaw ? Number.parseInt(String(timeoutMsRaw), 10) : null;
|
|
812
874
|
|
|
@@ -820,6 +882,7 @@ const commands = {
|
|
|
820
882
|
maxCalls,
|
|
821
883
|
allowedTopics,
|
|
822
884
|
allowedGoals: objectives.map(o => o.objective || o),
|
|
885
|
+
allowedTools,
|
|
823
886
|
timeoutMs
|
|
824
887
|
});
|
|
825
888
|
|
|
@@ -856,6 +919,9 @@ const commands = {
|
|
|
856
919
|
console.log(`Expires: ${record.expires_at || 'never'}`);
|
|
857
920
|
console.log(`Tier: ${record.tier}`);
|
|
858
921
|
console.log(`Topics: ${record.allowed_topics.join(', ')}`);
|
|
922
|
+
if (Array.isArray(record.allowed_tools) && record.allowed_tools.length > 0) {
|
|
923
|
+
console.log(`Tools: ${record.allowed_tools.join(', ')}`);
|
|
924
|
+
}
|
|
859
925
|
console.log(`Disclosure: ${record.disclosure}`);
|
|
860
926
|
console.log(`Notify: ${record.notify}`);
|
|
861
927
|
console.log(`Max calls: ${record.max_calls || 'unlimited'}`);
|
|
@@ -2117,6 +2183,9 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
2117
2183
|
});
|
|
2118
2184
|
} else {
|
|
2119
2185
|
console.log(' Using existing server.');
|
|
2186
|
+
// Persist detected server port even when reusing an already-running process.
|
|
2187
|
+
// Native app discovery depends on onboarding.server_port as a primary hint.
|
|
2188
|
+
config.setOnboarding({ server_port: serverPort });
|
|
2120
2189
|
}
|
|
2121
2190
|
console.log(' ✅ A2A server is running');
|
|
2122
2191
|
|
|
@@ -2282,6 +2351,11 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
2282
2351
|
}
|
|
2283
2352
|
|
|
2284
2353
|
if (action === 'install') {
|
|
2354
|
+
if (os.platform() === 'darwin' && !force && !isOnboarded()) {
|
|
2355
|
+
console.error('Onboarding not complete. Run `a2a quickstart` first, then install the app.');
|
|
2356
|
+
console.error('Use `a2a app install --force` to bypass this check.');
|
|
2357
|
+
process.exit(1);
|
|
2358
|
+
}
|
|
2285
2359
|
const result = installNativeMacApp({ force, quiet });
|
|
2286
2360
|
if (result.skipped === 'not_macos') {
|
|
2287
2361
|
console.error('Native app install is only available on macOS.');
|
|
@@ -2856,6 +2930,7 @@ Commands:
|
|
|
2856
2930
|
--expires, -e Expiration (1h, 1d, 7d, 30d, never)
|
|
2857
2931
|
--permissions, -p Tier (public, friends, family)
|
|
2858
2932
|
--topics Custom topics (comma-separated, overrides tier defaults)
|
|
2933
|
+
--tools Custom tool allowlist (comma-separated, overrides tier defaults)
|
|
2859
2934
|
--disclosure, -d Disclosure level (public, minimal, none)
|
|
2860
2935
|
--notify Owner notification (all, summary, none)
|
|
2861
2936
|
--max-calls Maximum invocations (default: 100)
|
|
@@ -2904,7 +2979,7 @@ Calling:
|
|
|
2904
2979
|
app Manage native macOS app
|
|
2905
2980
|
status Show native app installation status (default)
|
|
2906
2981
|
install Install/update native app from GitHub release
|
|
2907
|
-
--force, -f Reinstall
|
|
2982
|
+
--force, -f Reinstall/bypass onboarding guard
|
|
2908
2983
|
--quiet, -q Suppress download/extract output
|
|
2909
2984
|
uninstall Remove native app from ~/Applications
|
|
2910
2985
|
|
|
@@ -2939,6 +3014,7 @@ Server:
|
|
|
2939
3014
|
Examples:
|
|
2940
3015
|
a2a create --name "bappybot" --owner "Benjamin Pollack" --expires 7d
|
|
2941
3016
|
a2a create --name "custom" --topics "chat,calendar.read,email.read"
|
|
3017
|
+
a2a create --name "research" --tools "Read,Grep,Glob,WebSearch,WebFetch"
|
|
2942
3018
|
a2a contacts add a2a://host/fed_xxx --name "Alice" --owner "Alice Chen"
|
|
2943
3019
|
a2a contacts link Alice tok_abc123
|
|
2944
3020
|
a2a call Alice "Hello!"
|
package/docs/protocol.md
CHANGED
|
@@ -155,11 +155,11 @@ Example filters for `/logs`: `trace_id`, `conversation_id`, `token_id`, `error_c
|
|
|
155
155
|
|
|
156
156
|
## Permission Tiers
|
|
157
157
|
|
|
158
|
-
| Tier | Default capabilities |
|
|
159
|
-
|
|
160
|
-
| `public` | `context-read` |
|
|
161
|
-
| `friends` | `context-read`, `calendar.read`, `email.read`, `search` |
|
|
162
|
-
| `family` | `context-read`, `calendar`, `email`, `search`, `tools`, `memory` |
|
|
158
|
+
| Tier | Default capabilities | Default `allowed_tools` |
|
|
159
|
+
|------|----------------------|--------------------------|
|
|
160
|
+
| `public` | `context-read` | `Read`, `Grep`, `Glob` |
|
|
161
|
+
| `friends` | `context-read`, `calendar.read`, `email.read`, `search` | `Bash(readonly)`, `Read`, `Grep`, `Glob`, `WebSearch`, `WebFetch` |
|
|
162
|
+
| `family` | `context-read`, `calendar`, `email`, `search`, `tools`, `memory` | `Bash`, `Read`, `Grep`, `Glob`, `WebSearch`, `WebFetch` |
|
|
163
163
|
|
|
164
164
|
## Disclosure Levels
|
|
165
165
|
|
|
@@ -184,6 +184,7 @@ Stored in `~/.config/openclaw/a2a.json`:
|
|
|
184
184
|
"capabilities": ["context-read"],
|
|
185
185
|
"allowed_topics": ["chat"],
|
|
186
186
|
"allowed_goals": [],
|
|
187
|
+
"allowed_tools": ["Read", "Grep", "Glob"],
|
|
187
188
|
"tier_settings": {},
|
|
188
189
|
"disclosure": "minimal",
|
|
189
190
|
"notify": "all",
|
package/native/macos/index.html
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
<span class="status-indicator searching"></span>
|
|
63
63
|
Looking for a2a server...
|
|
64
64
|
</p>
|
|
65
|
-
<p class="port-info" id="port-info">Scanning ports:
|
|
65
|
+
<p class="port-info" id="port-info">Scanning ports: 80, 3001, 8080, 8443, 9001</p>
|
|
66
66
|
</div>
|
|
67
67
|
|
|
68
68
|
<div id="status-not-found" style="display:none;">
|
|
@@ -86,10 +86,22 @@
|
|
|
86
86
|
</div>
|
|
87
87
|
|
|
88
88
|
<script>
|
|
89
|
-
const
|
|
89
|
+
const tauriCore = window.__TAURI__ && window.__TAURI__.core;
|
|
90
|
+
const tauriEvents = window.__TAURI__ && window.__TAURI__.event;
|
|
91
|
+
const legacyInvoke = window.__TAURI_INTERNALS__ && window.__TAURI_INTERNALS__.invoke;
|
|
92
|
+
const invoke = (tauriCore && tauriCore.invoke)
|
|
93
|
+
? tauriCore.invoke
|
|
94
|
+
: (legacyInvoke ? ((cmd, args) => legacyInvoke(cmd, args)) : null);
|
|
90
95
|
|
|
91
96
|
async function checkServer() {
|
|
92
97
|
show('status-searching');
|
|
98
|
+
if (!invoke) {
|
|
99
|
+
show('status-not-found');
|
|
100
|
+
const detail = document.getElementById('error-detail');
|
|
101
|
+
detail.textContent = 'Tauri bridge unavailable. Reinstall with `a2a app install --force`.';
|
|
102
|
+
detail.style.display = 'block';
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
93
105
|
try {
|
|
94
106
|
const result = await invoke('discover_server');
|
|
95
107
|
if (result.port) {
|
|
@@ -132,16 +144,16 @@
|
|
|
132
144
|
checkServer();
|
|
133
145
|
|
|
134
146
|
// Listen for server disconnect/reconnect from Tauri backend
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
}
|
|
147
|
+
if (tauriEvents && tauriEvents.listen) {
|
|
148
|
+
tauriEvents.listen('server-status', (event) => {
|
|
149
|
+
const { connected } = event.payload;
|
|
150
|
+
if (!connected) {
|
|
151
|
+
showReconnectionOverlay();
|
|
152
|
+
} else {
|
|
153
|
+
hideReconnectionOverlay();
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
145
157
|
|
|
146
158
|
function showReconnectionOverlay() {
|
|
147
159
|
if (document.getElementById('reconnect-overlay')) return;
|