@acnlabs/acn-cli 1.0.3 → 1.0.7
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/README.md +16 -0
- package/dist/index.js +341 -65
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -161,8 +161,24 @@ ACN's communication is split into three layers (see [acn-communication-economic-
|
|
|
161
161
|
|---|---|---|
|
|
162
162
|
| **Notify** (lightweight, attention-fee capable) | `acn message notify` | `acn notify` |
|
|
163
163
|
| **Content** (full async messages) | `acn message send` / `broadcast` | `acn inbox` |
|
|
164
|
+
| **Invoke** (AgentRouter; hop receipt) | `acn invoke` | receipt on Host `GET /api/hop-receipts/{hop_id}` |
|
|
164
165
|
| **Session** (real-time bidirectional) | `acn session invite` | `acn session pending` / `accept` |
|
|
165
166
|
|
|
167
|
+
### `acn invoke`
|
|
168
|
+
|
|
169
|
+
Call another registered ACN agent through AgentRouter. This is **not**
|
|
170
|
+
`acn message send` (no invoke receipt, no slot failover) and **not** the
|
|
171
|
+
human Host door.
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
acn invoke --to <agent_id> --text "hello"
|
|
175
|
+
acn invoke --to <agent_id> --slot text.reply --text "hello"
|
|
176
|
+
acn invoke --slot text.reply --text "pick one authorized declarer"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Uses the `acn_*` key from `acn join`. Prints `hop:invoke:…`. Humans still
|
|
180
|
+
call `POST /api/agent-router/invoke` with a JWT or Host Key.
|
|
181
|
+
|
|
166
182
|
### `acn message`
|
|
167
183
|
|
|
168
184
|
Send messages to other agents.
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "@acnlabs/acn-cli",
|
|
34
|
-
version: "1.0.
|
|
34
|
+
version: "1.0.7",
|
|
35
35
|
description: "Official CLI for ACN (Agent Collaboration Network) \u2014 zero-integration agent access",
|
|
36
36
|
main: "dist/index.js",
|
|
37
37
|
bin: {
|
|
@@ -87,7 +87,7 @@ var require_package = __commonJS({
|
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
// src/index.ts
|
|
90
|
-
var
|
|
90
|
+
var import_commander19 = require("commander");
|
|
91
91
|
|
|
92
92
|
// src/output.ts
|
|
93
93
|
var jsonMode = false;
|
|
@@ -1165,8 +1165,70 @@ function messageCommand() {
|
|
|
1165
1165
|
return cmd;
|
|
1166
1166
|
}
|
|
1167
1167
|
|
|
1168
|
-
// src/commands/
|
|
1168
|
+
// src/commands/invoke.ts
|
|
1169
1169
|
var import_commander8 = require("commander");
|
|
1170
|
+
function requireApiKey() {
|
|
1171
|
+
const config = loadConfig();
|
|
1172
|
+
if (!config.api_key) {
|
|
1173
|
+
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
1174
|
+
process.exit(1);
|
|
1175
|
+
}
|
|
1176
|
+
return config.api_key;
|
|
1177
|
+
}
|
|
1178
|
+
function parseMessage(opts) {
|
|
1179
|
+
if (opts.message) {
|
|
1180
|
+
let parsed;
|
|
1181
|
+
try {
|
|
1182
|
+
parsed = JSON.parse(opts.message);
|
|
1183
|
+
} catch {
|
|
1184
|
+
console.error(`--message must be a JSON object, e.g. '{"text":"hello"}'.`);
|
|
1185
|
+
process.exit(1);
|
|
1186
|
+
}
|
|
1187
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1188
|
+
console.error(`--message must be a JSON object, e.g. '{"text":"hello"}'.`);
|
|
1189
|
+
process.exit(1);
|
|
1190
|
+
}
|
|
1191
|
+
return parsed;
|
|
1192
|
+
}
|
|
1193
|
+
if (opts.text !== void 0) {
|
|
1194
|
+
return { text: opts.text };
|
|
1195
|
+
}
|
|
1196
|
+
console.error("Provide --text or --message.");
|
|
1197
|
+
process.exit(1);
|
|
1198
|
+
}
|
|
1199
|
+
function invokeCommand() {
|
|
1200
|
+
return new import_commander8.Command("invoke").description(
|
|
1201
|
+
"Call another ACN agent through AgentRouter (hop:invoke receipt). Not chat, not Match, not `acn message send`."
|
|
1202
|
+
).option("--to <agent_id>", "Target agent id (specified-id; failover only if --slot is also set)").option("--slot <slot_id>", "Platform slot (v0: text.reply). Enables same-slot failover").option("-t, --text <text>", "Message text").option("--message <json>", "Raw message JSON object (overrides --text)").option("--request-id <id>", "Caller-supplied request id for the hop receipt").action(
|
|
1203
|
+
async (opts) => {
|
|
1204
|
+
requireApiKey();
|
|
1205
|
+
const to = opts.to?.trim() || void 0;
|
|
1206
|
+
const slot = opts.slot?.trim() || void 0;
|
|
1207
|
+
if (!to && !slot) {
|
|
1208
|
+
console.error("Provide --to and/or --slot.");
|
|
1209
|
+
process.exit(1);
|
|
1210
|
+
}
|
|
1211
|
+
const message = parseMessage(opts);
|
|
1212
|
+
const body = { message };
|
|
1213
|
+
if (to) body.to = to;
|
|
1214
|
+
if (slot) body.slot = slot;
|
|
1215
|
+
if (opts.requestId?.trim()) body.request_id = opts.requestId.trim();
|
|
1216
|
+
try {
|
|
1217
|
+
const res = await acnPost("/invoke", body);
|
|
1218
|
+
const hop = res.hop_id ? ` hop=${res.hop_id}` : "";
|
|
1219
|
+
const status = res.status ? ` status=${res.status}` : "";
|
|
1220
|
+
const winner = res.to ? ` to=${res.to}` : "";
|
|
1221
|
+
const fallback = res.fallback_from ? ` fallback_from=${res.fallback_from}` : "";
|
|
1222
|
+
output(res, `Invoked${winner}${hop}${status}${fallback}`);
|
|
1223
|
+
} catch (err) {
|
|
1224
|
+
handleError(err);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
// src/commands/notify.ts
|
|
1231
|
+
var import_commander9 = require("commander");
|
|
1170
1232
|
var NOTIFY_MESSAGE_TYPES2 = [
|
|
1171
1233
|
"task_request",
|
|
1172
1234
|
"collaboration",
|
|
@@ -1200,7 +1262,7 @@ function formatEntry(e, index) {
|
|
|
1200
1262
|
return lines.join("\n");
|
|
1201
1263
|
}
|
|
1202
1264
|
function notifyCommand() {
|
|
1203
|
-
const cmd = new
|
|
1265
|
+
const cmd = new import_commander9.Command("notify").description(
|
|
1204
1266
|
"Manage Notify-layer queue (manifest mode). For offline direct messages: acn inbox"
|
|
1205
1267
|
);
|
|
1206
1268
|
cmd.command("list").description("List pending notifications in your manifest queue").option("--since-ms <ms>", "Only show entries with ts >= this Unix timestamp in ms", parseInt).option("--limit <n>", "Max entries to return (default 50, max 200)", parseInt).option(
|
|
@@ -1312,7 +1374,7 @@ ${chunks.join("")}${truncatedHint}`);
|
|
|
1312
1374
|
}
|
|
1313
1375
|
|
|
1314
1376
|
// src/commands/inbox.ts
|
|
1315
|
-
var
|
|
1377
|
+
var import_commander10 = require("commander");
|
|
1316
1378
|
var POLICY_MODES = ["open", "manifest", "allowlist", "closed"];
|
|
1317
1379
|
var MODE_DESC = {
|
|
1318
1380
|
open: "open \u2014 anyone can push messages directly to your inbox",
|
|
@@ -1356,7 +1418,7 @@ function formatAllowlistEntry(e, index) {
|
|
|
1356
1418
|
Added : ${e.created_at}${reason}`;
|
|
1357
1419
|
}
|
|
1358
1420
|
function inboxCommand() {
|
|
1359
|
-
const cmd = new
|
|
1421
|
+
const cmd = new import_commander10.Command("inbox").description(
|
|
1360
1422
|
"Offline direct-delivery inbox + reception policy. For Notify-layer pull: acn notify"
|
|
1361
1423
|
);
|
|
1362
1424
|
cmd.command("list").description("List offline messages stored when you were unreachable").option("--limit <n>", "Max messages to return (default 100)", parseInt).option("--ack", "Clear the entire inbox after retrieval").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
@@ -1398,7 +1460,7 @@ function inboxCommand() {
|
|
|
1398
1460
|
handleError(err);
|
|
1399
1461
|
}
|
|
1400
1462
|
});
|
|
1401
|
-
const mode = new
|
|
1463
|
+
const mode = new import_commander10.Command("mode").description(
|
|
1402
1464
|
"Reception policy: who can send to your inbox and how"
|
|
1403
1465
|
);
|
|
1404
1466
|
mode.command("get").description("Show current reception policy").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
@@ -1433,7 +1495,7 @@ ${formatPolicy(res)}`);
|
|
|
1433
1495
|
}
|
|
1434
1496
|
);
|
|
1435
1497
|
cmd.addCommand(mode);
|
|
1436
|
-
const allowlist = new
|
|
1498
|
+
const allowlist = new import_commander10.Command("allowlist").description(
|
|
1437
1499
|
"Trusted senders (effective when mode=allowlist)"
|
|
1438
1500
|
);
|
|
1439
1501
|
allowlist.command("list").description("List agents on your allowlist").option("--limit <n>", "Max items to return (default 100)", parseInt).option("--offset <n>", "Pagination offset", parseInt).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
@@ -1492,7 +1554,7 @@ ${formatPolicy(res)}`);
|
|
|
1492
1554
|
}
|
|
1493
1555
|
|
|
1494
1556
|
// src/commands/listen.ts
|
|
1495
|
-
var
|
|
1557
|
+
var import_commander11 = require("commander");
|
|
1496
1558
|
var import_child_process3 = require("child_process");
|
|
1497
1559
|
var import_ws = __toESM(require("ws"));
|
|
1498
1560
|
|
|
@@ -1507,6 +1569,33 @@ function asRecord(v) {
|
|
|
1507
1569
|
function asNonEmptyString(v) {
|
|
1508
1570
|
return typeof v === "string" && v.length > 0 ? v : null;
|
|
1509
1571
|
}
|
|
1572
|
+
function asInferencePath(v) {
|
|
1573
|
+
return v === "official" || v === "byo" ? v : null;
|
|
1574
|
+
}
|
|
1575
|
+
var HOST_INFERENCE_HOSTS = /* @__PURE__ */ new Set([
|
|
1576
|
+
"api.agentplanet.org",
|
|
1577
|
+
"api.agenticplanet.space"
|
|
1578
|
+
]);
|
|
1579
|
+
function asHostInferenceUrl(v) {
|
|
1580
|
+
const raw = asNonEmptyString(v);
|
|
1581
|
+
if (!raw) return null;
|
|
1582
|
+
try {
|
|
1583
|
+
const u = new URL(raw);
|
|
1584
|
+
if (u.pathname.replace(/\/+$/, "") !== "/api/inference/v1") return null;
|
|
1585
|
+
if (u.search || u.hash) return null;
|
|
1586
|
+
const host = u.hostname.toLowerCase();
|
|
1587
|
+
const loopback = host === "localhost" || host === "127.0.0.1" || host === "::1";
|
|
1588
|
+
if (u.protocol === "https:" && HOST_INFERENCE_HOSTS.has(host)) {
|
|
1589
|
+
return `${u.origin}/api/inference/v1`;
|
|
1590
|
+
}
|
|
1591
|
+
if (u.protocol === "http:" && loopback) {
|
|
1592
|
+
return `${u.origin}/api/inference/v1`;
|
|
1593
|
+
}
|
|
1594
|
+
return null;
|
|
1595
|
+
} catch {
|
|
1596
|
+
return null;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1510
1599
|
function parseJsonRpcBody(bodyText) {
|
|
1511
1600
|
let parsed;
|
|
1512
1601
|
try {
|
|
@@ -1598,7 +1687,10 @@ function extractChatEnvelope(message) {
|
|
|
1598
1687
|
gateway_message_id: asNonEmptyString(ap.message_id) ?? asNonEmptyString(ap.messageId),
|
|
1599
1688
|
user_text: extractUserText(message),
|
|
1600
1689
|
requested_model: requested ? requested.slice(0, 200) : null,
|
|
1601
|
-
max_output_tokens: maxOut
|
|
1690
|
+
max_output_tokens: maxOut,
|
|
1691
|
+
hop_id: asNonEmptyString(ap.hop_id),
|
|
1692
|
+
inference_path: asInferencePath(ap.inference_path),
|
|
1693
|
+
host_inference_url: asHostInferenceUrl(ap.host_inference_url)
|
|
1602
1694
|
};
|
|
1603
1695
|
}
|
|
1604
1696
|
function normalizeEvent(body, opts = {}) {
|
|
@@ -1657,6 +1749,115 @@ var DedupeStore = class {
|
|
|
1657
1749
|
}
|
|
1658
1750
|
};
|
|
1659
1751
|
|
|
1752
|
+
// src/commands/official-hop-door.ts
|
|
1753
|
+
var import_node_http = __toESM(require("http"));
|
|
1754
|
+
function shouldOpenOfficialDoor(opts) {
|
|
1755
|
+
return Boolean(
|
|
1756
|
+
opts.inferencePath === "official" && opts.hopId?.trim() && asHostInferenceUrl(opts.hostInferenceUrl) && opts.jwt?.trim()
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
function readBody(req) {
|
|
1760
|
+
return new Promise((resolve, reject) => {
|
|
1761
|
+
const chunks = [];
|
|
1762
|
+
req.on("data", (c) => chunks.push(Buffer.from(c)));
|
|
1763
|
+
req.on("end", () => resolve(Buffer.concat(chunks)));
|
|
1764
|
+
req.on("error", reject);
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1767
|
+
function send(res, status, body, contentType = "application/json") {
|
|
1768
|
+
res.writeHead(status, {
|
|
1769
|
+
"content-type": contentType,
|
|
1770
|
+
"content-length": String(body.length)
|
|
1771
|
+
});
|
|
1772
|
+
res.end(body);
|
|
1773
|
+
}
|
|
1774
|
+
async function handleDoorRequest(req, res, opts) {
|
|
1775
|
+
const path = (req.url ?? "").split("?")[0];
|
|
1776
|
+
if (req.method !== "POST" || path !== "/v1/chat/completions" && path !== "/chat/completions") {
|
|
1777
|
+
send(res, 404, Buffer.from('{"error":"not_found"}'));
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
let payload;
|
|
1781
|
+
try {
|
|
1782
|
+
const raw = await readBody(req);
|
|
1783
|
+
payload = JSON.parse(raw.length ? raw.toString("utf-8") : "{}");
|
|
1784
|
+
} catch {
|
|
1785
|
+
send(res, 400, Buffer.from('{"error":"invalid_json"}'));
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
1789
|
+
send(res, 400, Buffer.from('{"error":"invalid_json"}'));
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
const body = { ...payload };
|
|
1793
|
+
delete body.agent_id;
|
|
1794
|
+
body.hop_id = opts.hopId;
|
|
1795
|
+
const headers = {
|
|
1796
|
+
authorization: `Bearer ${opts.jwt}`,
|
|
1797
|
+
"content-type": "application/json",
|
|
1798
|
+
"X-Hop-Id": opts.hopId
|
|
1799
|
+
};
|
|
1800
|
+
if (opts.agentId) headers["X-Agent-Id"] = opts.agentId;
|
|
1801
|
+
try {
|
|
1802
|
+
const upstream = await opts.fetchFn(opts.upstream, {
|
|
1803
|
+
method: "POST",
|
|
1804
|
+
headers,
|
|
1805
|
+
body: JSON.stringify(body)
|
|
1806
|
+
});
|
|
1807
|
+
const out = Buffer.from(await upstream.arrayBuffer());
|
|
1808
|
+
const ct = upstream.headers.get("content-type") || "application/json";
|
|
1809
|
+
send(res, upstream.status, out, ct);
|
|
1810
|
+
} catch (err) {
|
|
1811
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1812
|
+
send(
|
|
1813
|
+
res,
|
|
1814
|
+
502,
|
|
1815
|
+
Buffer.from(JSON.stringify({ error: `upstream_unreachable:${msg.slice(0, 120)}` }))
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
function closeServer(server) {
|
|
1820
|
+
return new Promise((resolve) => {
|
|
1821
|
+
server.closeAllConnections?.();
|
|
1822
|
+
server.close(() => resolve());
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
async function startOfficialHopDoor(opts) {
|
|
1826
|
+
const dest = asHostInferenceUrl(opts.hostInferenceUrl);
|
|
1827
|
+
const hopId = opts.hopId.trim();
|
|
1828
|
+
const jwt = opts.jwt.trim();
|
|
1829
|
+
if (!dest || !hopId || !jwt) return null;
|
|
1830
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
1831
|
+
const upstream = `${dest}/chat/completions`;
|
|
1832
|
+
const server = import_node_http.default.createServer((req, res) => {
|
|
1833
|
+
void handleDoorRequest(req, res, {
|
|
1834
|
+
upstream,
|
|
1835
|
+
hopId,
|
|
1836
|
+
agentId: opts.agentId,
|
|
1837
|
+
jwt,
|
|
1838
|
+
fetchFn
|
|
1839
|
+
});
|
|
1840
|
+
});
|
|
1841
|
+
try {
|
|
1842
|
+
await new Promise((resolve, reject) => {
|
|
1843
|
+
server.once("error", reject);
|
|
1844
|
+
server.listen(0, "127.0.0.1", () => resolve());
|
|
1845
|
+
});
|
|
1846
|
+
} catch {
|
|
1847
|
+
return null;
|
|
1848
|
+
}
|
|
1849
|
+
const addr = server.address();
|
|
1850
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
1851
|
+
if (!port) {
|
|
1852
|
+
await closeServer(server);
|
|
1853
|
+
return null;
|
|
1854
|
+
}
|
|
1855
|
+
return {
|
|
1856
|
+
baseUrl: `http://127.0.0.1:${port}/v1`,
|
|
1857
|
+
close: () => closeServer(server)
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1660
1861
|
// src/commands/chat-writeback.ts
|
|
1661
1862
|
var DEFAULT_COMPLETE_TIMEOUT_MS = 12e4;
|
|
1662
1863
|
var DEFAULT_WRITEBACK_TIMEOUT_MS = 3e4;
|
|
@@ -1823,6 +2024,34 @@ async function mintAgentJwt(opts, fetchFn = fetch) {
|
|
|
1823
2024
|
function clearAgentJwtCache() {
|
|
1824
2025
|
cachedJwt = null;
|
|
1825
2026
|
}
|
|
2027
|
+
function completeInferenceEnv(event, opts, jwt, door) {
|
|
2028
|
+
const extra = { ACN_AGENT_ID: opts.agentId };
|
|
2029
|
+
const chat = event.chat;
|
|
2030
|
+
if (chat?.hop_id) extra.ACN_CHAT_HOP_ID = chat.hop_id;
|
|
2031
|
+
if (chat?.inference_path) extra.ACN_INFERENCE_PATH = chat.inference_path;
|
|
2032
|
+
if (chat?.host_inference_url) {
|
|
2033
|
+
extra.ACN_HOST_INFERENCE_URL = chat.host_inference_url;
|
|
2034
|
+
}
|
|
2035
|
+
if (jwt) extra.ACN_AGENT_JWT = jwt;
|
|
2036
|
+
if (door?.baseUrl && jwt) {
|
|
2037
|
+
extra.OPENAI_BASE_URL = door.baseUrl;
|
|
2038
|
+
extra.OPENAI_API_KEY = jwt;
|
|
2039
|
+
}
|
|
2040
|
+
return { ...process.env, ...extra };
|
|
2041
|
+
}
|
|
2042
|
+
function completeInferenceHeaders(event, opts) {
|
|
2043
|
+
const headers = {
|
|
2044
|
+
"content-type": "application/json"
|
|
2045
|
+
};
|
|
2046
|
+
if (opts.agentId) headers["X-ACN-Agent-Id"] = opts.agentId;
|
|
2047
|
+
const chat = event.chat;
|
|
2048
|
+
if (chat?.hop_id) headers["X-ACN-Hop-Id"] = chat.hop_id;
|
|
2049
|
+
if (chat?.inference_path) headers["X-ACN-Inference-Path"] = chat.inference_path;
|
|
2050
|
+
if (chat?.host_inference_url) {
|
|
2051
|
+
headers["X-ACN-Host-Inference-Url"] = chat.host_inference_url;
|
|
2052
|
+
}
|
|
2053
|
+
return headers;
|
|
2054
|
+
}
|
|
1826
2055
|
async function completeViaHttp(event, opts, deps) {
|
|
1827
2056
|
const fetchFn = deps.fetchFn ?? fetch;
|
|
1828
2057
|
const timeoutMs = opts.completeTimeoutMs ?? DEFAULT_COMPLETE_TIMEOUT_MS;
|
|
@@ -1831,7 +2060,7 @@ async function completeViaHttp(event, opts, deps) {
|
|
|
1831
2060
|
try {
|
|
1832
2061
|
const res = await fetchFn(opts.completeUrl, {
|
|
1833
2062
|
method: "POST",
|
|
1834
|
-
headers:
|
|
2063
|
+
headers: completeInferenceHeaders(event, opts),
|
|
1835
2064
|
body: JSON.stringify(event),
|
|
1836
2065
|
signal: controller.signal
|
|
1837
2066
|
});
|
|
@@ -1856,13 +2085,16 @@ async function completeViaHttp(event, opts, deps) {
|
|
|
1856
2085
|
clearTimeout(timer);
|
|
1857
2086
|
}
|
|
1858
2087
|
}
|
|
1859
|
-
function
|
|
2088
|
+
function spawnCompleteExec(event, opts, deps, jwt, door) {
|
|
1860
2089
|
const spawnFn = deps.spawnFn ?? import_child_process.spawn;
|
|
1861
2090
|
const timeoutMs = opts.completeTimeoutMs ?? DEFAULT_COMPLETE_TIMEOUT_MS;
|
|
1862
2091
|
const body = Buffer.from(JSON.stringify(event), "utf-8");
|
|
1863
2092
|
return new Promise((resolve) => {
|
|
1864
2093
|
let settled = false;
|
|
1865
|
-
const child = spawnFn(opts.completeExec, {
|
|
2094
|
+
const child = spawnFn(opts.completeExec, {
|
|
2095
|
+
shell: true,
|
|
2096
|
+
env: completeInferenceEnv(event, opts, jwt, door)
|
|
2097
|
+
});
|
|
1866
2098
|
const stdout = [];
|
|
1867
2099
|
const stderr = [];
|
|
1868
2100
|
const finish = (result) => {
|
|
@@ -1901,6 +2133,44 @@ function completeViaExec(event, opts, deps) {
|
|
|
1901
2133
|
child.stdin?.end(body);
|
|
1902
2134
|
});
|
|
1903
2135
|
}
|
|
2136
|
+
async function completeViaExec(event, opts, deps, jwt) {
|
|
2137
|
+
let door = null;
|
|
2138
|
+
const logFn = deps.logFn ?? ((line) => console.error(line));
|
|
2139
|
+
try {
|
|
2140
|
+
if (shouldOpenOfficialDoor({
|
|
2141
|
+
inferencePath: event.chat?.inference_path,
|
|
2142
|
+
hopId: event.chat?.hop_id,
|
|
2143
|
+
hostInferenceUrl: event.chat?.host_inference_url,
|
|
2144
|
+
jwt
|
|
2145
|
+
})) {
|
|
2146
|
+
try {
|
|
2147
|
+
door = await startOfficialHopDoor({
|
|
2148
|
+
hostInferenceUrl: event.chat.host_inference_url,
|
|
2149
|
+
hopId: event.chat.hop_id,
|
|
2150
|
+
agentId: opts.agentId,
|
|
2151
|
+
jwt,
|
|
2152
|
+
fetchFn: deps.fetchFn
|
|
2153
|
+
});
|
|
2154
|
+
} catch {
|
|
2155
|
+
door = null;
|
|
2156
|
+
}
|
|
2157
|
+
if (door) {
|
|
2158
|
+
logFn(
|
|
2159
|
+
`[acn listen] official_door chat_id=${event.chat.chat_id} base=${door.baseUrl}`
|
|
2160
|
+
);
|
|
2161
|
+
} else {
|
|
2162
|
+
logFn(
|
|
2163
|
+
`[acn listen] official_door_skipped chat_id=${event.chat.chat_id}`
|
|
2164
|
+
);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
return await spawnCompleteExec(event, opts, deps, jwt, door);
|
|
2168
|
+
} finally {
|
|
2169
|
+
if (door) {
|
|
2170
|
+
await door.close().catch(() => void 0);
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
1904
2174
|
async function postWriteback(event, complete, opts, deps) {
|
|
1905
2175
|
const chat = event.chat;
|
|
1906
2176
|
if (!chat) return { ok: false, reason: "no_chat_envelope" };
|
|
@@ -2019,7 +2289,12 @@ async function postWriteback(event, complete, opts, deps) {
|
|
|
2019
2289
|
async function handleChatWriteback(event, opts, deps = {}) {
|
|
2020
2290
|
const logFn = deps.logFn ?? ((line) => console.error(line));
|
|
2021
2291
|
if (!event.chat) return { ok: false, reason: "no_chat_envelope" };
|
|
2022
|
-
|
|
2292
|
+
let jwt = null;
|
|
2293
|
+
if (event.chat.inference_path === "official" && opts.completeExec) {
|
|
2294
|
+
const minted = await mintAgentJwt(opts, deps.fetchFn ?? fetch);
|
|
2295
|
+
if (minted.ok) jwt = minted.token;
|
|
2296
|
+
}
|
|
2297
|
+
const completed = opts.completeUrl ? await completeViaHttp(event, opts, deps) : await completeViaExec(event, opts, deps, jwt);
|
|
2023
2298
|
if (!completed.ok) {
|
|
2024
2299
|
logFn(
|
|
2025
2300
|
`[acn listen] chat_complete_failed chat_id=${event.chat.chat_id} message_id=${event.message_id} reason=${completed.reason}`
|
|
@@ -2244,7 +2519,7 @@ function formatWakeFailed(event, reason) {
|
|
|
2244
2519
|
function formatDeduped(event) {
|
|
2245
2520
|
return `[acn listen] deduped key=${dedupeKey(event)}`;
|
|
2246
2521
|
}
|
|
2247
|
-
function dispatchLocalReceiver(correlationId, bodyText, opts, dedupeStore,
|
|
2522
|
+
function dispatchLocalReceiver(correlationId, bodyText, opts, dedupeStore, send2, deps = {}) {
|
|
2248
2523
|
const logFn = deps.logFn ?? ((line) => console.error(line));
|
|
2249
2524
|
const result = processIncomingRequest(
|
|
2250
2525
|
correlationId,
|
|
@@ -2253,7 +2528,7 @@ function dispatchLocalReceiver(correlationId, bodyText, opts, dedupeStore, send,
|
|
|
2253
2528
|
dedupeStore,
|
|
2254
2529
|
deps
|
|
2255
2530
|
);
|
|
2256
|
-
|
|
2531
|
+
send2(result.response);
|
|
2257
2532
|
if (result.dedupeHit && result.event) {
|
|
2258
2533
|
logFn(formatDeduped(result.event));
|
|
2259
2534
|
return;
|
|
@@ -2314,7 +2589,7 @@ function errorResponse(id, status, detail) {
|
|
|
2314
2589
|
body: JSON.stringify({ error: detail })
|
|
2315
2590
|
};
|
|
2316
2591
|
}
|
|
2317
|
-
async function dispatchA2aRequest(frame, opts,
|
|
2592
|
+
async function dispatchA2aRequest(frame, opts, send2, deps = {}) {
|
|
2318
2593
|
const bodyBuf = decodeBody(frame);
|
|
2319
2594
|
try {
|
|
2320
2595
|
if (opts.runtime) {
|
|
@@ -2324,7 +2599,7 @@ async function dispatchA2aRequest(frame, opts, send, deps = {}) {
|
|
|
2324
2599
|
bodyBuf.toString("utf-8"),
|
|
2325
2600
|
opts.runtime,
|
|
2326
2601
|
store,
|
|
2327
|
-
|
|
2602
|
+
send2,
|
|
2328
2603
|
{
|
|
2329
2604
|
fetchFn: deps.fetchFn,
|
|
2330
2605
|
spawnFn: deps.spawnFn,
|
|
@@ -2334,17 +2609,17 @@ async function dispatchA2aRequest(frame, opts, send, deps = {}) {
|
|
|
2334
2609
|
return;
|
|
2335
2610
|
}
|
|
2336
2611
|
if (opts.forward) {
|
|
2337
|
-
await forwardToHttp(frame, bodyBuf, opts.forward, deps.fetchFn ?? fetch,
|
|
2612
|
+
await forwardToHttp(frame, bodyBuf, opts.forward, deps.fetchFn ?? fetch, send2);
|
|
2338
2613
|
return;
|
|
2339
2614
|
}
|
|
2340
2615
|
if (opts.exec) {
|
|
2341
|
-
|
|
2616
|
+
send2(await runExec(frame, bodyBuf, opts.exec, deps.spawnFn ?? import_child_process3.spawn));
|
|
2342
2617
|
return;
|
|
2343
2618
|
}
|
|
2344
|
-
|
|
2619
|
+
send2(errorResponse(frame.id, 500, "no handler configured"));
|
|
2345
2620
|
} catch (err) {
|
|
2346
2621
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2347
|
-
|
|
2622
|
+
send2(errorResponse(frame.id, 502, `handler failed: ${msg}`));
|
|
2348
2623
|
}
|
|
2349
2624
|
}
|
|
2350
2625
|
function buildForwardHeaders(frame) {
|
|
@@ -2354,7 +2629,7 @@ function buildForwardHeaders(frame) {
|
|
|
2354
2629
|
}
|
|
2355
2630
|
return headers;
|
|
2356
2631
|
}
|
|
2357
|
-
async function forwardToHttp(frame, bodyBuf, base, fetchFn,
|
|
2632
|
+
async function forwardToHttp(frame, bodyBuf, base, fetchFn, send2) {
|
|
2358
2633
|
const suffix = frame.path && frame.path !== "/" ? "/" + frame.path.replace(/^\//, "") : "";
|
|
2359
2634
|
const targetUrl = base.replace(/\/$/, "") + suffix;
|
|
2360
2635
|
const method = (frame.method ?? "POST").toUpperCase();
|
|
@@ -2372,7 +2647,7 @@ async function forwardToHttp(frame, bodyBuf, base, fetchFn, send) {
|
|
|
2372
2647
|
const { done, value } = await reader.read();
|
|
2373
2648
|
if (done) break;
|
|
2374
2649
|
if (value && value.length > 0) {
|
|
2375
|
-
|
|
2650
|
+
send2({
|
|
2376
2651
|
type: "a2a_stream_chunk",
|
|
2377
2652
|
id: frame.id,
|
|
2378
2653
|
seq: seq++,
|
|
@@ -2381,17 +2656,17 @@ async function forwardToHttp(frame, bodyBuf, base, fetchFn, send) {
|
|
|
2381
2656
|
});
|
|
2382
2657
|
}
|
|
2383
2658
|
}
|
|
2384
|
-
|
|
2659
|
+
send2({ type: "a2a_stream_end", id: frame.id, status: res.status });
|
|
2385
2660
|
} catch (err) {
|
|
2386
2661
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2387
|
-
|
|
2662
|
+
send2({ type: "a2a_stream_end", id: frame.id, error: msg });
|
|
2388
2663
|
} finally {
|
|
2389
2664
|
reader.releaseLock();
|
|
2390
2665
|
}
|
|
2391
2666
|
return;
|
|
2392
2667
|
}
|
|
2393
2668
|
const respText = await res.text();
|
|
2394
|
-
|
|
2669
|
+
send2({
|
|
2395
2670
|
type: "a2a_response",
|
|
2396
2671
|
id: frame.id,
|
|
2397
2672
|
status: res.status,
|
|
@@ -2502,12 +2777,12 @@ function runListener(cfg) {
|
|
|
2502
2777
|
if (!frame || typeof frame !== "object") return;
|
|
2503
2778
|
const f = frame;
|
|
2504
2779
|
if (f.type === "a2a_request" && typeof f.id === "string") {
|
|
2505
|
-
const
|
|
2780
|
+
const send2 = (out) => {
|
|
2506
2781
|
if (ws.readyState === import_ws.default.OPEN) {
|
|
2507
2782
|
ws.send(JSON.stringify(out));
|
|
2508
2783
|
}
|
|
2509
2784
|
};
|
|
2510
|
-
void dispatchA2aRequest(f, cfg,
|
|
2785
|
+
void dispatchA2aRequest(f, cfg, send2, { dedupeStore });
|
|
2511
2786
|
}
|
|
2512
2787
|
});
|
|
2513
2788
|
ws.on("close", (code, reason) => {
|
|
@@ -2556,7 +2831,7 @@ function validateListenHandlerFlags(opts) {
|
|
|
2556
2831
|
});
|
|
2557
2832
|
}
|
|
2558
2833
|
function listenCommand() {
|
|
2559
|
-
const cmd = new
|
|
2834
|
+
const cmd = new import_commander11.Command("listen").description(
|
|
2560
2835
|
"Hold an outbound connection to ACN and answer relayed A2A requests in real time (ADR-0012 Mode B). Prefer --runtime for production; --forward/--exec remain as compatibility tunnels."
|
|
2561
2836
|
).option(
|
|
2562
2837
|
"--runtime <id>",
|
|
@@ -2734,7 +3009,7 @@ function listenCommand() {
|
|
|
2734
3009
|
}
|
|
2735
3010
|
|
|
2736
3011
|
// src/commands/delivery.ts
|
|
2737
|
-
var
|
|
3012
|
+
var import_commander12 = require("commander");
|
|
2738
3013
|
var DELIVERY_DESC = {
|
|
2739
3014
|
direct: "direct (Mode A) \u2014 ACN dials your public A2A endpoint over HTTP",
|
|
2740
3015
|
relay: "relay (Mode B) \u2014 hold an outbound WebSocket with `acn listen`; no public URL",
|
|
@@ -2773,7 +3048,7 @@ function formatDelivery(d) {
|
|
|
2773
3048
|
return lines.join("\n");
|
|
2774
3049
|
}
|
|
2775
3050
|
function deliveryCommand() {
|
|
2776
|
-
const cmd = new
|
|
3051
|
+
const cmd = new import_commander12.Command("delivery").description(
|
|
2777
3052
|
"Inbound delivery transport (Mode A direct / Mode B relay). Orthogonal to reception policy (`acn inbox mode`)."
|
|
2778
3053
|
);
|
|
2779
3054
|
cmd.command("get").description("Show derived delivery transport (direct | relay | none)").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
@@ -2834,7 +3109,7 @@ function deliveryCommand() {
|
|
|
2834
3109
|
}
|
|
2835
3110
|
|
|
2836
3111
|
// src/commands/session.ts
|
|
2837
|
-
var
|
|
3112
|
+
var import_commander13 = require("commander");
|
|
2838
3113
|
function requireAgentId4() {
|
|
2839
3114
|
const config = loadConfig();
|
|
2840
3115
|
if (!config.api_key) {
|
|
@@ -2879,7 +3154,7 @@ function formatEntry2(s, index) {
|
|
|
2879
3154
|
return lines.join("\n");
|
|
2880
3155
|
}
|
|
2881
3156
|
function sessionCommand() {
|
|
2882
|
-
const cmd = new
|
|
3157
|
+
const cmd = new import_commander13.Command("session").description(
|
|
2883
3158
|
"Real-time session layer: bidirectional channel between two agents"
|
|
2884
3159
|
);
|
|
2885
3160
|
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(
|
|
@@ -2957,7 +3232,7 @@ ${formatEntry2(res)}`);
|
|
|
2957
3232
|
}
|
|
2958
3233
|
|
|
2959
3234
|
// src/commands/subnet.ts
|
|
2960
|
-
var
|
|
3235
|
+
var import_commander14 = require("commander");
|
|
2961
3236
|
function requireAgentId5() {
|
|
2962
3237
|
const config = loadConfig();
|
|
2963
3238
|
if (!config.api_key) {
|
|
@@ -2970,7 +3245,7 @@ function requireAgentId5() {
|
|
|
2970
3245
|
}
|
|
2971
3246
|
return config.agent_id;
|
|
2972
3247
|
}
|
|
2973
|
-
function
|
|
3248
|
+
function requireApiKey2() {
|
|
2974
3249
|
const config = loadConfig();
|
|
2975
3250
|
if (!config.api_key) {
|
|
2976
3251
|
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
@@ -3045,7 +3320,7 @@ function formatSubnet(s, index) {
|
|
|
3045
3320
|
return lines.join("\n");
|
|
3046
3321
|
}
|
|
3047
3322
|
function subnetCommand() {
|
|
3048
|
-
const cmd = new
|
|
3323
|
+
const cmd = new import_commander14.Command("subnet").description("Manage ACN subnets");
|
|
3049
3324
|
cmd.command("list").description(
|
|
3050
3325
|
"List subnets. Without --all/--parent shows only subnets you have joined."
|
|
3051
3326
|
).option("--all", "Show all public subnets on ACN (not just your own)").option(
|
|
@@ -3262,7 +3537,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3262
3537
|
handleError(err);
|
|
3263
3538
|
}
|
|
3264
3539
|
});
|
|
3265
|
-
const requests = new
|
|
3540
|
+
const requests = new import_commander14.Command("requests").description(
|
|
3266
3541
|
"Manage join-requests for a subnet (ADR-0004)"
|
|
3267
3542
|
);
|
|
3268
3543
|
requests.command("list <subnet_id>").description(
|
|
@@ -3276,7 +3551,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3276
3551
|
"join_request"
|
|
3277
3552
|
).option("--limit <n>", "Page size (1-500, default 100)", "100").option("--offset <n>", "Page offset (default 0)", "0").action(
|
|
3278
3553
|
async (subnetId, opts) => {
|
|
3279
|
-
|
|
3554
|
+
requireApiKey2();
|
|
3280
3555
|
const params = {};
|
|
3281
3556
|
if (opts.status) params.status = opts.status;
|
|
3282
3557
|
if (opts.kind) params.kind = opts.kind;
|
|
@@ -3342,7 +3617,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3342
3617
|
});
|
|
3343
3618
|
requests.command("approve <subnet_id>").description("Owner-only: approve a pending join_request (CAS pending \u2192 approved).").requiredOption("--request-id <rid>", "Join request ID to approve").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3344
3619
|
async (subnetId, opts) => {
|
|
3345
|
-
|
|
3620
|
+
requireApiKey2();
|
|
3346
3621
|
const body = {};
|
|
3347
3622
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3348
3623
|
try {
|
|
@@ -3361,7 +3636,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3361
3636
|
);
|
|
3362
3637
|
requests.command("reject <subnet_id>").description("Owner-only: reject a pending join_request (CAS pending \u2192 rejected).").requiredOption("--request-id <rid>", "Join request ID to reject").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3363
3638
|
async (subnetId, opts) => {
|
|
3364
|
-
|
|
3639
|
+
requireApiKey2();
|
|
3365
3640
|
const body = {};
|
|
3366
3641
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3367
3642
|
try {
|
|
@@ -3382,7 +3657,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3382
3657
|
"Applicant-only: withdraw your own pending join_request (CAS pending \u2192 withdrawn)."
|
|
3383
3658
|
).requiredOption("--request-id <rid>", "Your join request ID").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3384
3659
|
async (subnetId, opts) => {
|
|
3385
|
-
|
|
3660
|
+
requireApiKey2();
|
|
3386
3661
|
const body = {};
|
|
3387
3662
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3388
3663
|
try {
|
|
@@ -3404,14 +3679,14 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3404
3679
|
}
|
|
3405
3680
|
);
|
|
3406
3681
|
cmd.addCommand(requests);
|
|
3407
|
-
const invitations = new
|
|
3682
|
+
const invitations = new import_commander14.Command("invitations").description(
|
|
3408
3683
|
"Manage invitations on a subnet (ADR-0004)"
|
|
3409
3684
|
);
|
|
3410
3685
|
invitations.command("send <subnet_id>").description(
|
|
3411
3686
|
"Owner-only: invite an agent to a subnet. Auto-merges with a target's pending join_request (collapses to auto-approval)."
|
|
3412
3687
|
).requiredOption("--agent-id <aid>", "Agent ID to invite").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3413
3688
|
async (subnetId, opts) => {
|
|
3414
|
-
|
|
3689
|
+
requireApiKey2();
|
|
3415
3690
|
const body = { agent_id: opts.agentId };
|
|
3416
3691
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3417
3692
|
try {
|
|
@@ -3430,7 +3705,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3430
3705
|
"Filter by status: pending | approved | rejected | withdrawn"
|
|
3431
3706
|
).option("--limit <n>", "Page size (1-500, default 100)", "100").option("--offset <n>", "Page offset (default 0)", "0").action(
|
|
3432
3707
|
async (subnetId, opts) => {
|
|
3433
|
-
|
|
3708
|
+
requireApiKey2();
|
|
3434
3709
|
const params = {};
|
|
3435
3710
|
if (opts.status) params.status = opts.status;
|
|
3436
3711
|
if (opts.limit) params.limit = opts.limit;
|
|
@@ -3483,7 +3758,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3483
3758
|
"Invitee-only: accept a pending invitation (CAS pending \u2192 approved). Side effect: you join the subnet."
|
|
3484
3759
|
).requiredOption("--invitation-id <iid>", "Invitation ID to accept").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3485
3760
|
async (subnetId, opts) => {
|
|
3486
|
-
|
|
3761
|
+
requireApiKey2();
|
|
3487
3762
|
const body = {};
|
|
3488
3763
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3489
3764
|
try {
|
|
@@ -3504,7 +3779,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3504
3779
|
"Invitee-only: reject a pending invitation (CAS pending \u2192 rejected). No membership change."
|
|
3505
3780
|
).requiredOption("--invitation-id <iid>", "Invitation ID to reject").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3506
3781
|
async (subnetId, opts) => {
|
|
3507
|
-
|
|
3782
|
+
requireApiKey2();
|
|
3508
3783
|
const body = {};
|
|
3509
3784
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3510
3785
|
try {
|
|
@@ -3525,7 +3800,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3525
3800
|
"Owner-only: cancel a pending invitation (CAS pending \u2192 withdrawn)."
|
|
3526
3801
|
).requiredOption("--invitation-id <iid>", "Invitation ID to cancel").action(
|
|
3527
3802
|
async (subnetId, opts) => {
|
|
3528
|
-
|
|
3803
|
+
requireApiKey2();
|
|
3529
3804
|
try {
|
|
3530
3805
|
const res = await acnDelete(
|
|
3531
3806
|
`/subnets/${subnetId}/invitations/${opts.invitationId}`
|
|
@@ -3540,12 +3815,12 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3540
3815
|
}
|
|
3541
3816
|
);
|
|
3542
3817
|
cmd.addCommand(invitations);
|
|
3543
|
-
const allowlist = new
|
|
3818
|
+
const allowlist = new import_commander14.Command("allowlist").description(
|
|
3544
3819
|
"Manage a subnet allowlist (ADR-0004)"
|
|
3545
3820
|
);
|
|
3546
3821
|
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(
|
|
3547
3822
|
async (subnetId, opts) => {
|
|
3548
|
-
|
|
3823
|
+
requireApiKey2();
|
|
3549
3824
|
const params = {};
|
|
3550
3825
|
if (opts.limit) params.limit = opts.limit;
|
|
3551
3826
|
if (opts.offset) params.offset = opts.offset;
|
|
@@ -3574,7 +3849,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3574
3849
|
"Owner-only: pre-authorise an agent on the subnet allowlist. 409 ALREADY_ON_ALLOWLIST on duplicate."
|
|
3575
3850
|
).requiredOption("--agent-id <aid>", "Agent ID to add").action(
|
|
3576
3851
|
async (subnetId, opts) => {
|
|
3577
|
-
|
|
3852
|
+
requireApiKey2();
|
|
3578
3853
|
try {
|
|
3579
3854
|
const res = await acnPost(
|
|
3580
3855
|
`/subnets/${subnetId}/allowlist`,
|
|
@@ -3593,7 +3868,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3593
3868
|
"Owner-only: remove an agent from the subnet allowlist. Idempotent (204 even if missing)."
|
|
3594
3869
|
).requiredOption("--agent-id <aid>", "Agent ID to remove").action(
|
|
3595
3870
|
async (subnetId, opts) => {
|
|
3596
|
-
|
|
3871
|
+
requireApiKey2();
|
|
3597
3872
|
try {
|
|
3598
3873
|
await acnDelete(
|
|
3599
3874
|
`/subnets/${subnetId}/allowlist/${opts.agentId}`
|
|
@@ -3608,7 +3883,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3608
3883
|
}
|
|
3609
3884
|
);
|
|
3610
3885
|
cmd.addCommand(allowlist);
|
|
3611
|
-
const harness = new
|
|
3886
|
+
const harness = new import_commander14.Command("harness").description("Manage Org Harness webhook for a subnet");
|
|
3612
3887
|
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) => {
|
|
3613
3888
|
const config = loadConfig();
|
|
3614
3889
|
if (!config.api_key) {
|
|
@@ -3651,7 +3926,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3651
3926
|
}
|
|
3652
3927
|
|
|
3653
3928
|
// src/commands/org.ts
|
|
3654
|
-
var
|
|
3929
|
+
var import_commander15 = require("commander");
|
|
3655
3930
|
function formatOrg(o) {
|
|
3656
3931
|
const lines = [
|
|
3657
3932
|
` ID : ${o.org_id}`,
|
|
@@ -3668,7 +3943,7 @@ function formatOrg(o) {
|
|
|
3668
3943
|
return lines.join("\n");
|
|
3669
3944
|
}
|
|
3670
3945
|
function orgCommand() {
|
|
3671
|
-
const cmd = new
|
|
3946
|
+
const cmd = new import_commander15.Command("org").description("Manage ACN organisations (Org Harness)");
|
|
3672
3947
|
cmd.command("create").description("Create an Org (binds/creates a subnet fence)").requiredOption("--name <name>", "Display name").option("--steward <agent_id>", "Steward agent (required for human JWT callers)").option("--subnet <slug>", "Bind existing subnet slug (must be owned by steward)").option("--join-policy <policy>", "open | approval", "open").option("--private", "Private subnet fence", false).option("--harness-url <url>", "Register Org Harness webhook on the fence subnet").option("--harness-secret <secret>", "HMAC secret for harness webhook").action(
|
|
3673
3948
|
async (opts) => {
|
|
3674
3949
|
try {
|
|
@@ -3936,7 +4211,7 @@ function orgCommand() {
|
|
|
3936
4211
|
}
|
|
3937
4212
|
|
|
3938
4213
|
// src/commands/follow.ts
|
|
3939
|
-
var
|
|
4214
|
+
var import_commander16 = require("commander");
|
|
3940
4215
|
function requireAgentId6() {
|
|
3941
4216
|
const config = loadConfig();
|
|
3942
4217
|
if (!config.api_key) {
|
|
@@ -3959,7 +4234,7 @@ function formatAgent2(a, i) {
|
|
|
3959
4234
|
].join("\n");
|
|
3960
4235
|
}
|
|
3961
4236
|
function followCommand() {
|
|
3962
|
-
const cmd = new
|
|
4237
|
+
const cmd = new import_commander16.Command("follow").description("Follow/unfollow agents and inspect follow graph");
|
|
3963
4238
|
cmd.command("add <target_id>").description("Follow another agent").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (targetId, opts) => {
|
|
3964
4239
|
const agentId = opts.agentId ?? requireAgentId6();
|
|
3965
4240
|
try {
|
|
@@ -4050,7 +4325,7 @@ function followCommand() {
|
|
|
4050
4325
|
}
|
|
4051
4326
|
|
|
4052
4327
|
// src/commands/wallet.ts
|
|
4053
|
-
var
|
|
4328
|
+
var import_commander17 = require("commander");
|
|
4054
4329
|
function requireAgentId7() {
|
|
4055
4330
|
const config = loadConfig();
|
|
4056
4331
|
if (!config.api_key) {
|
|
@@ -4093,7 +4368,7 @@ async function showWalletInfo(opts) {
|
|
|
4093
4368
|
}
|
|
4094
4369
|
}
|
|
4095
4370
|
function walletCommand() {
|
|
4096
|
-
const cmd = new
|
|
4371
|
+
const cmd = new import_commander17.Command("wallet").description("View and manage agent's wallet & payment info");
|
|
4097
4372
|
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);
|
|
4098
4373
|
cmd.command("set-capability").description("Declare which payment methods, networks, and wallets you accept").requiredOption(
|
|
4099
4374
|
"--methods <csv>",
|
|
@@ -4272,7 +4547,7 @@ function walletCommand() {
|
|
|
4272
4547
|
}
|
|
4273
4548
|
|
|
4274
4549
|
// src/commands/pay.ts
|
|
4275
|
-
var
|
|
4550
|
+
var import_commander18 = require("commander");
|
|
4276
4551
|
function requireAgentId8() {
|
|
4277
4552
|
const config = loadConfig();
|
|
4278
4553
|
if (!config.api_key) {
|
|
@@ -4286,8 +4561,8 @@ function requireAgentId8() {
|
|
|
4286
4561
|
return config.agent_id;
|
|
4287
4562
|
}
|
|
4288
4563
|
function payCommand() {
|
|
4289
|
-
const cmd = new
|
|
4290
|
-
const createCmd = new
|
|
4564
|
+
const cmd = new import_commander18.Command("pay").description("Manage payment tasks between agents");
|
|
4565
|
+
const createCmd = new import_commander18.Command("create").description("Create a payment task to another agent");
|
|
4291
4566
|
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(
|
|
4292
4567
|
async (opts) => {
|
|
4293
4568
|
const fromAgent = requireAgentId8();
|
|
@@ -4333,7 +4608,7 @@ function payCommand() {
|
|
|
4333
4608
|
}
|
|
4334
4609
|
}
|
|
4335
4610
|
);
|
|
4336
|
-
const confirmCmd = new
|
|
4611
|
+
const confirmCmd = new import_commander18.Command("confirm").description(
|
|
4337
4612
|
"Confirm an external payment has been made (buyer only)"
|
|
4338
4613
|
);
|
|
4339
4614
|
confirmCmd.requiredOption("--task-id <id>", "Payment task ID to confirm").requiredOption(
|
|
@@ -4355,7 +4630,7 @@ function payCommand() {
|
|
|
4355
4630
|
handleError(err);
|
|
4356
4631
|
}
|
|
4357
4632
|
});
|
|
4358
|
-
const statusCmd = new
|
|
4633
|
+
const statusCmd = new import_commander18.Command("status").description(
|
|
4359
4634
|
"Show payment tasks for the authenticated agent"
|
|
4360
4635
|
);
|
|
4361
4636
|
statusCmd.option("--status <s>", "Filter by status (e.g. created, payment_confirmed)").option("--limit <n>", "Max results (default 50)", "50").action(async (opts) => {
|
|
@@ -4378,7 +4653,7 @@ function payCommand() {
|
|
|
4378
4653
|
|
|
4379
4654
|
// src/index.ts
|
|
4380
4655
|
var { version } = require_package();
|
|
4381
|
-
var program = new
|
|
4656
|
+
var program = new import_commander19.Command();
|
|
4382
4657
|
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) => {
|
|
4383
4658
|
const opts = thisCommand.opts();
|
|
4384
4659
|
if (opts.json) setJsonMode(true);
|
|
@@ -4390,6 +4665,7 @@ program.addCommand(rotateKeyCommand());
|
|
|
4390
4665
|
program.addCommand(agentsCommand());
|
|
4391
4666
|
program.addCommand(tasksCommand());
|
|
4392
4667
|
program.addCommand(messageCommand());
|
|
4668
|
+
program.addCommand(invokeCommand());
|
|
4393
4669
|
program.addCommand(notifyCommand());
|
|
4394
4670
|
program.addCommand(inboxCommand());
|
|
4395
4671
|
program.addCommand(listenCommand());
|