a2acalling 0.6.49 → 0.6.51
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 +228 -2
- package/docs/protocol.md +42 -0
- package/native/macos/index.html +5 -10
- package/native/macos/src-tauri/Cargo.lock +5875 -0
- package/native/macos/src-tauri/Cargo.toml +3 -2
- 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/tray-connected.png +0 -0
- package/native/macos/src-tauri/icons/tray-disconnected.png +0 -0
- package/native/macos/src-tauri/src/lib.rs +2 -2
- package/native/macos/src-tauri/src/notifications.rs +147 -68
- package/native/macos/src-tauri/tauri.conf.json +2 -9
- package/package.json +1 -1
- package/scripts/install-skills.js +80 -0
- package/scripts/postinstall.js +8 -45
- package/src/dashboard/public/app.js +147 -1
- package/src/lib/claude-subagent.js +6 -5
- package/src/lib/config.js +1 -0
- package/src/lib/conversation-driver.js +12 -3
- package/src/lib/conversations.js +55 -1
- package/src/lib/dashboard-events.js +205 -0
- package/src/lib/runtime-adapter.js +8 -3
- package/src/lib/tokens.js +13 -1
- package/src/lib/turn-timeout.js +52 -0
- package/src/routes/a2a.js +26 -4
- package/src/routes/dashboard.js +114 -1
- package/src/server.js +20 -1
package/bin/cli.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* a2a call <url> <msg> Call a contact (or invite URL)
|
|
12
12
|
* a2a ping <url> Ping an invite URL
|
|
13
13
|
* a2a gui Open the local dashboard GUI in a browser
|
|
14
|
+
* a2a app <action> Manage native macOS app (status/install/uninstall)
|
|
14
15
|
* a2a setup Auto setup (gateway-aware dashboard install)
|
|
15
16
|
* a2a uninstall Stop server and remove local A2A config
|
|
16
17
|
*/
|
|
@@ -37,7 +38,9 @@ const ONBOARDING_EXEMPT = new Set([
|
|
|
37
38
|
'dashboard',
|
|
38
39
|
'server',
|
|
39
40
|
'setup',
|
|
40
|
-
'
|
|
41
|
+
'app',
|
|
42
|
+
'install',
|
|
43
|
+
'skills'
|
|
41
44
|
]);
|
|
42
45
|
|
|
43
46
|
function isOnboarded() {
|
|
@@ -167,6 +170,100 @@ function findNativeApp() {
|
|
|
167
170
|
return null;
|
|
168
171
|
}
|
|
169
172
|
|
|
173
|
+
function getNativeAppPaths() {
|
|
174
|
+
return {
|
|
175
|
+
appDir: path.join(os.homedir(), 'Applications'),
|
|
176
|
+
appPath: path.join(os.homedir(), 'Applications', 'A2A Callbook.app')
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function parseInstalledNativeAppVersion(appPath) {
|
|
181
|
+
if (!appPath) return null;
|
|
182
|
+
const plistPath = path.join(appPath, 'Contents', 'Info.plist');
|
|
183
|
+
if (!fs.existsSync(plistPath)) return null;
|
|
184
|
+
try {
|
|
185
|
+
const plist = fs.readFileSync(plistPath, 'utf8');
|
|
186
|
+
const m = plist.match(/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/);
|
|
187
|
+
return m && m[1] ? m[1].trim() : null;
|
|
188
|
+
} catch (_) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function installNativeMacApp(options = {}) {
|
|
194
|
+
if (os.platform() !== 'darwin') {
|
|
195
|
+
return { success: false, skipped: 'not_macos' };
|
|
196
|
+
}
|
|
197
|
+
const quiet = Boolean(options.quiet);
|
|
198
|
+
const force = Boolean(options.force);
|
|
199
|
+
const version = require('../package.json').version;
|
|
200
|
+
const { appDir, appPath } = getNativeAppPaths();
|
|
201
|
+
const installedVersion = parseInstalledNativeAppVersion(appPath);
|
|
202
|
+
if (!force && installedVersion === version) {
|
|
203
|
+
return { success: true, installed: false, version, appPath, reason: 'already_current' };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const tarUrl = `https://github.com/onthegonow/a2a_calling/releases/download/v${version}/A2A-Callbook-${version}.app.tar.gz`;
|
|
207
|
+
const tmpFile = path.join(os.tmpdir(), `a2a-callbook-${version}.app.tar.gz`);
|
|
208
|
+
const { execFileSync } = require('child_process');
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
212
|
+
execFileSync('curl', ['-fL', '-o', tmpFile, tarUrl], { timeout: 120000, stdio: quiet ? 'ignore' : 'inherit' });
|
|
213
|
+
if (!fs.existsSync(tmpFile) || fs.statSync(tmpFile).size < 1000) {
|
|
214
|
+
return { success: false, error: 'download_failed' };
|
|
215
|
+
}
|
|
216
|
+
if (fs.existsSync(appPath)) {
|
|
217
|
+
fs.rmSync(appPath, { recursive: true, force: true });
|
|
218
|
+
}
|
|
219
|
+
execFileSync('tar', ['-xzf', tmpFile, '-C', appDir], { timeout: 60000, stdio: quiet ? 'ignore' : 'inherit' });
|
|
220
|
+
try { fs.unlinkSync(tmpFile); } catch (_) {}
|
|
221
|
+
return { success: true, installed: true, version, appPath };
|
|
222
|
+
} catch (err) {
|
|
223
|
+
try { fs.unlinkSync(tmpFile); } catch (_) {}
|
|
224
|
+
return { success: false, error: err.message || 'install_failed' };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function uninstallNativeMacApp() {
|
|
229
|
+
if (os.platform() !== 'darwin') {
|
|
230
|
+
return { success: false, skipped: 'not_macos' };
|
|
231
|
+
}
|
|
232
|
+
const candidates = [
|
|
233
|
+
path.join(os.homedir(), 'Applications', 'A2A Callbook.app'),
|
|
234
|
+
'/Applications/A2A Callbook.app'
|
|
235
|
+
];
|
|
236
|
+
const existing = candidates.filter((candidate) => {
|
|
237
|
+
try {
|
|
238
|
+
return fs.existsSync(candidate);
|
|
239
|
+
} catch (_) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
if (existing.length === 0) {
|
|
244
|
+
return { success: true, removed: false, appPath: candidates[0] };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const removed = [];
|
|
248
|
+
const failed = [];
|
|
249
|
+
for (const appPath of existing) {
|
|
250
|
+
try {
|
|
251
|
+
fs.rmSync(appPath, { recursive: true, force: true });
|
|
252
|
+
removed.push(appPath);
|
|
253
|
+
} catch (err) {
|
|
254
|
+
failed.push({ appPath, error: err && err.message ? err.message : 'uninstall_failed' });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (failed.length > 0) {
|
|
258
|
+
return {
|
|
259
|
+
success: false,
|
|
260
|
+
error: failed.map((f) => `${f.appPath}: ${f.error}`).join('; '),
|
|
261
|
+
appPath: removed[0] || existing[0]
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return { success: true, removed: true, appPath: removed[0] || existing[0] };
|
|
265
|
+
}
|
|
266
|
+
|
|
170
267
|
async function findLocalServerPort(preferredPorts = []) {
|
|
171
268
|
const http = require('http');
|
|
172
269
|
|
|
@@ -710,6 +807,8 @@ const commands = {
|
|
|
710
807
|
|
|
711
808
|
// Get objectives from disclosure
|
|
712
809
|
const objectives = tierTopics.objectives || [];
|
|
810
|
+
const timeoutMsRaw = args.flags['timeout-ms'] || args.flags.timeout_ms;
|
|
811
|
+
const timeoutMs = timeoutMsRaw ? Number.parseInt(String(timeoutMsRaw), 10) : null;
|
|
713
812
|
|
|
714
813
|
const { token, record } = store.create({
|
|
715
814
|
name: args.flags.name || args.flags.n || 'unnamed',
|
|
@@ -720,7 +819,8 @@ const commands = {
|
|
|
720
819
|
notify: args.flags.notify || 'all',
|
|
721
820
|
maxCalls,
|
|
722
821
|
allowedTopics,
|
|
723
|
-
allowedGoals: objectives.map(o => o.objective || o)
|
|
822
|
+
allowedGoals: objectives.map(o => o.objective || o),
|
|
823
|
+
timeoutMs
|
|
724
824
|
});
|
|
725
825
|
|
|
726
826
|
const resolvedHost = await resolveInviteHostname();
|
|
@@ -759,6 +859,7 @@ const commands = {
|
|
|
759
859
|
console.log(`Disclosure: ${record.disclosure}`);
|
|
760
860
|
console.log(`Notify: ${record.notify}`);
|
|
761
861
|
console.log(`Max calls: ${record.max_calls || 'unlimited'}`);
|
|
862
|
+
if (record.timeout_ms) console.log(`Turn timeout: ${record.timeout_ms}ms`);
|
|
762
863
|
if (linkContact) console.log(`Linked to: ${linkContact}`);
|
|
763
864
|
console.log(`\nTo revoke: a2a revoke ${record.id}`);
|
|
764
865
|
console.log(`\n${'─'.repeat(50)}`);
|
|
@@ -1355,11 +1456,15 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
1355
1456
|
|
|
1356
1457
|
// Build owner context from config for summarizer
|
|
1357
1458
|
let ownerContext = {};
|
|
1459
|
+
let configTurnTimeoutMs = null;
|
|
1358
1460
|
try {
|
|
1359
1461
|
const { A2AConfig } = require('../src/lib/config');
|
|
1360
1462
|
const config = new A2AConfig();
|
|
1361
1463
|
const configAll = config.getAll();
|
|
1362
1464
|
const tierGoals = configAll.tiers?.public?.goals || [];
|
|
1465
|
+
configTurnTimeoutMs = configAll.defaults?.turnTimeoutMs
|
|
1466
|
+
|| configAll.defaults?.turn_timeout_ms
|
|
1467
|
+
|| null;
|
|
1363
1468
|
ownerContext = {
|
|
1364
1469
|
goals: tierGoals,
|
|
1365
1470
|
agentName: agentContext.name,
|
|
@@ -1378,6 +1483,7 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
1378
1483
|
disclosure,
|
|
1379
1484
|
minTurns,
|
|
1380
1485
|
maxTurns,
|
|
1486
|
+
configTurnTimeoutMs,
|
|
1381
1487
|
ownerContext,
|
|
1382
1488
|
onTurn: (info) => {
|
|
1383
1489
|
const preview = info.messagePreview.length >= 80
|
|
@@ -2149,6 +2255,74 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
2149
2255
|
require('../scripts/install-openclaw.js');
|
|
2150
2256
|
},
|
|
2151
2257
|
|
|
2258
|
+
app: (args) => {
|
|
2259
|
+
const action = String(args._[1] || 'status').trim().toLowerCase();
|
|
2260
|
+
const force = Boolean(args.flags.force || args.flags.f);
|
|
2261
|
+
const quiet = Boolean(args.flags.quiet || args.flags.q);
|
|
2262
|
+
const pkgVersion = require('../package.json').version;
|
|
2263
|
+
|
|
2264
|
+
if (action === 'status') {
|
|
2265
|
+
const installedAppPath = findNativeApp();
|
|
2266
|
+
const preferredPath = getNativeAppPaths().appPath;
|
|
2267
|
+
const version = installedAppPath ? parseInstalledNativeAppVersion(installedAppPath) : null;
|
|
2268
|
+
console.log('A2A Native App Status\n');
|
|
2269
|
+
console.log(` Platform: ${os.platform()}`);
|
|
2270
|
+
console.log(` CLI version: ${pkgVersion}`);
|
|
2271
|
+
if (os.platform() !== 'darwin') {
|
|
2272
|
+
console.log(' Native app: Not supported on this platform');
|
|
2273
|
+
return;
|
|
2274
|
+
}
|
|
2275
|
+
console.log(` Installed: ${installedAppPath ? 'yes' : 'no'}`);
|
|
2276
|
+
console.log(` App path: ${installedAppPath || preferredPath}`);
|
|
2277
|
+
console.log(` App version: ${version || '(unknown)'}`);
|
|
2278
|
+
if (!installedAppPath) {
|
|
2279
|
+
console.log('\nInstall with: a2a app install');
|
|
2280
|
+
}
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
if (action === 'install') {
|
|
2285
|
+
const result = installNativeMacApp({ force, quiet });
|
|
2286
|
+
if (result.skipped === 'not_macos') {
|
|
2287
|
+
console.error('Native app install is only available on macOS.');
|
|
2288
|
+
process.exit(1);
|
|
2289
|
+
}
|
|
2290
|
+
if (!result.success) {
|
|
2291
|
+
console.error(`Native app install failed: ${result.error || 'unknown error'}`);
|
|
2292
|
+
process.exit(1);
|
|
2293
|
+
}
|
|
2294
|
+
if (result.reason === 'already_current') {
|
|
2295
|
+
console.log(`Native app already installed at current version (${result.version}).`);
|
|
2296
|
+
console.log(`Path: ${result.appPath}`);
|
|
2297
|
+
return;
|
|
2298
|
+
}
|
|
2299
|
+
console.log(`Native app installed (v${result.version}).`);
|
|
2300
|
+
console.log(`Path: ${result.appPath}`);
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
if (action === 'uninstall') {
|
|
2305
|
+
const result = uninstallNativeMacApp();
|
|
2306
|
+
if (result.skipped === 'not_macos') {
|
|
2307
|
+
console.error('Native app uninstall is only available on macOS.');
|
|
2308
|
+
process.exit(1);
|
|
2309
|
+
}
|
|
2310
|
+
if (!result.success) {
|
|
2311
|
+
console.error(`Native app uninstall failed: ${result.error || 'unknown error'}`);
|
|
2312
|
+
process.exit(1);
|
|
2313
|
+
}
|
|
2314
|
+
if (!result.removed) {
|
|
2315
|
+
console.log('Native app is not installed.');
|
|
2316
|
+
return;
|
|
2317
|
+
}
|
|
2318
|
+
console.log(`Native app removed: ${result.appPath}`);
|
|
2319
|
+
return;
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
console.error('Usage: a2a app <status|install|uninstall> [--force] [--quiet]');
|
|
2323
|
+
process.exit(1);
|
|
2324
|
+
},
|
|
2325
|
+
|
|
2152
2326
|
uninstall: async (args) => {
|
|
2153
2327
|
const fs = require('fs');
|
|
2154
2328
|
const path = require('path');
|
|
@@ -2625,6 +2799,46 @@ a2a add "${inviteUrl}" "${ownerText || 'friend'}" && a2a call "${ownerText || 'f
|
|
|
2625
2799
|
return commands.quickstart(args);
|
|
2626
2800
|
},
|
|
2627
2801
|
|
|
2802
|
+
skills: (args) => {
|
|
2803
|
+
const { installSkills, SKILL_FILES } = require('../scripts/install-skills');
|
|
2804
|
+
const check = args.flags.check || args.flags.c;
|
|
2805
|
+
const force = args.flags.force;
|
|
2806
|
+
const targetDir = process.cwd();
|
|
2807
|
+
|
|
2808
|
+
if (check) {
|
|
2809
|
+
console.log('A2A skills for this project:\n');
|
|
2810
|
+
for (const file of SKILL_FILES) {
|
|
2811
|
+
const destPath = path.join(targetDir, file.dest);
|
|
2812
|
+
const exists = fs.existsSync(destPath);
|
|
2813
|
+
const icon = exists ? ' \u2713' : ' \u2717';
|
|
2814
|
+
console.log(`${icon} ${file.dest}${exists ? ' (installed)' : ' (not installed)'}`);
|
|
2815
|
+
}
|
|
2816
|
+
console.log(`\nRun "a2a skills" to install missing files.`);
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
const result = installSkills(targetDir, { force });
|
|
2821
|
+
|
|
2822
|
+
if (result.installed.length) {
|
|
2823
|
+
console.log(`\n Installed ${result.installed.length} A2A skill file(s):\n`);
|
|
2824
|
+
result.installed.forEach(f => console.log(` + ${f}`));
|
|
2825
|
+
}
|
|
2826
|
+
if (result.skipped.length) {
|
|
2827
|
+
console.log(`\n Skipped ${result.skipped.length} unchanged file(s)`);
|
|
2828
|
+
}
|
|
2829
|
+
if (result.errors.length) {
|
|
2830
|
+
console.error(`\n Errors:`);
|
|
2831
|
+
result.errors.forEach(e => console.error(` ! ${e.file}: ${e.error}`));
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
if (result.installed.length === 0 && result.skipped.length > 0) {
|
|
2835
|
+
console.log('\n All skills already installed. Use --force to overwrite.\n');
|
|
2836
|
+
} else if (result.installed.length > 0) {
|
|
2837
|
+
console.log('\n Skills ready. In Claude Code, type /a2a- to see available commands.');
|
|
2838
|
+
console.log(' In Codex CLI, A2A instructions are in .codex/AGENTS.md\n');
|
|
2839
|
+
}
|
|
2840
|
+
},
|
|
2841
|
+
|
|
2628
2842
|
version: () => {
|
|
2629
2843
|
const pkg = require('../package.json');
|
|
2630
2844
|
console.log(pkg.version);
|
|
@@ -2645,6 +2859,7 @@ Commands:
|
|
|
2645
2859
|
--disclosure, -d Disclosure level (public, minimal, none)
|
|
2646
2860
|
--notify Owner notification (all, summary, none)
|
|
2647
2861
|
--max-calls Maximum invocations (default: 100)
|
|
2862
|
+
--timeout-ms Per-token Claude turn timeout in milliseconds
|
|
2648
2863
|
--link, -l Auto-link to contact name
|
|
2649
2864
|
|
|
2650
2865
|
list List active tokens
|
|
@@ -2686,6 +2901,12 @@ Calling:
|
|
|
2686
2901
|
status <url> Get A2A status
|
|
2687
2902
|
gui Open the local dashboard GUI in a browser
|
|
2688
2903
|
--tab, -t Optional: contacts|calls|logs|settings|invites
|
|
2904
|
+
app Manage native macOS app
|
|
2905
|
+
status Show native app installation status (default)
|
|
2906
|
+
install Install/update native app from GitHub release
|
|
2907
|
+
--force, -f Reinstall even when current version is present
|
|
2908
|
+
--quiet, -q Suppress download/extract output
|
|
2909
|
+
uninstall Remove native app from ~/Applications
|
|
2689
2910
|
|
|
2690
2911
|
Server:
|
|
2691
2912
|
server Start the A2A server
|
|
@@ -2710,6 +2931,9 @@ Server:
|
|
|
2710
2931
|
uninstall Stop server and remove local config/DB
|
|
2711
2932
|
--keep-config Preserve config/DB (for reinstall)
|
|
2712
2933
|
--force Skip confirmation prompt
|
|
2934
|
+
skills Install Claude Code + Codex CLI skills
|
|
2935
|
+
--check, -c Show what would be installed
|
|
2936
|
+
--force Overwrite existing files
|
|
2713
2937
|
version Show installed package version
|
|
2714
2938
|
|
|
2715
2939
|
Examples:
|
|
@@ -2719,6 +2943,8 @@ Examples:
|
|
|
2719
2943
|
a2a contacts link Alice tok_abc123
|
|
2720
2944
|
a2a call Alice "Hello!"
|
|
2721
2945
|
a2a conversations show conv_abc123
|
|
2946
|
+
a2a app status
|
|
2947
|
+
a2a app install --force
|
|
2722
2948
|
a2a server --port 3001
|
|
2723
2949
|
`);
|
|
2724
2950
|
}
|
package/docs/protocol.md
CHANGED
|
@@ -388,6 +388,48 @@ module.exports = function (test, assert, helpers) {
|
|
|
388
388
|
};
|
|
389
389
|
```
|
|
390
390
|
|
|
391
|
+
## CLI Skills (Claude Code & Codex)
|
|
392
|
+
|
|
393
|
+
A2A ships with slash commands for Claude Code and agent instructions for Codex CLI.
|
|
394
|
+
|
|
395
|
+
### Installation
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
a2a skills # Install into current project
|
|
399
|
+
a2a skills --check # See what would be installed
|
|
400
|
+
a2a skills --force # Overwrite existing files
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Skills are also installed automatically on `npm install -g a2acalling`.
|
|
404
|
+
|
|
405
|
+
### Claude Code Commands
|
|
406
|
+
|
|
407
|
+
| Command | Description |
|
|
408
|
+
|---------|-------------|
|
|
409
|
+
| `/a2a-call <contact> <msg>` | Call another agent (multi-turn) |
|
|
410
|
+
| `/a2a-invite [name] [--tier]` | Create invite token |
|
|
411
|
+
| `/a2a-contacts [add\|show\|ping\|rm]` | Manage contacts |
|
|
412
|
+
| `/a2a-status` | Server and agent health dashboard |
|
|
413
|
+
| `/a2a-setup` | First-time setup and onboarding |
|
|
414
|
+
|
|
415
|
+
Files installed to: `.claude/commands/a2a-*.md`
|
|
416
|
+
|
|
417
|
+
### Codex CLI
|
|
418
|
+
|
|
419
|
+
A2A agent instructions are installed to `.codex/AGENTS.md`. Codex reads this file automatically to understand available A2A commands, permission tiers, and workflows.
|
|
420
|
+
|
|
421
|
+
### Manual Installation
|
|
422
|
+
|
|
423
|
+
If the automatic install didn't work, copy the files manually:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Claude Code commands
|
|
427
|
+
cp node_modules/a2acalling/.claude/commands/a2a-*.md .claude/commands/
|
|
428
|
+
|
|
429
|
+
# Codex instructions
|
|
430
|
+
cp node_modules/a2acalling/.codex/AGENTS.md .codex/AGENTS.md
|
|
431
|
+
```
|
|
432
|
+
|
|
391
433
|
## Future Protocol Extensions (v1+)
|
|
392
434
|
|
|
393
435
|
- **Capability advertisement**: Agents declare what they can help with
|
package/native/macos/index.html
CHANGED
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
Server not running
|
|
72
72
|
</p>
|
|
73
73
|
<p class="port-info" id="last-port">No a2a server found on common ports</p>
|
|
74
|
-
<button id="btn-start">
|
|
74
|
+
<button id="btn-start">How to start server</button>
|
|
75
75
|
<button id="btn-retry" class="secondary">Retry</button>
|
|
76
76
|
<p id="error-detail"></p>
|
|
77
77
|
</div>
|
|
@@ -120,15 +120,10 @@
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
document.getElementById('btn-start')?.addEventListener('click', async () => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
} catch (err) {
|
|
128
|
-
const detail = document.getElementById('error-detail');
|
|
129
|
-
detail.textContent = `Failed to start: ${err}`;
|
|
130
|
-
detail.style.display = 'block';
|
|
131
|
-
}
|
|
123
|
+
const detail = document.getElementById('error-detail');
|
|
124
|
+
// v1 design decision: app links/status only; no app-owned server lifecycle management yet.
|
|
125
|
+
detail.textContent = 'Run `a2a server` (or `a2a quickstart`) in Terminal, then click Retry.';
|
|
126
|
+
detail.style.display = 'block';
|
|
132
127
|
});
|
|
133
128
|
|
|
134
129
|
document.getElementById('btn-retry')?.addEventListener('click', checkServer);
|