a2acalling 0.6.45 → 0.6.46
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/bin/cli.js
CHANGED
|
@@ -29,6 +29,7 @@ const ONBOARDING_EXEMPT = new Set([
|
|
|
29
29
|
'quickstart',
|
|
30
30
|
'help',
|
|
31
31
|
'version',
|
|
32
|
+
'status',
|
|
32
33
|
'update',
|
|
33
34
|
'uninstall',
|
|
34
35
|
'onboard',
|
|
@@ -75,7 +76,7 @@ const store = new TokenStore();
|
|
|
75
76
|
// rather than falling through to the interactive quickstart flow.
|
|
76
77
|
// These are outbound operations often invoked by agents/automation.
|
|
77
78
|
const ONBOARDING_HARD_FAIL = new Set([
|
|
78
|
-
'call', 'ping'
|
|
79
|
+
'call', 'ping'
|
|
79
80
|
]);
|
|
80
81
|
|
|
81
82
|
// ── enforceOnboarding ────────────────────────────────────────────────────
|
|
@@ -489,6 +490,19 @@ function generateProxyConfig(backendPort) {
|
|
|
489
490
|
return { hasNginx, hasCaddy, nginxConfig, caddyConfig };
|
|
490
491
|
}
|
|
491
492
|
|
|
493
|
+
function extractNameFromPersonality(notes) {
|
|
494
|
+
if (!notes || typeof notes !== 'string') return null;
|
|
495
|
+
const patterns = [
|
|
496
|
+
/(?:I'm|I am|My name is|Name:|Owner:)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/,
|
|
497
|
+
/^([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)\s+(?:is|here|speaking)/
|
|
498
|
+
];
|
|
499
|
+
for (const p of patterns) {
|
|
500
|
+
const m = notes.match(p);
|
|
501
|
+
if (m && m[1]) return m[1].trim();
|
|
502
|
+
}
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
|
|
492
506
|
async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
|
|
493
507
|
const submitRaw = args.flags.submit;
|
|
494
508
|
if (!submitRaw) return false;
|
|
@@ -537,18 +551,29 @@ async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
|
|
|
537
551
|
|
|
538
552
|
const tiersData = manifest.tiers || {};
|
|
539
553
|
|
|
554
|
+
// Derive goals from disclosure objectives (used in tier config and token creation)
|
|
555
|
+
const disclosureObjectives = (tiersData.public?.objectives || [])
|
|
556
|
+
.map(o => typeof o === 'string' ? o : (o && o.objective || ''))
|
|
557
|
+
.map(s => s.trim().toLowerCase().replace(/\s+/g, '-').slice(0, 60))
|
|
558
|
+
.filter(Boolean);
|
|
559
|
+
|
|
560
|
+
const tokenGoals = disclosureObjectives.length > 0
|
|
561
|
+
? [...new Set(disclosureObjectives)].slice(0, 5)
|
|
562
|
+
: ['grow-network', 'find-collaborators', 'build-in-public'];
|
|
563
|
+
|
|
540
564
|
try {
|
|
541
565
|
config.setTier('public', {
|
|
542
566
|
topics: getTierTopics(tiersData.public),
|
|
543
|
-
|
|
567
|
+
goals: tokenGoals,
|
|
568
|
+
disclosure: 'minimal'
|
|
544
569
|
});
|
|
545
570
|
config.setTier('friends', {
|
|
546
571
|
topics: [...getTierTopics(tiersData.public), ...getTierTopics(tiersData.friends)],
|
|
547
|
-
disclosure: '
|
|
572
|
+
disclosure: 'standard'
|
|
548
573
|
});
|
|
549
574
|
config.setTier('family', {
|
|
550
575
|
topics: [...getTierTopics(tiersData.public), ...getTierTopics(tiersData.friends), ...getTierTopics(tiersData.family)],
|
|
551
|
-
disclosure: '
|
|
576
|
+
disclosure: 'full'
|
|
552
577
|
});
|
|
553
578
|
} catch (err) {
|
|
554
579
|
console.error(` Warning: could not sync tier config: ${err.message}`);
|
|
@@ -562,21 +587,34 @@ async function handleDisclosureSubmit(args, commandLabel = 'onboard') {
|
|
|
562
587
|
|
|
563
588
|
console.log('\nStep 4 of 4: Generating your first invite...\n');
|
|
564
589
|
|
|
565
|
-
|
|
590
|
+
// Extract identity from disclosure submission (parsed = raw JSON, result = validated)
|
|
591
|
+
const ownerName = parsed.owner_name
|
|
592
|
+
|| extractNameFromPersonality(result.manifest?.personality_notes)
|
|
593
|
+
|| process.env.USER
|
|
594
|
+
|| 'Agent Owner';
|
|
595
|
+
|
|
596
|
+
const agentName = args.flags.name
|
|
597
|
+
|| parsed.agent_name
|
|
598
|
+
|| config.getAgent().name
|
|
599
|
+
|| process.env.A2A_AGENT_NAME
|
|
600
|
+
|| `${ownerName}'s Agent`;
|
|
601
|
+
|
|
602
|
+
// Save identity to config
|
|
603
|
+
config.setAgent({ name: agentName, owner_name: ownerName });
|
|
604
|
+
|
|
566
605
|
const hostname = config.getAgent().hostname || process.env.A2A_HOSTNAME || 'localhost';
|
|
567
|
-
if (args.flags.name) config.setAgent({ name: agentName });
|
|
568
606
|
|
|
569
607
|
const publicTopics = getTierTopics(tiersData.public);
|
|
570
608
|
|
|
571
609
|
const { token } = store.create({
|
|
572
610
|
name: agentName,
|
|
573
|
-
owner:
|
|
611
|
+
owner: ownerName,
|
|
574
612
|
permissions: 'public',
|
|
575
613
|
disclosure: 'minimal',
|
|
576
614
|
expires: 'never',
|
|
577
615
|
maxCalls: null,
|
|
578
616
|
allowedTopics: publicTopics,
|
|
579
|
-
allowedGoals:
|
|
617
|
+
allowedGoals: tokenGoals,
|
|
580
618
|
notify: 'all'
|
|
581
619
|
});
|
|
582
620
|
|
|
@@ -1537,20 +1575,83 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
1537
1575
|
|
|
1538
1576
|
status: async (args) => {
|
|
1539
1577
|
const url = args._[1];
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1578
|
+
|
|
1579
|
+
// If a URL is provided, check that remote agent's status
|
|
1580
|
+
if (url) {
|
|
1581
|
+
const client = new A2AClient();
|
|
1582
|
+
try {
|
|
1583
|
+
const status = await client.status(url);
|
|
1584
|
+
console.log(`A2A status for ${url}:\n`);
|
|
1585
|
+
console.log(JSON.stringify(status, null, 2));
|
|
1586
|
+
} catch (err) {
|
|
1587
|
+
console.error(`❌ Failed to get status: ${err.message}`);
|
|
1588
|
+
process.exit(1);
|
|
1589
|
+
}
|
|
1590
|
+
return;
|
|
1543
1591
|
}
|
|
1544
1592
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1593
|
+
// No URL — show local server status
|
|
1594
|
+
const { A2AConfig } = require('../src/lib/config');
|
|
1595
|
+
const config = new A2AConfig();
|
|
1596
|
+
const onboarding = config.getOnboarding();
|
|
1597
|
+
const agent = config.getAgent();
|
|
1598
|
+
|
|
1599
|
+
console.log('A2A Local Status\n');
|
|
1600
|
+
|
|
1601
|
+
// Onboarding state
|
|
1602
|
+
const onboarded = onboarding.version === 2 && onboarding.step === 'complete';
|
|
1603
|
+
console.log(` Onboarding: ${onboarded ? '✅ Complete' : `⚠️ ${onboarding.step || 'not started'} (run: a2a quickstart)`}`);
|
|
1604
|
+
console.log(` Agent name: ${agent.name || '(not set)'}`);
|
|
1605
|
+
console.log(` Hostname: ${agent.hostname || '(not set)'}`);
|
|
1606
|
+
|
|
1607
|
+
// Check if server is running
|
|
1608
|
+
const preferred = [];
|
|
1609
|
+
if (onboarding.server_port) preferred.push(onboarding.server_port);
|
|
1610
|
+
const port = await findLocalServerPort(preferred);
|
|
1611
|
+
if (port) {
|
|
1612
|
+
console.log(` Server: ✅ Running on port ${port}`);
|
|
1613
|
+
|
|
1614
|
+
// Fetch dashboard status for more detail
|
|
1615
|
+
const http = require('http');
|
|
1616
|
+
try {
|
|
1617
|
+
const statusData = await new Promise((resolve, reject) => {
|
|
1618
|
+
const req = http.request({
|
|
1619
|
+
hostname: '127.0.0.1', port,
|
|
1620
|
+
path: '/api/a2a/dashboard/status',
|
|
1621
|
+
method: 'GET', timeout: 2000
|
|
1622
|
+
}, (res) => {
|
|
1623
|
+
let body = '';
|
|
1624
|
+
res.on('data', c => body += c);
|
|
1625
|
+
res.on('end', () => {
|
|
1626
|
+
try { resolve(JSON.parse(body)); } catch (e) { reject(e); }
|
|
1627
|
+
});
|
|
1628
|
+
});
|
|
1629
|
+
req.on('error', reject);
|
|
1630
|
+
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
|
1631
|
+
req.end();
|
|
1632
|
+
});
|
|
1633
|
+
|
|
1634
|
+
if (statusData.agent) {
|
|
1635
|
+
if (statusData.agent.owner_name) console.log(` Owner: ${statusData.agent.owner_name}`);
|
|
1636
|
+
}
|
|
1637
|
+
if (statusData.invite_host) {
|
|
1638
|
+
console.log(` Invite host: ${statusData.invite_host}`);
|
|
1639
|
+
}
|
|
1640
|
+
if (statusData.warnings && statusData.warnings.length) {
|
|
1641
|
+
console.log('');
|
|
1642
|
+
for (const w of statusData.warnings) {
|
|
1643
|
+
console.log(` ⚠️ ${w}`);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
} catch (_) {
|
|
1647
|
+
// Dashboard status unavailable — that's fine, we already showed port
|
|
1648
|
+
}
|
|
1649
|
+
} else {
|
|
1650
|
+
console.log(' Server: ❌ Not running');
|
|
1651
|
+
console.log(' Start with: a2a server --port 3001');
|
|
1553
1652
|
}
|
|
1653
|
+
|
|
1654
|
+
console.log(`\n Tip: a2a status <invite_url> to check a remote agent`);
|
|
1554
1655
|
},
|
|
1555
1656
|
|
|
1556
1657
|
config: (args) => {
|
|
@@ -1945,6 +2046,9 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
1945
2046
|
// User chose 'continue' on non-standard port — brief reminder
|
|
1946
2047
|
console.log(`\n ⚠ Running on port ${serverPort} (non-standard).`);
|
|
1947
2048
|
console.log(` Invite hostname: ${publicHost}`);
|
|
2049
|
+
console.log('');
|
|
2050
|
+
console.log(' ⚠️ Remote agents using your invite URL will try port 80 by default.');
|
|
2051
|
+
console.log(' Without a reverse proxy, inbound calls on port 80 will fail silently.');
|
|
1948
2052
|
console.log(`\n To set up a reverse proxy later:`);
|
|
1949
2053
|
console.log(` a2a config --hostname ${externalIp}`);
|
|
1950
2054
|
console.log(` Then configure nginx/caddy to proxy port 80 → ${serverPort}.`);
|
|
@@ -1952,6 +2056,45 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
1952
2056
|
|
|
1953
2057
|
const verifyUrl = `http://${publicHost}/api/a2a/ping`;
|
|
1954
2058
|
console.log(`\n Verify: curl -s ${verifyUrl}`);
|
|
2059
|
+
|
|
2060
|
+
// Fix 6: Actually run the connectivity check
|
|
2061
|
+
const http = require('http');
|
|
2062
|
+
const verifyOk = await new Promise(resolve => {
|
|
2063
|
+
const req = http.request({
|
|
2064
|
+
hostname: '127.0.0.1',
|
|
2065
|
+
port: serverPort,
|
|
2066
|
+
path: '/api/a2a/ping',
|
|
2067
|
+
method: 'GET',
|
|
2068
|
+
timeout: 2000
|
|
2069
|
+
}, (res) => {
|
|
2070
|
+
res.resume();
|
|
2071
|
+
resolve(res.statusCode === 200);
|
|
2072
|
+
});
|
|
2073
|
+
req.on('error', () => resolve(false));
|
|
2074
|
+
req.on('timeout', () => { req.destroy(); resolve(false); });
|
|
2075
|
+
req.end();
|
|
2076
|
+
});
|
|
2077
|
+
|
|
2078
|
+
if (verifyOk) {
|
|
2079
|
+
console.log(' ✅ Local connectivity verified');
|
|
2080
|
+
} else {
|
|
2081
|
+
console.log(' ⚠️ Local server check failed — server may still be starting');
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
// Fix 7: Surface invite-host warnings during quickstart
|
|
2085
|
+
try {
|
|
2086
|
+
const { resolveInviteHost } = require('../src/lib/invite-host');
|
|
2087
|
+
const resolved = await resolveInviteHost({
|
|
2088
|
+
hostname: publicHost,
|
|
2089
|
+
port: serverPort
|
|
2090
|
+
});
|
|
2091
|
+
if (resolved.warnings && resolved.warnings.length) {
|
|
2092
|
+
console.log('\n ━━━ Network Warnings ━━━');
|
|
2093
|
+
for (const w of resolved.warnings) {
|
|
2094
|
+
console.warn(` ⚠️ ${w}`);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
} catch (_) {}
|
|
1955
2098
|
}
|
|
1956
2099
|
|
|
1957
2100
|
// Save server config and advance onboarding state to awaiting_disclosure.
|
|
@@ -2513,6 +2656,13 @@ Examples:
|
|
|
2513
2656
|
|
|
2514
2657
|
// Main
|
|
2515
2658
|
const args = parseArgs(process.argv);
|
|
2659
|
+
|
|
2660
|
+
// Handle --version flag before command dispatch (standard CLI convention)
|
|
2661
|
+
if (args.flags.version || args.flags.v) {
|
|
2662
|
+
commands.version();
|
|
2663
|
+
process.exit(0);
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2516
2666
|
const command = args._[0] || 'help';
|
|
2517
2667
|
|
|
2518
2668
|
if (!commands[command]) {
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Bugfix Plan: A2A-22 + A2A-24
|
|
2
|
+
|
|
3
|
+
> **For Claude:** Execute these fixes on branch `fix/bugs-22-23-24` in `/root/a2acalling`
|
|
4
|
+
|
|
5
|
+
**Goal:** Fix quickstart onboarding gaps (identity, disclosure levels, goals) and surface network warnings during quickstart.
|
|
6
|
+
|
|
7
|
+
**A2A-23 is already fixed** in commit d3fe14e. This plan covers A2A-22 and A2A-24 only.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Bug A2A-22: Quickstart onboarding gaps
|
|
12
|
+
|
|
13
|
+
### Fix 1: Disclosure levels inverted on friends/family tiers
|
|
14
|
+
|
|
15
|
+
**File:** `bin/cli.js` ~line 546-553 (inside `handleDisclosureSubmit`)
|
|
16
|
+
|
|
17
|
+
**Problem:** Friends and family tiers are set to `disclosure: 'minimal'` when they should be more open than public.
|
|
18
|
+
|
|
19
|
+
**Fix:** Change disclosure levels to escalate: public→'minimal', friends→'standard', family→'full'.
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
// BEFORE (broken):
|
|
23
|
+
config.setTier('public', { topics: ..., disclosure: 'public' });
|
|
24
|
+
config.setTier('friends', { topics: ..., disclosure: 'minimal' });
|
|
25
|
+
config.setTier('family', { topics: ..., disclosure: 'minimal' });
|
|
26
|
+
|
|
27
|
+
// AFTER (fixed):
|
|
28
|
+
config.setTier('public', { topics: ..., disclosure: 'minimal' });
|
|
29
|
+
config.setTier('friends', { topics: ..., disclosure: 'standard' });
|
|
30
|
+
config.setTier('family', { topics: ..., disclosure: 'full' });
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Rationale:** Public tier should be most restrictive (minimal). Friends get more (standard). Family gets full disclosure. This matches the trust hierarchy.
|
|
34
|
+
|
|
35
|
+
### Fix 2: Extract identity from disclosure submission
|
|
36
|
+
|
|
37
|
+
**File:** `bin/cli.js` ~line 564-568 (inside `handleDisclosureSubmit`)
|
|
38
|
+
|
|
39
|
+
**Problem:** Agent name defaults to 'my-agent', owner name is set to agent name. The disclosure manifest often contains the real owner name in `personality_notes` or the submission JSON, but it's never extracted.
|
|
40
|
+
|
|
41
|
+
**Fix:** After parsing the disclosure JSON, extract identity fields:
|
|
42
|
+
1. Check if the submission JSON has `agent_name` or `owner_name` fields (the extraction prompt should request these)
|
|
43
|
+
2. Fall back to extracting from `personality_notes` (often contains "I'm [Name]" or similar)
|
|
44
|
+
3. Fall back to the OS username
|
|
45
|
+
4. Use extracted values for config and token creation
|
|
46
|
+
|
|
47
|
+
In `handleDisclosureSubmit`, after line ~527 where `result` is validated, add:
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
// Extract identity from disclosure submission
|
|
51
|
+
const ownerName = result.owner_name
|
|
52
|
+
|| result.manifest?.owner_name
|
|
53
|
+
|| extractNameFromPersonality(result.manifest?.personality_notes)
|
|
54
|
+
|| process.env.USER
|
|
55
|
+
|| 'Agent Owner';
|
|
56
|
+
|
|
57
|
+
const agentName = args.flags.name
|
|
58
|
+
|| result.agent_name
|
|
59
|
+
|| config.getAgent().name
|
|
60
|
+
|| process.env.A2A_AGENT_NAME
|
|
61
|
+
|| `${ownerName}'s Agent`;
|
|
62
|
+
|
|
63
|
+
// Save identity to config
|
|
64
|
+
config.setAgent({ name: agentName, owner_name: ownerName });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Add a helper function (before `handleDisclosureSubmit`):
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
function extractNameFromPersonality(notes) {
|
|
71
|
+
if (!notes || typeof notes !== 'string') return null;
|
|
72
|
+
// Look for patterns like "I'm Ben", "My name is Ben", "Owner: Ben"
|
|
73
|
+
const patterns = [
|
|
74
|
+
/(?:I'm|I am|My name is|Name:|Owner:)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)/,
|
|
75
|
+
/^([A-Z][a-z]+(?:\s+[A-Z][a-z]+)?)\s+(?:is|here|speaking)/
|
|
76
|
+
];
|
|
77
|
+
for (const p of patterns) {
|
|
78
|
+
const m = notes.match(p);
|
|
79
|
+
if (m && m[1]) return m[1].trim();
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Fix 3: Use extracted identity in token creation
|
|
86
|
+
|
|
87
|
+
**File:** `bin/cli.js` ~line 572-582
|
|
88
|
+
|
|
89
|
+
**Problem:** Token uses `agentName` as both name and owner, with hardcoded goals.
|
|
90
|
+
|
|
91
|
+
**Fix:** Use the extracted `ownerName` for the token owner field:
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
// BEFORE:
|
|
95
|
+
const { token } = store.create({
|
|
96
|
+
name: agentName,
|
|
97
|
+
owner: agentName, // wrong — should be owner name
|
|
98
|
+
...
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// AFTER:
|
|
102
|
+
const { token } = store.create({
|
|
103
|
+
name: agentName,
|
|
104
|
+
owner: ownerName,
|
|
105
|
+
...
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Fix 4: Sync disclosure objectives to token goals
|
|
110
|
+
|
|
111
|
+
**File:** `bin/cli.js` ~line 579
|
|
112
|
+
|
|
113
|
+
**Problem:** Token goals are hardcoded `['grow-network', 'find-collaborators', 'build-in-public']` instead of derived from disclosure.
|
|
114
|
+
|
|
115
|
+
**Fix:** Extract objectives from the disclosure manifest and use them as goals:
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
// Extract goals from disclosure objectives
|
|
119
|
+
const disclosureObjectives = (result.manifest?.objectives || [])
|
|
120
|
+
.map(o => typeof o === 'string' ? o : (o && o.objective || ''))
|
|
121
|
+
.map(s => s.trim().toLowerCase().replace(/\s+/g, '-').slice(0, 60))
|
|
122
|
+
.filter(Boolean);
|
|
123
|
+
|
|
124
|
+
const tokenGoals = disclosureObjectives.length > 0
|
|
125
|
+
? disclosureObjectives.slice(0, 5)
|
|
126
|
+
: ['grow-network', 'find-collaborators', 'build-in-public'];
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Then use `tokenGoals` in the store.create call:
|
|
130
|
+
```javascript
|
|
131
|
+
allowedGoals: tokenGoals,
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Also sync goals to tier config:
|
|
135
|
+
```javascript
|
|
136
|
+
config.setTier('public', {
|
|
137
|
+
topics: getTierTopics(tiersData.public),
|
|
138
|
+
goals: tokenGoals,
|
|
139
|
+
disclosure: 'minimal'
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Fix 5: Update extraction prompt to request identity fields
|
|
144
|
+
|
|
145
|
+
**File:** `src/lib/disclosure.js` — the `buildExtractionPrompt` function
|
|
146
|
+
|
|
147
|
+
**Problem:** The extraction prompt tells the agent what to scan but doesn't ask for `owner_name` or `agent_name` fields in the JSON output.
|
|
148
|
+
|
|
149
|
+
**Fix:** Add `owner_name` and `agent_name` to the required JSON schema in the prompt. Look for the JSON structure section and add:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
"owner_name": "The human owner's real name (extracted from USER.md, git config, etc.)",
|
|
153
|
+
"agent_name": "The agent's display name (extracted from USER.md or workspace context)",
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Bug A2A-24: Surface network warnings during quickstart
|
|
159
|
+
|
|
160
|
+
### Fix 6: Add connectivity check after server start
|
|
161
|
+
|
|
162
|
+
**File:** `bin/cli.js` — quickstart command, after server start (~line 2017-2019)
|
|
163
|
+
|
|
164
|
+
**Problem:** The verify URL is printed but never executed. No connectivity feedback.
|
|
165
|
+
|
|
166
|
+
**Fix:** After the server starts and the verify URL is printed, actually run the connectivity check:
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
// After line: console.log(`\n Verify: curl -s ${verifyUrl}`);
|
|
170
|
+
// Add actual verification:
|
|
171
|
+
const http = require('http');
|
|
172
|
+
const verifyOk = await new Promise(resolve => {
|
|
173
|
+
const req = http.request({
|
|
174
|
+
hostname: '127.0.0.1',
|
|
175
|
+
port: serverPort,
|
|
176
|
+
path: '/api/a2a/ping',
|
|
177
|
+
method: 'GET',
|
|
178
|
+
timeout: 2000
|
|
179
|
+
}, (res) => {
|
|
180
|
+
res.resume();
|
|
181
|
+
resolve(res.statusCode === 200);
|
|
182
|
+
});
|
|
183
|
+
req.on('error', () => resolve(false));
|
|
184
|
+
req.on('timeout', () => { req.destroy(); resolve(false); });
|
|
185
|
+
req.end();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (verifyOk) {
|
|
189
|
+
console.log(' ✅ Local connectivity verified');
|
|
190
|
+
} else {
|
|
191
|
+
console.log(' ⚠️ Local server check failed — server may still be starting');
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Fix 7: Surface invite-host warnings during quickstart
|
|
196
|
+
|
|
197
|
+
**File:** `bin/cli.js` — quickstart command, after server start
|
|
198
|
+
|
|
199
|
+
**Problem:** `resolveInviteHost()` returns warnings about NAT/firewall, but they're only shown during `a2a create`, not during quickstart.
|
|
200
|
+
|
|
201
|
+
**Fix:** After `publicHost` is set in quickstart, call `resolveInviteHost` and print its warnings:
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
// After publicHost is determined, resolve and show warnings
|
|
205
|
+
try {
|
|
206
|
+
const { resolveInviteHost } = require('../src/lib/invite-host');
|
|
207
|
+
const resolved = await resolveInviteHost({
|
|
208
|
+
hostname: publicHost,
|
|
209
|
+
port: serverPort
|
|
210
|
+
});
|
|
211
|
+
if (resolved.warnings && resolved.warnings.length) {
|
|
212
|
+
console.log('\n ━━━ Network Warnings ━━━');
|
|
213
|
+
for (const w of resolved.warnings) {
|
|
214
|
+
console.warn(` ⚠️ ${w}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch (_) {}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Fix 8: Add non-standard port warning with reverse proxy guidance
|
|
221
|
+
|
|
222
|
+
**File:** `bin/cli.js` — quickstart, already partially handled
|
|
223
|
+
|
|
224
|
+
**Assessment:** Looking at the code at lines 2008-2014, this is already partially implemented — when the user chooses 'continue' on a non-standard port, it prints a brief reminder about reverse proxy setup. But it could be more prominent.
|
|
225
|
+
|
|
226
|
+
**Fix:** Enhance the existing warning. After the "Running on port X (non-standard)" message, add:
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
console.log('');
|
|
230
|
+
console.log(' ⚠️ Remote agents using your invite URL will try port 80 by default.');
|
|
231
|
+
console.log(' Without a reverse proxy, inbound calls on port 80 will fail silently.');
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Commit Strategy
|
|
237
|
+
|
|
238
|
+
1. First commit: A2A-22 fixes (disclosure levels, identity extraction, goals sync)
|
|
239
|
+
2. Second commit: A2A-24 fixes (connectivity check, network warnings)
|
|
240
|
+
3. Run `npm test` after each commit to verify no regressions
|
|
241
|
+
|
|
242
|
+
## Testing
|
|
243
|
+
|
|
244
|
+
After all fixes:
|
|
245
|
+
- `npm test` — all 269+ tests must pass
|
|
246
|
+
- Manual verification of the logic changes (the reviewer should trace through the code paths)
|
package/package.json
CHANGED
package/src/lib/disclosure.js
CHANGED
|
@@ -608,6 +608,8 @@ Use ALL available context to build a reasonable disclosure profile. If truly not
|
|
|
608
608
|
|
|
609
609
|
const jsonBlock = `\`\`\`json
|
|
610
610
|
{
|
|
611
|
+
"owner_name": "The human owner's real name (extracted from USER.md, git config, etc.)",
|
|
612
|
+
"agent_name": "The agent's display name (extracted from USER.md or workspace context)",
|
|
611
613
|
"tiers": {
|
|
612
614
|
"public": {
|
|
613
615
|
"topics": [
|