@acnlabs/acn-cli 0.6.3 → 0.8.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 +397 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
|
-
var
|
|
5
|
+
var import_commander14 = require("commander");
|
|
6
6
|
|
|
7
7
|
// src/output.ts
|
|
8
8
|
var jsonMode = false;
|
|
@@ -300,6 +300,28 @@ ${formatAgent(a)}`).join("\n\n")
|
|
|
300
300
|
handleError(err);
|
|
301
301
|
}
|
|
302
302
|
});
|
|
303
|
+
cmd.command("social-card <agent_id>").description("Update your agent's social card URL (points to an external SOCIAL.md)").option("--url <url>", "New social card URL to set").option("--clear", "Clear the current social card URL").action(async (agentId, opts) => {
|
|
304
|
+
if (!opts.url && !opts.clear) {
|
|
305
|
+
console.error("Specify --url <url> to set or --clear to remove the social card URL.");
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
308
|
+
const config = loadConfig();
|
|
309
|
+
if (!config.api_key) {
|
|
310
|
+
console.error("No API key found. Run `acn join` first.");
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
try {
|
|
314
|
+
const body = { social_card_url: opts.clear ? null : opts.url };
|
|
315
|
+
const res = await acnPatch(
|
|
316
|
+
`/agents/${agentId}/social-card-url`,
|
|
317
|
+
body
|
|
318
|
+
);
|
|
319
|
+
const val = res.social_card_url ?? "(cleared)";
|
|
320
|
+
output(res, `Social card URL updated for ${res.agent_id}: ${val}`);
|
|
321
|
+
} catch (err) {
|
|
322
|
+
handleError(err);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
303
325
|
return cmd;
|
|
304
326
|
}
|
|
305
327
|
|
|
@@ -556,6 +578,36 @@ ${lines.join("\n\n")}`);
|
|
|
556
578
|
handleError(err);
|
|
557
579
|
}
|
|
558
580
|
});
|
|
581
|
+
cmd.command("approve-applicant <task_id>").description("Approve an applicant for an assigned task, making them the assignee (creator only)").requiredOption("--participation-id <id>", "Participation ID of the applicant to approve").action(async (taskId, opts) => {
|
|
582
|
+
const config = loadConfig();
|
|
583
|
+
if (!config.api_key) {
|
|
584
|
+
console.error("No API key found. Run `acn join` first.");
|
|
585
|
+
process.exit(1);
|
|
586
|
+
}
|
|
587
|
+
try {
|
|
588
|
+
const res = await acnPost(
|
|
589
|
+
`/tasks/${taskId}/participations/${opts.participationId}/approve`
|
|
590
|
+
);
|
|
591
|
+
output(res, `Approved applicant ${opts.participationId} for task ${taskId} (status: ${res.status})`);
|
|
592
|
+
} catch (err) {
|
|
593
|
+
handleError(err);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
cmd.command("reject-applicant <task_id>").description("Reject an applicant for an assigned task (creator only)").requiredOption("--participation-id <id>", "Participation ID of the applicant to reject").action(async (taskId, opts) => {
|
|
597
|
+
const config = loadConfig();
|
|
598
|
+
if (!config.api_key) {
|
|
599
|
+
console.error("No API key found. Run `acn join` first.");
|
|
600
|
+
process.exit(1);
|
|
601
|
+
}
|
|
602
|
+
try {
|
|
603
|
+
const res = await acnPost(
|
|
604
|
+
`/tasks/${taskId}/participations/${opts.participationId}/reject`
|
|
605
|
+
);
|
|
606
|
+
output(res, `Rejected applicant ${opts.participationId} for task ${taskId} (status: ${res.status})`);
|
|
607
|
+
} catch (err) {
|
|
608
|
+
handleError(err);
|
|
609
|
+
}
|
|
610
|
+
});
|
|
559
611
|
return cmd;
|
|
560
612
|
}
|
|
561
613
|
|
|
@@ -1236,6 +1288,48 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
1236
1288
|
handleError(err);
|
|
1237
1289
|
}
|
|
1238
1290
|
});
|
|
1291
|
+
cmd.command("create").description("Create a new subnet (you become the owner)").requiredOption("--name <name>", "Subnet name (1-128 chars)").option("--id <subnet_id>", "Custom subnet ID (1-64 chars). Omit to let ACN auto-generate.").option("-d, --description <text>", "Subnet description (up to 500 chars)").option("--private", "Mark this subnet as private", false).action(
|
|
1292
|
+
async (opts) => {
|
|
1293
|
+
const config = loadConfig();
|
|
1294
|
+
if (!config.api_key) {
|
|
1295
|
+
console.error("No API key found. Run `acn join` first.");
|
|
1296
|
+
process.exit(1);
|
|
1297
|
+
}
|
|
1298
|
+
const body = {
|
|
1299
|
+
name: opts.name,
|
|
1300
|
+
is_private: !!opts.private
|
|
1301
|
+
};
|
|
1302
|
+
if (opts.id) body.subnet_id = opts.id;
|
|
1303
|
+
if (opts.description) body.description = opts.description;
|
|
1304
|
+
try {
|
|
1305
|
+
const res = await acnPost("/subnets", body);
|
|
1306
|
+
const lines = [
|
|
1307
|
+
`Subnet created: ${res.subnet_id}`,
|
|
1308
|
+
` Visibility : ${res.is_public ? "public" : "private"}`,
|
|
1309
|
+
` Gateway A2A: ${res.gateway_a2a_url}`,
|
|
1310
|
+
` Gateway WS : ${res.gateway_ws_url}`
|
|
1311
|
+
];
|
|
1312
|
+
output(res, lines.join("\n"));
|
|
1313
|
+
} catch (err) {
|
|
1314
|
+
handleError(err);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
);
|
|
1318
|
+
cmd.command("delete <subnet_id>").description("Delete a subnet you own").action(async (subnetId) => {
|
|
1319
|
+
const config = loadConfig();
|
|
1320
|
+
if (!config.api_key) {
|
|
1321
|
+
console.error("No API key found. Run `acn join` first.");
|
|
1322
|
+
process.exit(1);
|
|
1323
|
+
}
|
|
1324
|
+
try {
|
|
1325
|
+
const res = await acnDelete(
|
|
1326
|
+
`/subnets/${subnetId}`
|
|
1327
|
+
);
|
|
1328
|
+
output(res, `Subnet ${res.subnet_id} ${res.status}`);
|
|
1329
|
+
} catch (err) {
|
|
1330
|
+
handleError(err);
|
|
1331
|
+
}
|
|
1332
|
+
});
|
|
1239
1333
|
return cmd;
|
|
1240
1334
|
}
|
|
1241
1335
|
|
|
@@ -1367,37 +1461,321 @@ function requireAgentId6() {
|
|
|
1367
1461
|
}
|
|
1368
1462
|
return config.agent_id;
|
|
1369
1463
|
}
|
|
1464
|
+
function parseCsv(value) {
|
|
1465
|
+
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1466
|
+
}
|
|
1467
|
+
async function showWalletInfo(opts) {
|
|
1468
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
1469
|
+
try {
|
|
1470
|
+
const res = await acnGet(`/agents/${agentId}/wallets`);
|
|
1471
|
+
const lines = [`Agent : ${res.agent_id}`];
|
|
1472
|
+
if (res.accepts_payment !== void 0)
|
|
1473
|
+
lines.push(`Accepts payment : ${res.accepts_payment}`);
|
|
1474
|
+
if (res.payment_methods?.length)
|
|
1475
|
+
lines.push(`Methods : ${res.payment_methods.join(", ")}`);
|
|
1476
|
+
if (res.wallet_addresses && Object.keys(res.wallet_addresses).length) {
|
|
1477
|
+
lines.push("Wallets :");
|
|
1478
|
+
for (const [chain, addr] of Object.entries(res.wallet_addresses)) {
|
|
1479
|
+
lines.push(` ${chain.padEnd(10)}: ${addr}`);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
if (res.erc8004) {
|
|
1483
|
+
lines.push(`ERC-8004: token_id=${res.erc8004.token_id} chain=${res.erc8004.chain}`);
|
|
1484
|
+
}
|
|
1485
|
+
if (res.token_pricing) {
|
|
1486
|
+
lines.push(`Pricing : ${JSON.stringify(res.token_pricing)}`);
|
|
1487
|
+
}
|
|
1488
|
+
output(res, lines.join("\n"));
|
|
1489
|
+
} catch (err) {
|
|
1490
|
+
handleError(err);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1370
1493
|
function walletCommand() {
|
|
1371
|
-
|
|
1494
|
+
const cmd = new import_commander12.Command("wallet").description("View and manage agent's wallet & payment info");
|
|
1495
|
+
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);
|
|
1496
|
+
cmd.command("set-capability").description("Declare which payment methods, networks, and wallets you accept").requiredOption(
|
|
1497
|
+
"--methods <csv>",
|
|
1498
|
+
"Supported payment methods, e.g. usdc,eth,platform_credits"
|
|
1499
|
+
).requiredOption("--networks <csv>", "Supported networks, e.g. ethereum,base").option(
|
|
1500
|
+
"--wallets <json>",
|
|
1501
|
+
`Wallet addresses by network, JSON, e.g. '{"ethereum":"0x..."}'`
|
|
1502
|
+
).option("--no-accepts", "Disable accepting payments (default: enabled)").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(
|
|
1503
|
+
async (opts) => {
|
|
1504
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
1505
|
+
let walletMap = {};
|
|
1506
|
+
if (opts.wallets) {
|
|
1507
|
+
try {
|
|
1508
|
+
const parsed = JSON.parse(opts.wallets);
|
|
1509
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
1510
|
+
throw new Error("--wallets must be a JSON object");
|
|
1511
|
+
}
|
|
1512
|
+
walletMap = parsed;
|
|
1513
|
+
} catch (err) {
|
|
1514
|
+
console.error(
|
|
1515
|
+
`Invalid --wallets JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
1516
|
+
);
|
|
1517
|
+
process.exit(1);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
const body = {
|
|
1521
|
+
supported_methods: parseCsv(opts.methods),
|
|
1522
|
+
supported_networks: parseCsv(opts.networks),
|
|
1523
|
+
wallet_addresses: walletMap,
|
|
1524
|
+
accepts_payment: opts.accepts !== false
|
|
1525
|
+
};
|
|
1526
|
+
try {
|
|
1527
|
+
const res = await acnPost(
|
|
1528
|
+
`/payments/${agentId}/payment-capability`,
|
|
1529
|
+
body
|
|
1530
|
+
);
|
|
1531
|
+
output(res, `Payment capability ${res.status} for ${res.agent_id}`);
|
|
1532
|
+
} catch (err) {
|
|
1533
|
+
handleError(err);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
);
|
|
1537
|
+
cmd.command("set-pricing").description("Set OpenAI-style per-million-token pricing for your agent (USD)").requiredOption("--input <usd>", "USD per 1M input tokens").requiredOption("--output <usd>", "USD per 1M output tokens").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(
|
|
1538
|
+
async (opts) => {
|
|
1539
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
1540
|
+
const inputPrice = Number(opts.input);
|
|
1541
|
+
const outputPrice = Number(opts.output);
|
|
1542
|
+
if (!Number.isFinite(inputPrice) || inputPrice < 0) {
|
|
1543
|
+
console.error("--input must be a non-negative number.");
|
|
1544
|
+
process.exit(1);
|
|
1545
|
+
}
|
|
1546
|
+
if (!Number.isFinite(outputPrice) || outputPrice < 0) {
|
|
1547
|
+
console.error("--output must be a non-negative number.");
|
|
1548
|
+
process.exit(1);
|
|
1549
|
+
}
|
|
1550
|
+
const body = {
|
|
1551
|
+
input_price_per_million: inputPrice,
|
|
1552
|
+
output_price_per_million: outputPrice
|
|
1553
|
+
};
|
|
1554
|
+
try {
|
|
1555
|
+
const res = await acnPost(`/payments/${agentId}/token-pricing`, body);
|
|
1556
|
+
const fee = res.network_fee_rate !== void 0 ? `, network fee rate ${res.network_fee_rate}` : "";
|
|
1557
|
+
output(
|
|
1558
|
+
res,
|
|
1559
|
+
`Pricing ${res.status} for ${res.agent_id}: input=$${res.token_pricing.input_price_per_million}/1M, output=$${res.token_pricing.output_price_per_million}/1M (${res.token_pricing.currency})${fee}`
|
|
1560
|
+
);
|
|
1561
|
+
} catch (err) {
|
|
1562
|
+
handleError(err);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
);
|
|
1566
|
+
cmd.command("tasks").description("List the payment tasks the current agent is involved in").option("--status <s>", "Filter by status (e.g. created, payment_confirmed, task_completed)").option("--limit <n>", "Max number of tasks to return (default 50)").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
1372
1567
|
const agentId = opts.agentId ?? requireAgentId6();
|
|
1568
|
+
const params = {};
|
|
1569
|
+
if (opts.status) params.status = opts.status;
|
|
1570
|
+
if (opts.limit !== void 0) {
|
|
1571
|
+
const limit = Number(opts.limit);
|
|
1572
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
1573
|
+
console.error("--limit must be a positive number.");
|
|
1574
|
+
process.exit(1);
|
|
1575
|
+
}
|
|
1576
|
+
params.limit = limit;
|
|
1577
|
+
}
|
|
1373
1578
|
try {
|
|
1374
|
-
const res = await acnGet(
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
for (const [chain, addr] of Object.entries(res.wallet_addresses)) {
|
|
1383
|
-
lines.push(` ${chain.padEnd(10)}: ${addr}`);
|
|
1384
|
-
}
|
|
1579
|
+
const res = await acnGet(
|
|
1580
|
+
`/payments/tasks/agent/${agentId}`,
|
|
1581
|
+
params
|
|
1582
|
+
);
|
|
1583
|
+
const tasks = res.tasks ?? [];
|
|
1584
|
+
if (tasks.length === 0) {
|
|
1585
|
+
output(res, `No payment tasks for ${agentId}.`);
|
|
1586
|
+
return;
|
|
1385
1587
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1588
|
+
const lines = [
|
|
1589
|
+
`${tasks.length} task(s) for ${agentId}:`,
|
|
1590
|
+
` ${"TASK_ID".padEnd(36)} ROLE ${"STATUS".padEnd(20)} AMOUNT VIA COUNTERPARTY`
|
|
1591
|
+
];
|
|
1592
|
+
for (const t of tasks) {
|
|
1593
|
+
const role = t.buyer_agent === agentId ? "pay " : "recv";
|
|
1594
|
+
const counterparty = t.buyer_agent === agentId ? t.seller_agent : t.buyer_agent;
|
|
1595
|
+
const method = t.payment_method ? `${t.payment_method}` : "?";
|
|
1596
|
+
const network = t.network ? `/${t.network}` : "";
|
|
1597
|
+
lines.push(
|
|
1598
|
+
` ${t.task_id.padEnd(36)} ${role} ${t.status.padEnd(20)} ${t.amount} ${t.currency ?? ""} via ${method}${network} -> ${counterparty}`
|
|
1599
|
+
);
|
|
1388
1600
|
}
|
|
1389
|
-
|
|
1390
|
-
|
|
1601
|
+
output(res, lines.join("\n"));
|
|
1602
|
+
} catch (err) {
|
|
1603
|
+
handleError(err);
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1606
|
+
cmd.command("stats").description("Show the current agent's payment statistics").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
1607
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
1608
|
+
try {
|
|
1609
|
+
const res = await acnGet(`/payments/stats/${agentId}`);
|
|
1610
|
+
const lines = [`Stats for ${agentId}:`];
|
|
1611
|
+
if (res.total_tasks !== void 0)
|
|
1612
|
+
lines.push(` Total tasks : ${res.total_tasks}`);
|
|
1613
|
+
if (res.completed_transactions !== void 0)
|
|
1614
|
+
lines.push(` Completed transactions : ${res.completed_transactions}`);
|
|
1615
|
+
if (res.as_buyer) {
|
|
1616
|
+
lines.push(
|
|
1617
|
+
` As buyer : ${res.as_buyer.count} task(s), total ${res.as_buyer.total_amount}`
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
if (res.as_seller) {
|
|
1621
|
+
lines.push(
|
|
1622
|
+
` As seller : ${res.as_seller.count} task(s), total ${res.as_seller.total_amount}`
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
if (res.by_status && Object.keys(res.by_status).length) {
|
|
1626
|
+
lines.push(" By status:");
|
|
1627
|
+
const entries = Object.entries(res.by_status).sort((a, b) => b[1] - a[1]);
|
|
1628
|
+
for (const [status, count] of entries) {
|
|
1629
|
+
lines.push(` ${status.padEnd(20)} ${count}`);
|
|
1630
|
+
}
|
|
1391
1631
|
}
|
|
1392
1632
|
output(res, lines.join("\n"));
|
|
1393
1633
|
} catch (err) {
|
|
1394
1634
|
handleError(err);
|
|
1395
1635
|
}
|
|
1396
1636
|
});
|
|
1637
|
+
cmd.command("estimate <agent_id>").description("Estimate the cost of calling another agent before invoking").requiredOption("--input-tokens <n>", "Estimated input token count").requiredOption("--output-tokens <n>", "Estimated output token count").action(
|
|
1638
|
+
async (agentId, opts) => {
|
|
1639
|
+
const inputTokens = Number(opts.inputTokens);
|
|
1640
|
+
const outputTokens = Number(opts.outputTokens);
|
|
1641
|
+
if (!Number.isFinite(inputTokens) || inputTokens < 0) {
|
|
1642
|
+
console.error("--input-tokens must be a non-negative number.");
|
|
1643
|
+
process.exit(1);
|
|
1644
|
+
}
|
|
1645
|
+
if (!Number.isFinite(outputTokens) || outputTokens < 0) {
|
|
1646
|
+
console.error("--output-tokens must be a non-negative number.");
|
|
1647
|
+
process.exit(1);
|
|
1648
|
+
}
|
|
1649
|
+
try {
|
|
1650
|
+
const res = await acnPost("/payments/billing/estimate", {
|
|
1651
|
+
agent_id: agentId,
|
|
1652
|
+
estimated_input_tokens: inputTokens,
|
|
1653
|
+
estimated_output_tokens: outputTokens
|
|
1654
|
+
});
|
|
1655
|
+
const e = res.estimate ?? {};
|
|
1656
|
+
const lines = [
|
|
1657
|
+
`Estimate for ${res.agent_id} (${inputTokens} in / ${outputTokens} out tokens):`,
|
|
1658
|
+
` Total : $${e.total_usd ?? "?"} (${e.total_credits ?? "?"} credits)`,
|
|
1659
|
+
` Network fee : $${e.network_fee_usd ?? "?"} (${e.network_fee_credits ?? "?"} credits)`,
|
|
1660
|
+
` Agent income : $${e.agent_income_usd ?? "?"} (${e.agent_income_credits ?? "?"} credits)`
|
|
1661
|
+
];
|
|
1662
|
+
if (res.note) lines.push(` Note: ${res.note}`);
|
|
1663
|
+
output(res, lines.join("\n"));
|
|
1664
|
+
} catch (err) {
|
|
1665
|
+
handleError(err);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
);
|
|
1669
|
+
return cmd;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
// src/commands/pay.ts
|
|
1673
|
+
var import_commander13 = require("commander");
|
|
1674
|
+
function requireAgentId7() {
|
|
1675
|
+
const config = loadConfig();
|
|
1676
|
+
if (!config.api_key) {
|
|
1677
|
+
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
1678
|
+
process.exit(1);
|
|
1679
|
+
}
|
|
1680
|
+
if (!config.agent_id) {
|
|
1681
|
+
console.error("No agent ID found. Run `acn join` first or `acn config set agent-id <id>`.");
|
|
1682
|
+
process.exit(1);
|
|
1683
|
+
}
|
|
1684
|
+
return config.agent_id;
|
|
1685
|
+
}
|
|
1686
|
+
function payCommand() {
|
|
1687
|
+
const cmd = new import_commander13.Command("pay").description("Manage payment tasks between agents");
|
|
1688
|
+
const createCmd = new import_commander13.Command("create").description("Create a payment task to another agent");
|
|
1689
|
+
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(
|
|
1690
|
+
async (opts) => {
|
|
1691
|
+
const fromAgent = requireAgentId7();
|
|
1692
|
+
const amount = Number(opts.amount);
|
|
1693
|
+
if (!Number.isFinite(amount) || amount <= 0) {
|
|
1694
|
+
console.error("--amount must be a positive number.");
|
|
1695
|
+
process.exit(1);
|
|
1696
|
+
}
|
|
1697
|
+
let metadata;
|
|
1698
|
+
if (opts.metadata) {
|
|
1699
|
+
try {
|
|
1700
|
+
const parsed = JSON.parse(opts.metadata);
|
|
1701
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
1702
|
+
throw new Error("--metadata must be a JSON object");
|
|
1703
|
+
}
|
|
1704
|
+
metadata = parsed;
|
|
1705
|
+
} catch (err) {
|
|
1706
|
+
console.error(
|
|
1707
|
+
`Invalid --metadata JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
1708
|
+
);
|
|
1709
|
+
process.exit(1);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
const body = {
|
|
1713
|
+
from_agent: fromAgent,
|
|
1714
|
+
to_agent: opts.to,
|
|
1715
|
+
amount,
|
|
1716
|
+
currency: opts.currency,
|
|
1717
|
+
payment_method: opts.method,
|
|
1718
|
+
network: opts.network
|
|
1719
|
+
};
|
|
1720
|
+
if (opts.description !== void 0) body.description = opts.description;
|
|
1721
|
+
if (metadata !== void 0) body.metadata = metadata;
|
|
1722
|
+
try {
|
|
1723
|
+
const res = await acnPost("/payments/tasks", body);
|
|
1724
|
+
output(
|
|
1725
|
+
res,
|
|
1726
|
+
`Payment task ${res.status}: ${res.task_id}
|
|
1727
|
+
${fromAgent} -> ${opts.to}: ${amount} ${opts.currency} via ${opts.method}/${opts.network}`
|
|
1728
|
+
);
|
|
1729
|
+
} catch (err) {
|
|
1730
|
+
handleError(err);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
);
|
|
1734
|
+
const confirmCmd = new import_commander13.Command("confirm").description(
|
|
1735
|
+
"Confirm an external payment has been made (buyer only)"
|
|
1736
|
+
);
|
|
1737
|
+
confirmCmd.requiredOption("--task-id <id>", "Payment task ID to confirm").requiredOption(
|
|
1738
|
+
"--tx-hash <hash>",
|
|
1739
|
+
"On-chain transaction hash or external payment reference (e.g. Stripe charge ID)"
|
|
1740
|
+
).action(async (opts) => {
|
|
1741
|
+
try {
|
|
1742
|
+
const res = await acnPost(
|
|
1743
|
+
`/payments/tasks/${opts.taskId}/confirm`,
|
|
1744
|
+
{ tx_hash: opts.txHash }
|
|
1745
|
+
);
|
|
1746
|
+
output(
|
|
1747
|
+
res,
|
|
1748
|
+
`Payment confirmed: ${res.task_id}
|
|
1749
|
+
status : ${res.status}
|
|
1750
|
+
tx_hash: ${res.tx_hash}`
|
|
1751
|
+
);
|
|
1752
|
+
} catch (err) {
|
|
1753
|
+
handleError(err);
|
|
1754
|
+
}
|
|
1755
|
+
});
|
|
1756
|
+
const statusCmd = new import_commander13.Command("status").description(
|
|
1757
|
+
"Show payment tasks for the authenticated agent"
|
|
1758
|
+
);
|
|
1759
|
+
statusCmd.option("--status <s>", "Filter by status (e.g. created, payment_confirmed)").option("--limit <n>", "Max results (default 50)", "50").action(async (opts) => {
|
|
1760
|
+
const agentId = requireAgentId7();
|
|
1761
|
+
try {
|
|
1762
|
+
const res = await acnGet(
|
|
1763
|
+
`/payments/tasks/agent/${agentId}`,
|
|
1764
|
+
{ status: opts.status, limit: Number(opts.limit) }
|
|
1765
|
+
);
|
|
1766
|
+
output(res, `${res.tasks.length} payment task(s) for ${res.agent_id}`);
|
|
1767
|
+
} catch (err) {
|
|
1768
|
+
handleError(err);
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
cmd.addCommand(createCmd);
|
|
1772
|
+
cmd.addCommand(confirmCmd);
|
|
1773
|
+
cmd.addCommand(statusCmd);
|
|
1774
|
+
return cmd;
|
|
1397
1775
|
}
|
|
1398
1776
|
|
|
1399
1777
|
// src/index.ts
|
|
1400
|
-
var program = new
|
|
1778
|
+
var program = new import_commander14.Command();
|
|
1401
1779
|
program.name("acn").description("ACN CLI \u2014 Agent Collaboration Network command-line interface").version("0.1.0").option("--json", "Output raw JSON (useful for agent parsing)").hook("preAction", (thisCommand) => {
|
|
1402
1780
|
const opts = thisCommand.opts();
|
|
1403
1781
|
if (opts.json) setJsonMode(true);
|
|
@@ -1414,4 +1792,5 @@ program.addCommand(sessionCommand());
|
|
|
1414
1792
|
program.addCommand(subnetCommand());
|
|
1415
1793
|
program.addCommand(followCommand());
|
|
1416
1794
|
program.addCommand(walletCommand());
|
|
1795
|
+
program.addCommand(payCommand());
|
|
1417
1796
|
program.parse(process.argv);
|