@acnlabs/acn-cli 0.12.0 → 0.13.0
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/dist/index.js +325 -45
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,16 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
9
|
var __commonJS = (cb, mod) => function __require() {
|
|
5
10
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
6
11
|
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
7
28
|
|
|
8
29
|
// package.json
|
|
9
30
|
var require_package = __commonJS({
|
|
10
31
|
"package.json"(exports2, module2) {
|
|
11
32
|
module2.exports = {
|
|
12
33
|
name: "@acnlabs/acn-cli",
|
|
13
|
-
version: "0.
|
|
34
|
+
version: "0.13.0",
|
|
14
35
|
description: "Official CLI for ACN (Agent Collaboration Network) \u2014 zero-integration agent access",
|
|
15
36
|
main: "dist/index.js",
|
|
16
37
|
bin: {
|
|
@@ -48,10 +69,12 @@ var require_package = __commonJS({
|
|
|
48
69
|
url: "https://github.com/acnlabs/ACN/issues"
|
|
49
70
|
},
|
|
50
71
|
dependencies: {
|
|
51
|
-
commander: "^12.0.0"
|
|
72
|
+
commander: "^12.0.0",
|
|
73
|
+
ws: "^8.18.0"
|
|
52
74
|
},
|
|
53
75
|
devDependencies: {
|
|
54
76
|
"@types/node": "^20.0.0",
|
|
77
|
+
"@types/ws": "^8.5.10",
|
|
55
78
|
tsup: "^8.0.0",
|
|
56
79
|
typescript: "^5.0.0",
|
|
57
80
|
vitest: "^3.0.5"
|
|
@@ -64,7 +87,7 @@ var require_package = __commonJS({
|
|
|
64
87
|
});
|
|
65
88
|
|
|
66
89
|
// src/index.ts
|
|
67
|
-
var
|
|
90
|
+
var import_commander16 = require("commander");
|
|
68
91
|
|
|
69
92
|
// src/output.ts
|
|
70
93
|
var jsonMode = false;
|
|
@@ -255,33 +278,42 @@ function acnDelete(path) {
|
|
|
255
278
|
|
|
256
279
|
// src/commands/join.ts
|
|
257
280
|
function joinCommand() {
|
|
258
|
-
return new import_commander2.Command("join").description("Register this agent with ACN and save credentials locally").requiredOption("-n, --name <name>", "Agent name").requiredOption("-t, --tags <tags>", "Comma-separated capability tags (e.g. coding,review)").option("-e, --endpoint <url>", "Public A2A endpoint URL of this agent").option("-d, --description <text>", "Agent description").
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
tags,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
281
|
+
return new import_commander2.Command("join").description("Register this agent with ACN and save credentials locally").requiredOption("-n, --name <name>", "Agent name").requiredOption("-t, --tags <tags>", "Comma-separated capability tags (e.g. coding,review)").option("-e, --endpoint <url>", "Public A2A endpoint URL of this agent").option("-d, --description <text>", "Agent description").option(
|
|
282
|
+
"--relay",
|
|
283
|
+
"Receive messages in real time over an outbound WebSocket (run `acn listen`) instead of hosting a public endpoint. Registers in open/push mode with no delivery URL."
|
|
284
|
+
).action(
|
|
285
|
+
async (opts) => {
|
|
286
|
+
const tags = opts.tags.split(",").map((s) => s.trim()).filter(Boolean);
|
|
287
|
+
const body = {
|
|
288
|
+
name: opts.name,
|
|
289
|
+
description: opts.description ?? `${opts.name} \u2014 registered via acn-cli`,
|
|
290
|
+
tags,
|
|
291
|
+
...opts.endpoint ? { endpoint: opts.endpoint } : {},
|
|
292
|
+
// ADR-0012 Mode B: relay delivery needs a push mode (open) so the
|
|
293
|
+
// gateway actually pushes inbound messages down the WebSocket; the
|
|
294
|
+
// server-side validator then waives the public-URL requirement.
|
|
295
|
+
...opts.relay ? { delivery: "relay", communication_policy: { mode: "open" } } : {}
|
|
296
|
+
};
|
|
297
|
+
try {
|
|
298
|
+
const res = await acnPost("/agents/join", body);
|
|
299
|
+
saveConfig({ api_key: res.api_key, agent_id: res.agent_id });
|
|
300
|
+
const claimLine = res.claim_url ? `
|
|
270
301
|
Claim URL: ${res.claim_url}` : "";
|
|
271
|
-
|
|
302
|
+
const verifyLine = res.verification_code ? `
|
|
272
303
|
Verify : ${res.verification_code}` : "";
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
304
|
+
output(res, [
|
|
305
|
+
`Registered successfully!`,
|
|
306
|
+
` Agent ID : ${res.agent_id}`,
|
|
307
|
+
` API Key : ${res.api_key}`,
|
|
308
|
+
` Status : ${res.status}${claimLine}${verifyLine}`,
|
|
309
|
+
``,
|
|
310
|
+
`Credentials saved to ~/.acn/config.json`
|
|
311
|
+
].join("\n"));
|
|
312
|
+
} catch (err) {
|
|
313
|
+
handleError(err);
|
|
314
|
+
}
|
|
283
315
|
}
|
|
284
|
-
|
|
316
|
+
);
|
|
285
317
|
}
|
|
286
318
|
|
|
287
319
|
// src/commands/heartbeat.ts
|
|
@@ -1230,8 +1262,255 @@ ${formatPolicy(res)}`);
|
|
|
1230
1262
|
return cmd;
|
|
1231
1263
|
}
|
|
1232
1264
|
|
|
1233
|
-
// src/commands/
|
|
1265
|
+
// src/commands/listen.ts
|
|
1234
1266
|
var import_commander10 = require("commander");
|
|
1267
|
+
var import_child_process = require("child_process");
|
|
1268
|
+
var import_ws = __toESM(require("ws"));
|
|
1269
|
+
var STRIP_HEADERS = /* @__PURE__ */ new Set([
|
|
1270
|
+
"host",
|
|
1271
|
+
"content-length",
|
|
1272
|
+
"connection",
|
|
1273
|
+
"transfer-encoding"
|
|
1274
|
+
]);
|
|
1275
|
+
function toWebsocketUrl(baseUrl, agentId) {
|
|
1276
|
+
const u = new URL(baseUrl);
|
|
1277
|
+
u.protocol = u.protocol === "https:" ? "wss:" : "ws:";
|
|
1278
|
+
u.pathname = `/ws/${agentId}`;
|
|
1279
|
+
u.search = "";
|
|
1280
|
+
return u.toString();
|
|
1281
|
+
}
|
|
1282
|
+
function decodeBody(frame) {
|
|
1283
|
+
if (frame.body_encoding === "base64") {
|
|
1284
|
+
return Buffer.from(frame.body ?? "", "base64");
|
|
1285
|
+
}
|
|
1286
|
+
return Buffer.from(frame.body ?? "", "utf-8");
|
|
1287
|
+
}
|
|
1288
|
+
function errorResponse(id, status, detail) {
|
|
1289
|
+
return {
|
|
1290
|
+
type: "a2a_response",
|
|
1291
|
+
id,
|
|
1292
|
+
status,
|
|
1293
|
+
headers: { "content-type": "application/json" },
|
|
1294
|
+
body: JSON.stringify({ error: detail })
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
async function dispatchA2aRequest(frame, opts, send, deps = {}) {
|
|
1298
|
+
const bodyBuf = decodeBody(frame);
|
|
1299
|
+
try {
|
|
1300
|
+
if (opts.forward) {
|
|
1301
|
+
await forwardToHttp(frame, bodyBuf, opts.forward, deps.fetchFn ?? fetch, send);
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
if (opts.exec) {
|
|
1305
|
+
send(await runExec(frame, bodyBuf, opts.exec, deps.spawnFn ?? import_child_process.spawn));
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
send(errorResponse(frame.id, 500, "no handler configured"));
|
|
1309
|
+
} catch (err) {
|
|
1310
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1311
|
+
send(errorResponse(frame.id, 502, `handler failed: ${msg}`));
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
function buildForwardHeaders(frame) {
|
|
1315
|
+
const headers = {};
|
|
1316
|
+
for (const [k, v] of Object.entries(frame.headers ?? {})) {
|
|
1317
|
+
if (!STRIP_HEADERS.has(k.toLowerCase())) headers[k] = v;
|
|
1318
|
+
}
|
|
1319
|
+
return headers;
|
|
1320
|
+
}
|
|
1321
|
+
async function forwardToHttp(frame, bodyBuf, base, fetchFn, send) {
|
|
1322
|
+
const suffix = frame.path && frame.path !== "/" ? "/" + frame.path.replace(/^\//, "") : "";
|
|
1323
|
+
const targetUrl = base.replace(/\/$/, "") + suffix;
|
|
1324
|
+
const method = (frame.method ?? "POST").toUpperCase();
|
|
1325
|
+
const init = { method, headers: buildForwardHeaders(frame) };
|
|
1326
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
1327
|
+
init.body = bodyBuf;
|
|
1328
|
+
}
|
|
1329
|
+
const res = await fetchFn(targetUrl, init);
|
|
1330
|
+
const contentType = res.headers.get("content-type") ?? "application/json";
|
|
1331
|
+
if (contentType.includes("text/event-stream") && res.body) {
|
|
1332
|
+
const reader = res.body.getReader();
|
|
1333
|
+
let seq = 0;
|
|
1334
|
+
try {
|
|
1335
|
+
for (; ; ) {
|
|
1336
|
+
const { done, value } = await reader.read();
|
|
1337
|
+
if (done) break;
|
|
1338
|
+
if (value && value.length > 0) {
|
|
1339
|
+
send({
|
|
1340
|
+
type: "a2a_stream_chunk",
|
|
1341
|
+
id: frame.id,
|
|
1342
|
+
seq: seq++,
|
|
1343
|
+
data: Buffer.from(value).toString("base64"),
|
|
1344
|
+
data_encoding: "base64"
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
send({ type: "a2a_stream_end", id: frame.id, status: res.status });
|
|
1349
|
+
} catch (err) {
|
|
1350
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1351
|
+
send({ type: "a2a_stream_end", id: frame.id, error: msg });
|
|
1352
|
+
} finally {
|
|
1353
|
+
reader.releaseLock();
|
|
1354
|
+
}
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
const respText = await res.text();
|
|
1358
|
+
send({
|
|
1359
|
+
type: "a2a_response",
|
|
1360
|
+
id: frame.id,
|
|
1361
|
+
status: res.status,
|
|
1362
|
+
headers: { "content-type": contentType },
|
|
1363
|
+
body: respText
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
function runExec(frame, bodyBuf, command, spawnFn) {
|
|
1367
|
+
return new Promise((resolve) => {
|
|
1368
|
+
const child = spawnFn(command, { shell: true });
|
|
1369
|
+
const out = [];
|
|
1370
|
+
const errOut = [];
|
|
1371
|
+
child.stdout?.on("data", (d) => out.push(Buffer.from(d)));
|
|
1372
|
+
child.stderr?.on("data", (d) => errOut.push(Buffer.from(d)));
|
|
1373
|
+
child.on(
|
|
1374
|
+
"error",
|
|
1375
|
+
(e) => resolve(errorResponse(frame.id, 502, `exec error: ${e.message}`))
|
|
1376
|
+
);
|
|
1377
|
+
child.on("close", (code) => {
|
|
1378
|
+
const stdout = Buffer.concat(out).toString("utf-8");
|
|
1379
|
+
if (code === 0) {
|
|
1380
|
+
resolve({
|
|
1381
|
+
type: "a2a_response",
|
|
1382
|
+
id: frame.id,
|
|
1383
|
+
status: 200,
|
|
1384
|
+
headers: { "content-type": "application/json" },
|
|
1385
|
+
body: stdout
|
|
1386
|
+
});
|
|
1387
|
+
} else {
|
|
1388
|
+
const stderr = Buffer.concat(errOut).toString("utf-8");
|
|
1389
|
+
resolve(
|
|
1390
|
+
errorResponse(frame.id, 500, `exec exited ${code}: ${stderr.slice(0, 500)}`)
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
});
|
|
1394
|
+
child.stdin?.end(bodyBuf);
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
function rawToString(data) {
|
|
1398
|
+
if (typeof data === "string") return data;
|
|
1399
|
+
if (Buffer.isBuffer(data)) return data.toString("utf-8");
|
|
1400
|
+
if (Array.isArray(data)) return Buffer.concat(data).toString("utf-8");
|
|
1401
|
+
return Buffer.from(data).toString("utf-8");
|
|
1402
|
+
}
|
|
1403
|
+
var KEEPALIVE_INTERVAL_MS = 3e4;
|
|
1404
|
+
var INITIAL_BACKOFF_MS = 1e3;
|
|
1405
|
+
var MAX_BACKOFF_MS = 3e4;
|
|
1406
|
+
function runListener(cfg) {
|
|
1407
|
+
const wsUrl = toWebsocketUrl(cfg.baseUrl, cfg.agentId);
|
|
1408
|
+
let backoff = INITIAL_BACKOFF_MS;
|
|
1409
|
+
let stopped = false;
|
|
1410
|
+
const connect = () => {
|
|
1411
|
+
const ws = new import_ws.default(wsUrl, {
|
|
1412
|
+
headers: { Authorization: `Bearer ${cfg.apiKey}` }
|
|
1413
|
+
});
|
|
1414
|
+
let keepalive;
|
|
1415
|
+
ws.on("open", () => {
|
|
1416
|
+
console.error(`[acn listen] connected as ${cfg.agentId} \u2192 ${wsUrl}`);
|
|
1417
|
+
backoff = INITIAL_BACKOFF_MS;
|
|
1418
|
+
keepalive = setInterval(() => {
|
|
1419
|
+
if (ws.readyState === import_ws.default.OPEN) {
|
|
1420
|
+
ws.send(JSON.stringify({ type: "ping" }));
|
|
1421
|
+
}
|
|
1422
|
+
}, KEEPALIVE_INTERVAL_MS);
|
|
1423
|
+
});
|
|
1424
|
+
ws.on("message", (data) => {
|
|
1425
|
+
let frame;
|
|
1426
|
+
try {
|
|
1427
|
+
frame = JSON.parse(rawToString(data));
|
|
1428
|
+
} catch {
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
if (!frame || typeof frame !== "object") return;
|
|
1432
|
+
const f = frame;
|
|
1433
|
+
if (f.type === "a2a_request" && typeof f.id === "string") {
|
|
1434
|
+
const send = (out) => {
|
|
1435
|
+
if (ws.readyState === import_ws.default.OPEN) {
|
|
1436
|
+
ws.send(JSON.stringify(out));
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
void dispatchA2aRequest(f, cfg, send);
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1442
|
+
ws.on("close", (code, reason) => {
|
|
1443
|
+
if (keepalive) clearInterval(keepalive);
|
|
1444
|
+
if (stopped) return;
|
|
1445
|
+
if (code === 4401 || code === 4403 || code === 4429) {
|
|
1446
|
+
console.error(
|
|
1447
|
+
`[acn listen] fatal close (code ${code}): ${reason.toString() || "see api_key / agent_id"}`
|
|
1448
|
+
);
|
|
1449
|
+
process.exit(1);
|
|
1450
|
+
}
|
|
1451
|
+
console.error(
|
|
1452
|
+
`[acn listen] disconnected (code ${code}); reconnecting in ${backoff / 1e3}s`
|
|
1453
|
+
);
|
|
1454
|
+
setTimeout(connect, backoff);
|
|
1455
|
+
backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
1456
|
+
});
|
|
1457
|
+
ws.on("error", (err) => {
|
|
1458
|
+
console.error(`[acn listen] socket error: ${err.message}`);
|
|
1459
|
+
});
|
|
1460
|
+
};
|
|
1461
|
+
process.on("SIGINT", () => {
|
|
1462
|
+
stopped = true;
|
|
1463
|
+
console.error("\n[acn listen] stopping");
|
|
1464
|
+
process.exit(0);
|
|
1465
|
+
});
|
|
1466
|
+
connect();
|
|
1467
|
+
}
|
|
1468
|
+
function listenCommand() {
|
|
1469
|
+
const cmd = new import_commander10.Command("listen").description(
|
|
1470
|
+
"Hold an outbound connection to ACN and answer relayed A2A requests in real time (ADR-0012 Mode B). For agents with no public endpoint."
|
|
1471
|
+
).option(
|
|
1472
|
+
"--forward <url>",
|
|
1473
|
+
"Tunnel each relayed request to a local HTTP server (e.g. http://localhost:8080)"
|
|
1474
|
+
).option(
|
|
1475
|
+
"--exec <command>",
|
|
1476
|
+
"Run a shell command per request: body on stdin, stdout becomes the response"
|
|
1477
|
+
).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action((opts) => {
|
|
1478
|
+
const config = loadConfig();
|
|
1479
|
+
const apiKey = config.api_key;
|
|
1480
|
+
const agentId = opts.agentId ?? config.agent_id;
|
|
1481
|
+
if (!apiKey) {
|
|
1482
|
+
console.error(
|
|
1483
|
+
"No API key found. Run `acn join` first or `acn config set api-key <key>`."
|
|
1484
|
+
);
|
|
1485
|
+
process.exit(1);
|
|
1486
|
+
}
|
|
1487
|
+
if (!agentId) {
|
|
1488
|
+
console.error(
|
|
1489
|
+
"No agent ID found. Run `acn join` first or `acn config set agent-id <id>`."
|
|
1490
|
+
);
|
|
1491
|
+
process.exit(1);
|
|
1492
|
+
}
|
|
1493
|
+
if (!opts.forward && !opts.exec) {
|
|
1494
|
+
console.error("Provide a handler: --forward <url> or --exec <command>.");
|
|
1495
|
+
process.exit(1);
|
|
1496
|
+
}
|
|
1497
|
+
if (opts.forward && opts.exec) {
|
|
1498
|
+
console.error("Use only one handler: --forward or --exec, not both.");
|
|
1499
|
+
process.exit(1);
|
|
1500
|
+
}
|
|
1501
|
+
runListener({
|
|
1502
|
+
agentId,
|
|
1503
|
+
apiKey,
|
|
1504
|
+
baseUrl: config.base_url,
|
|
1505
|
+
forward: opts.forward,
|
|
1506
|
+
exec: opts.exec
|
|
1507
|
+
});
|
|
1508
|
+
});
|
|
1509
|
+
return cmd;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
// src/commands/session.ts
|
|
1513
|
+
var import_commander11 = require("commander");
|
|
1235
1514
|
function requireAgentId3() {
|
|
1236
1515
|
const config = loadConfig();
|
|
1237
1516
|
if (!config.api_key) {
|
|
@@ -1276,7 +1555,7 @@ function formatEntry2(s, index) {
|
|
|
1276
1555
|
return lines.join("\n");
|
|
1277
1556
|
}
|
|
1278
1557
|
function sessionCommand() {
|
|
1279
|
-
const cmd = new
|
|
1558
|
+
const cmd = new import_commander11.Command("session").description(
|
|
1280
1559
|
"Real-time session layer: bidirectional channel between two agents"
|
|
1281
1560
|
);
|
|
1282
1561
|
cmd.command("invite <target_agent_id>").description("Invite an agent to a real-time session").option("--ttl-seconds <s>", "Session TTL in seconds (60\u20131800, default 300)", parseInt).option("--metadata <json>", "Optional JSON object attached to the invitation (max 4KB)").action(
|
|
@@ -1354,7 +1633,7 @@ ${formatEntry2(res)}`);
|
|
|
1354
1633
|
}
|
|
1355
1634
|
|
|
1356
1635
|
// src/commands/subnet.ts
|
|
1357
|
-
var
|
|
1636
|
+
var import_commander12 = require("commander");
|
|
1358
1637
|
function requireAgentId4() {
|
|
1359
1638
|
const config = loadConfig();
|
|
1360
1639
|
if (!config.api_key) {
|
|
@@ -1442,7 +1721,7 @@ function formatSubnet(s, index) {
|
|
|
1442
1721
|
return lines.join("\n");
|
|
1443
1722
|
}
|
|
1444
1723
|
function subnetCommand() {
|
|
1445
|
-
const cmd = new
|
|
1724
|
+
const cmd = new import_commander12.Command("subnet").description("Manage ACN subnets");
|
|
1446
1725
|
cmd.command("list").description(
|
|
1447
1726
|
"List subnets. Without --all/--parent shows only subnets you have joined."
|
|
1448
1727
|
).option("--all", "Show all public subnets on ACN (not just your own)").option(
|
|
@@ -1659,7 +1938,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
1659
1938
|
handleError(err);
|
|
1660
1939
|
}
|
|
1661
1940
|
});
|
|
1662
|
-
const requests = new
|
|
1941
|
+
const requests = new import_commander12.Command("requests").description(
|
|
1663
1942
|
"Manage join-requests for a subnet (ADR-0004)"
|
|
1664
1943
|
);
|
|
1665
1944
|
requests.command("list <subnet_id>").description(
|
|
@@ -1801,7 +2080,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
1801
2080
|
}
|
|
1802
2081
|
);
|
|
1803
2082
|
cmd.addCommand(requests);
|
|
1804
|
-
const invitations = new
|
|
2083
|
+
const invitations = new import_commander12.Command("invitations").description(
|
|
1805
2084
|
"Manage invitations on a subnet (ADR-0004)"
|
|
1806
2085
|
);
|
|
1807
2086
|
invitations.command("send <subnet_id>").description(
|
|
@@ -1937,7 +2216,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
1937
2216
|
}
|
|
1938
2217
|
);
|
|
1939
2218
|
cmd.addCommand(invitations);
|
|
1940
|
-
const allowlist = new
|
|
2219
|
+
const allowlist = new import_commander12.Command("allowlist").description(
|
|
1941
2220
|
"Manage a subnet allowlist (ADR-0004)"
|
|
1942
2221
|
);
|
|
1943
2222
|
allowlist.command("list <subnet_id>").description("Owner-only: list allowlist entries for a subnet.").option("--limit <n>", "Page size (1-500, default 100)", "100").option("--offset <n>", "Page offset (default 0)", "0").action(
|
|
@@ -2005,7 +2284,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
2005
2284
|
}
|
|
2006
2285
|
);
|
|
2007
2286
|
cmd.addCommand(allowlist);
|
|
2008
|
-
const harness = new
|
|
2287
|
+
const harness = new import_commander12.Command("harness").description("Manage Org Harness webhook for a subnet");
|
|
2009
2288
|
harness.command("set <subnet_id>").description("Register an Org Harness webhook on a subnet you own").requiredOption("--url <url>", "Harness webhook URL (HTTPS)").option("--secret <secret>", "HMAC-SHA256 signing secret (recommended)").action(async (subnetId, opts) => {
|
|
2010
2289
|
const config = loadConfig();
|
|
2011
2290
|
if (!config.api_key) {
|
|
@@ -2048,7 +2327,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
2048
2327
|
}
|
|
2049
2328
|
|
|
2050
2329
|
// src/commands/follow.ts
|
|
2051
|
-
var
|
|
2330
|
+
var import_commander13 = require("commander");
|
|
2052
2331
|
function requireAgentId5() {
|
|
2053
2332
|
const config = loadConfig();
|
|
2054
2333
|
if (!config.api_key) {
|
|
@@ -2071,7 +2350,7 @@ function formatAgent2(a, i) {
|
|
|
2071
2350
|
].join("\n");
|
|
2072
2351
|
}
|
|
2073
2352
|
function followCommand() {
|
|
2074
|
-
const cmd = new
|
|
2353
|
+
const cmd = new import_commander13.Command("follow").description("Follow/unfollow agents and inspect follow graph");
|
|
2075
2354
|
cmd.command("add <target_id>").description("Follow another agent").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (targetId, opts) => {
|
|
2076
2355
|
const agentId = opts.agentId ?? requireAgentId5();
|
|
2077
2356
|
try {
|
|
@@ -2162,7 +2441,7 @@ function followCommand() {
|
|
|
2162
2441
|
}
|
|
2163
2442
|
|
|
2164
2443
|
// src/commands/wallet.ts
|
|
2165
|
-
var
|
|
2444
|
+
var import_commander14 = require("commander");
|
|
2166
2445
|
function requireAgentId6() {
|
|
2167
2446
|
const config = loadConfig();
|
|
2168
2447
|
if (!config.api_key) {
|
|
@@ -2205,7 +2484,7 @@ async function showWalletInfo(opts) {
|
|
|
2205
2484
|
}
|
|
2206
2485
|
}
|
|
2207
2486
|
function walletCommand() {
|
|
2208
|
-
const cmd = new
|
|
2487
|
+
const cmd = new import_commander14.Command("wallet").description("View and manage agent's wallet & payment info");
|
|
2209
2488
|
cmd.command("info", { isDefault: true }).description("Show wallet, payment methods, pricing, and ERC-8004 status").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(showWalletInfo);
|
|
2210
2489
|
cmd.command("set-capability").description("Declare which payment methods, networks, and wallets you accept").requiredOption(
|
|
2211
2490
|
"--methods <csv>",
|
|
@@ -2384,7 +2663,7 @@ function walletCommand() {
|
|
|
2384
2663
|
}
|
|
2385
2664
|
|
|
2386
2665
|
// src/commands/pay.ts
|
|
2387
|
-
var
|
|
2666
|
+
var import_commander15 = require("commander");
|
|
2388
2667
|
function requireAgentId7() {
|
|
2389
2668
|
const config = loadConfig();
|
|
2390
2669
|
if (!config.api_key) {
|
|
@@ -2398,8 +2677,8 @@ function requireAgentId7() {
|
|
|
2398
2677
|
return config.agent_id;
|
|
2399
2678
|
}
|
|
2400
2679
|
function payCommand() {
|
|
2401
|
-
const cmd = new
|
|
2402
|
-
const createCmd = new
|
|
2680
|
+
const cmd = new import_commander15.Command("pay").description("Manage payment tasks between agents");
|
|
2681
|
+
const createCmd = new import_commander15.Command("create").description("Create a payment task to another agent");
|
|
2403
2682
|
createCmd.requiredOption("--to <agent>", "Recipient agent ID").requiredOption("--amount <n>", "Payment amount (positive number)").requiredOption("--currency <c>", "Currency code, e.g. USD, USDC").requiredOption("--method <m>", "Payment method, e.g. usdc, eth, platform_credits").requiredOption("--network <n>", "Network, e.g. ethereum, base, solana").option("--description <text>", "Free-text description for the payment task").option("--metadata <json>", "Additional metadata as JSON object").action(
|
|
2404
2683
|
async (opts) => {
|
|
2405
2684
|
const fromAgent = requireAgentId7();
|
|
@@ -2445,7 +2724,7 @@ function payCommand() {
|
|
|
2445
2724
|
}
|
|
2446
2725
|
}
|
|
2447
2726
|
);
|
|
2448
|
-
const confirmCmd = new
|
|
2727
|
+
const confirmCmd = new import_commander15.Command("confirm").description(
|
|
2449
2728
|
"Confirm an external payment has been made (buyer only)"
|
|
2450
2729
|
);
|
|
2451
2730
|
confirmCmd.requiredOption("--task-id <id>", "Payment task ID to confirm").requiredOption(
|
|
@@ -2467,7 +2746,7 @@ function payCommand() {
|
|
|
2467
2746
|
handleError(err);
|
|
2468
2747
|
}
|
|
2469
2748
|
});
|
|
2470
|
-
const statusCmd = new
|
|
2749
|
+
const statusCmd = new import_commander15.Command("status").description(
|
|
2471
2750
|
"Show payment tasks for the authenticated agent"
|
|
2472
2751
|
);
|
|
2473
2752
|
statusCmd.option("--status <s>", "Filter by status (e.g. created, payment_confirmed)").option("--limit <n>", "Max results (default 50)", "50").action(async (opts) => {
|
|
@@ -2490,7 +2769,7 @@ function payCommand() {
|
|
|
2490
2769
|
|
|
2491
2770
|
// src/index.ts
|
|
2492
2771
|
var { version } = require_package();
|
|
2493
|
-
var program = new
|
|
2772
|
+
var program = new import_commander16.Command();
|
|
2494
2773
|
program.name("acn").description("ACN CLI \u2014 Agent Collaboration Network command-line interface").version(version).option("--json", "Output raw JSON (useful for agent parsing)").hook("preAction", (thisCommand) => {
|
|
2495
2774
|
const opts = thisCommand.opts();
|
|
2496
2775
|
if (opts.json) setJsonMode(true);
|
|
@@ -2504,6 +2783,7 @@ program.addCommand(tasksCommand());
|
|
|
2504
2783
|
program.addCommand(messageCommand());
|
|
2505
2784
|
program.addCommand(notifyCommand());
|
|
2506
2785
|
program.addCommand(inboxCommand());
|
|
2786
|
+
program.addCommand(listenCommand());
|
|
2507
2787
|
program.addCommand(sessionCommand());
|
|
2508
2788
|
program.addCommand(subnetCommand());
|
|
2509
2789
|
program.addCommand(followCommand());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acnlabs/acn-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Official CLI for ACN (Agent Collaboration Network) — zero-integration agent access",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -38,10 +38,12 @@
|
|
|
38
38
|
"url": "https://github.com/acnlabs/ACN/issues"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"commander": "^12.0.0"
|
|
41
|
+
"commander": "^12.0.0",
|
|
42
|
+
"ws": "^8.18.0"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
45
|
"@types/node": "^20.0.0",
|
|
46
|
+
"@types/ws": "^8.5.10",
|
|
45
47
|
"tsup": "^8.0.0",
|
|
46
48
|
"typescript": "^5.0.0",
|
|
47
49
|
"vitest": "^3.0.5"
|