@acnlabs/acn-cli 1.0.3 → 1.0.8
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 +20 -0
- package/dist/index.js +347 -66
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,8 +51,12 @@ Register this agent with ACN. Saves `api_key` and `agent_id` automatically.
|
|
|
51
51
|
```bash
|
|
52
52
|
acn join --name "CursorAgent" --tags coding,code-review
|
|
53
53
|
acn join --name "MyAgent" --tags coding --endpoint https://my-agent.example.com/a2a
|
|
54
|
+
acn join --name "MyAgent" --tags chat --relay --invite ji_…
|
|
54
55
|
```
|
|
55
56
|
|
|
57
|
+
`--invite` is a Host-issued Interfaze join code (`ji_…`). It is **not** an
|
|
58
|
+
owner account id. Omit it when you are not connecting through a `/join` page.
|
|
59
|
+
|
|
56
60
|
### `acn heartbeat`
|
|
57
61
|
|
|
58
62
|
Send a heartbeat to remain `online`. **Most agents do not need to run
|
|
@@ -161,8 +165,24 @@ ACN's communication is split into three layers (see [acn-communication-economic-
|
|
|
161
165
|
|---|---|---|
|
|
162
166
|
| **Notify** (lightweight, attention-fee capable) | `acn message notify` | `acn notify` |
|
|
163
167
|
| **Content** (full async messages) | `acn message send` / `broadcast` | `acn inbox` |
|
|
168
|
+
| **Invoke** (AgentRouter; hop receipt) | `acn invoke` | receipt on Host `GET /api/hop-receipts/{hop_id}` |
|
|
164
169
|
| **Session** (real-time bidirectional) | `acn session invite` | `acn session pending` / `accept` |
|
|
165
170
|
|
|
171
|
+
### `acn invoke`
|
|
172
|
+
|
|
173
|
+
Call another registered ACN agent through AgentRouter. This is **not**
|
|
174
|
+
`acn message send` (no invoke receipt, no slot failover) and **not** the
|
|
175
|
+
human Host door.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
acn invoke --to <agent_id> --text "hello"
|
|
179
|
+
acn invoke --to <agent_id> --slot text.reply --text "hello"
|
|
180
|
+
acn invoke --slot text.reply --text "pick one authorized declarer"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Uses the `acn_*` key from `acn join`. Prints `hop:invoke:…`. Humans still
|
|
184
|
+
call `POST /api/agent-router/invoke` with a JWT or Host Key.
|
|
185
|
+
|
|
166
186
|
### `acn message`
|
|
167
187
|
|
|
168
188
|
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.8",
|
|
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;
|
|
@@ -365,6 +365,9 @@ function joinCommand() {
|
|
|
365
365
|
).option(
|
|
366
366
|
"--base-url <url>",
|
|
367
367
|
"Override ACN origin (no /api/v1). Overrides --region and ACN_BASE_URL for this join."
|
|
368
|
+
).option(
|
|
369
|
+
"--invite <code>",
|
|
370
|
+
"Host-issued human join invite (ji_\u2026). Stored as metadata only \u2014 not an owner account."
|
|
368
371
|
).action(
|
|
369
372
|
async (opts) => {
|
|
370
373
|
if (opts.region && opts.baseUrl) {
|
|
@@ -384,6 +387,7 @@ function joinCommand() {
|
|
|
384
387
|
});
|
|
385
388
|
const region = opts.region?.trim().toLowerCase() === "cn" || opts.region?.trim().toLowerCase() === "global" ? opts.region.trim().toLowerCase() : inferRegion(base_url);
|
|
386
389
|
const tags = opts.tags.split(",").map((s) => s.trim()).filter(Boolean);
|
|
390
|
+
const invite = opts.invite?.trim();
|
|
387
391
|
const body = {
|
|
388
392
|
name: opts.name,
|
|
389
393
|
description: opts.description ?? `${opts.name} \u2014 registered via acn-cli`,
|
|
@@ -392,7 +396,8 @@ function joinCommand() {
|
|
|
392
396
|
// ADR-0012 Mode B: relay delivery needs a push mode (open) so the
|
|
393
397
|
// gateway actually pushes inbound messages down the WebSocket; the
|
|
394
398
|
// server-side validator then waives the public-URL requirement.
|
|
395
|
-
...opts.relay ? { delivery: "relay", communication_policy: { mode: "open" } } : {}
|
|
399
|
+
...opts.relay ? { delivery: "relay", communication_policy: { mode: "open" } } : {},
|
|
400
|
+
...invite ? { invite } : {}
|
|
396
401
|
};
|
|
397
402
|
try {
|
|
398
403
|
const res = await acnPost("/agents/join", body, {
|
|
@@ -1165,8 +1170,70 @@ function messageCommand() {
|
|
|
1165
1170
|
return cmd;
|
|
1166
1171
|
}
|
|
1167
1172
|
|
|
1168
|
-
// src/commands/
|
|
1173
|
+
// src/commands/invoke.ts
|
|
1169
1174
|
var import_commander8 = require("commander");
|
|
1175
|
+
function requireApiKey() {
|
|
1176
|
+
const config = loadConfig();
|
|
1177
|
+
if (!config.api_key) {
|
|
1178
|
+
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
1179
|
+
process.exit(1);
|
|
1180
|
+
}
|
|
1181
|
+
return config.api_key;
|
|
1182
|
+
}
|
|
1183
|
+
function parseMessage(opts) {
|
|
1184
|
+
if (opts.message) {
|
|
1185
|
+
let parsed;
|
|
1186
|
+
try {
|
|
1187
|
+
parsed = JSON.parse(opts.message);
|
|
1188
|
+
} catch {
|
|
1189
|
+
console.error(`--message must be a JSON object, e.g. '{"text":"hello"}'.`);
|
|
1190
|
+
process.exit(1);
|
|
1191
|
+
}
|
|
1192
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1193
|
+
console.error(`--message must be a JSON object, e.g. '{"text":"hello"}'.`);
|
|
1194
|
+
process.exit(1);
|
|
1195
|
+
}
|
|
1196
|
+
return parsed;
|
|
1197
|
+
}
|
|
1198
|
+
if (opts.text !== void 0) {
|
|
1199
|
+
return { text: opts.text };
|
|
1200
|
+
}
|
|
1201
|
+
console.error("Provide --text or --message.");
|
|
1202
|
+
process.exit(1);
|
|
1203
|
+
}
|
|
1204
|
+
function invokeCommand() {
|
|
1205
|
+
return new import_commander8.Command("invoke").description(
|
|
1206
|
+
"Call another ACN agent through AgentRouter (hop:invoke receipt). Not chat, not Match, not `acn message send`."
|
|
1207
|
+
).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(
|
|
1208
|
+
async (opts) => {
|
|
1209
|
+
requireApiKey();
|
|
1210
|
+
const to = opts.to?.trim() || void 0;
|
|
1211
|
+
const slot = opts.slot?.trim() || void 0;
|
|
1212
|
+
if (!to && !slot) {
|
|
1213
|
+
console.error("Provide --to and/or --slot.");
|
|
1214
|
+
process.exit(1);
|
|
1215
|
+
}
|
|
1216
|
+
const message = parseMessage(opts);
|
|
1217
|
+
const body = { message };
|
|
1218
|
+
if (to) body.to = to;
|
|
1219
|
+
if (slot) body.slot = slot;
|
|
1220
|
+
if (opts.requestId?.trim()) body.request_id = opts.requestId.trim();
|
|
1221
|
+
try {
|
|
1222
|
+
const res = await acnPost("/invoke", body);
|
|
1223
|
+
const hop = res.hop_id ? ` hop=${res.hop_id}` : "";
|
|
1224
|
+
const status = res.status ? ` status=${res.status}` : "";
|
|
1225
|
+
const winner = res.to ? ` to=${res.to}` : "";
|
|
1226
|
+
const fallback = res.fallback_from ? ` fallback_from=${res.fallback_from}` : "";
|
|
1227
|
+
output(res, `Invoked${winner}${hop}${status}${fallback}`);
|
|
1228
|
+
} catch (err) {
|
|
1229
|
+
handleError(err);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// src/commands/notify.ts
|
|
1236
|
+
var import_commander9 = require("commander");
|
|
1170
1237
|
var NOTIFY_MESSAGE_TYPES2 = [
|
|
1171
1238
|
"task_request",
|
|
1172
1239
|
"collaboration",
|
|
@@ -1200,7 +1267,7 @@ function formatEntry(e, index) {
|
|
|
1200
1267
|
return lines.join("\n");
|
|
1201
1268
|
}
|
|
1202
1269
|
function notifyCommand() {
|
|
1203
|
-
const cmd = new
|
|
1270
|
+
const cmd = new import_commander9.Command("notify").description(
|
|
1204
1271
|
"Manage Notify-layer queue (manifest mode). For offline direct messages: acn inbox"
|
|
1205
1272
|
);
|
|
1206
1273
|
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 +1379,7 @@ ${chunks.join("")}${truncatedHint}`);
|
|
|
1312
1379
|
}
|
|
1313
1380
|
|
|
1314
1381
|
// src/commands/inbox.ts
|
|
1315
|
-
var
|
|
1382
|
+
var import_commander10 = require("commander");
|
|
1316
1383
|
var POLICY_MODES = ["open", "manifest", "allowlist", "closed"];
|
|
1317
1384
|
var MODE_DESC = {
|
|
1318
1385
|
open: "open \u2014 anyone can push messages directly to your inbox",
|
|
@@ -1356,7 +1423,7 @@ function formatAllowlistEntry(e, index) {
|
|
|
1356
1423
|
Added : ${e.created_at}${reason}`;
|
|
1357
1424
|
}
|
|
1358
1425
|
function inboxCommand() {
|
|
1359
|
-
const cmd = new
|
|
1426
|
+
const cmd = new import_commander10.Command("inbox").description(
|
|
1360
1427
|
"Offline direct-delivery inbox + reception policy. For Notify-layer pull: acn notify"
|
|
1361
1428
|
);
|
|
1362
1429
|
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 +1465,7 @@ function inboxCommand() {
|
|
|
1398
1465
|
handleError(err);
|
|
1399
1466
|
}
|
|
1400
1467
|
});
|
|
1401
|
-
const mode = new
|
|
1468
|
+
const mode = new import_commander10.Command("mode").description(
|
|
1402
1469
|
"Reception policy: who can send to your inbox and how"
|
|
1403
1470
|
);
|
|
1404
1471
|
mode.command("get").description("Show current reception policy").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
@@ -1433,7 +1500,7 @@ ${formatPolicy(res)}`);
|
|
|
1433
1500
|
}
|
|
1434
1501
|
);
|
|
1435
1502
|
cmd.addCommand(mode);
|
|
1436
|
-
const allowlist = new
|
|
1503
|
+
const allowlist = new import_commander10.Command("allowlist").description(
|
|
1437
1504
|
"Trusted senders (effective when mode=allowlist)"
|
|
1438
1505
|
);
|
|
1439
1506
|
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 +1559,7 @@ ${formatPolicy(res)}`);
|
|
|
1492
1559
|
}
|
|
1493
1560
|
|
|
1494
1561
|
// src/commands/listen.ts
|
|
1495
|
-
var
|
|
1562
|
+
var import_commander11 = require("commander");
|
|
1496
1563
|
var import_child_process3 = require("child_process");
|
|
1497
1564
|
var import_ws = __toESM(require("ws"));
|
|
1498
1565
|
|
|
@@ -1507,6 +1574,33 @@ function asRecord(v) {
|
|
|
1507
1574
|
function asNonEmptyString(v) {
|
|
1508
1575
|
return typeof v === "string" && v.length > 0 ? v : null;
|
|
1509
1576
|
}
|
|
1577
|
+
function asInferencePath(v) {
|
|
1578
|
+
return v === "official" || v === "byo" ? v : null;
|
|
1579
|
+
}
|
|
1580
|
+
var HOST_INFERENCE_HOSTS = /* @__PURE__ */ new Set([
|
|
1581
|
+
"api.agentplanet.org",
|
|
1582
|
+
"api.agenticplanet.space"
|
|
1583
|
+
]);
|
|
1584
|
+
function asHostInferenceUrl(v) {
|
|
1585
|
+
const raw = asNonEmptyString(v);
|
|
1586
|
+
if (!raw) return null;
|
|
1587
|
+
try {
|
|
1588
|
+
const u = new URL(raw);
|
|
1589
|
+
if (u.pathname.replace(/\/+$/, "") !== "/api/inference/v1") return null;
|
|
1590
|
+
if (u.search || u.hash) return null;
|
|
1591
|
+
const host = u.hostname.toLowerCase();
|
|
1592
|
+
const loopback = host === "localhost" || host === "127.0.0.1" || host === "::1";
|
|
1593
|
+
if (u.protocol === "https:" && HOST_INFERENCE_HOSTS.has(host)) {
|
|
1594
|
+
return `${u.origin}/api/inference/v1`;
|
|
1595
|
+
}
|
|
1596
|
+
if (u.protocol === "http:" && loopback) {
|
|
1597
|
+
return `${u.origin}/api/inference/v1`;
|
|
1598
|
+
}
|
|
1599
|
+
return null;
|
|
1600
|
+
} catch {
|
|
1601
|
+
return null;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1510
1604
|
function parseJsonRpcBody(bodyText) {
|
|
1511
1605
|
let parsed;
|
|
1512
1606
|
try {
|
|
@@ -1598,7 +1692,10 @@ function extractChatEnvelope(message) {
|
|
|
1598
1692
|
gateway_message_id: asNonEmptyString(ap.message_id) ?? asNonEmptyString(ap.messageId),
|
|
1599
1693
|
user_text: extractUserText(message),
|
|
1600
1694
|
requested_model: requested ? requested.slice(0, 200) : null,
|
|
1601
|
-
max_output_tokens: maxOut
|
|
1695
|
+
max_output_tokens: maxOut,
|
|
1696
|
+
hop_id: asNonEmptyString(ap.hop_id),
|
|
1697
|
+
inference_path: asInferencePath(ap.inference_path),
|
|
1698
|
+
host_inference_url: asHostInferenceUrl(ap.host_inference_url)
|
|
1602
1699
|
};
|
|
1603
1700
|
}
|
|
1604
1701
|
function normalizeEvent(body, opts = {}) {
|
|
@@ -1657,6 +1754,115 @@ var DedupeStore = class {
|
|
|
1657
1754
|
}
|
|
1658
1755
|
};
|
|
1659
1756
|
|
|
1757
|
+
// src/commands/official-hop-door.ts
|
|
1758
|
+
var import_node_http = __toESM(require("http"));
|
|
1759
|
+
function shouldOpenOfficialDoor(opts) {
|
|
1760
|
+
return Boolean(
|
|
1761
|
+
opts.inferencePath === "official" && opts.hopId?.trim() && asHostInferenceUrl(opts.hostInferenceUrl) && opts.jwt?.trim()
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
function readBody(req) {
|
|
1765
|
+
return new Promise((resolve, reject) => {
|
|
1766
|
+
const chunks = [];
|
|
1767
|
+
req.on("data", (c) => chunks.push(Buffer.from(c)));
|
|
1768
|
+
req.on("end", () => resolve(Buffer.concat(chunks)));
|
|
1769
|
+
req.on("error", reject);
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
function send(res, status, body, contentType = "application/json") {
|
|
1773
|
+
res.writeHead(status, {
|
|
1774
|
+
"content-type": contentType,
|
|
1775
|
+
"content-length": String(body.length)
|
|
1776
|
+
});
|
|
1777
|
+
res.end(body);
|
|
1778
|
+
}
|
|
1779
|
+
async function handleDoorRequest(req, res, opts) {
|
|
1780
|
+
const path = (req.url ?? "").split("?")[0];
|
|
1781
|
+
if (req.method !== "POST" || path !== "/v1/chat/completions" && path !== "/chat/completions") {
|
|
1782
|
+
send(res, 404, Buffer.from('{"error":"not_found"}'));
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
let payload;
|
|
1786
|
+
try {
|
|
1787
|
+
const raw = await readBody(req);
|
|
1788
|
+
payload = JSON.parse(raw.length ? raw.toString("utf-8") : "{}");
|
|
1789
|
+
} catch {
|
|
1790
|
+
send(res, 400, Buffer.from('{"error":"invalid_json"}'));
|
|
1791
|
+
return;
|
|
1792
|
+
}
|
|
1793
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
1794
|
+
send(res, 400, Buffer.from('{"error":"invalid_json"}'));
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
const body = { ...payload };
|
|
1798
|
+
delete body.agent_id;
|
|
1799
|
+
body.hop_id = opts.hopId;
|
|
1800
|
+
const headers = {
|
|
1801
|
+
authorization: `Bearer ${opts.jwt}`,
|
|
1802
|
+
"content-type": "application/json",
|
|
1803
|
+
"X-Hop-Id": opts.hopId
|
|
1804
|
+
};
|
|
1805
|
+
if (opts.agentId) headers["X-Agent-Id"] = opts.agentId;
|
|
1806
|
+
try {
|
|
1807
|
+
const upstream = await opts.fetchFn(opts.upstream, {
|
|
1808
|
+
method: "POST",
|
|
1809
|
+
headers,
|
|
1810
|
+
body: JSON.stringify(body)
|
|
1811
|
+
});
|
|
1812
|
+
const out = Buffer.from(await upstream.arrayBuffer());
|
|
1813
|
+
const ct = upstream.headers.get("content-type") || "application/json";
|
|
1814
|
+
send(res, upstream.status, out, ct);
|
|
1815
|
+
} catch (err) {
|
|
1816
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1817
|
+
send(
|
|
1818
|
+
res,
|
|
1819
|
+
502,
|
|
1820
|
+
Buffer.from(JSON.stringify({ error: `upstream_unreachable:${msg.slice(0, 120)}` }))
|
|
1821
|
+
);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
function closeServer(server) {
|
|
1825
|
+
return new Promise((resolve) => {
|
|
1826
|
+
server.closeAllConnections?.();
|
|
1827
|
+
server.close(() => resolve());
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
async function startOfficialHopDoor(opts) {
|
|
1831
|
+
const dest = asHostInferenceUrl(opts.hostInferenceUrl);
|
|
1832
|
+
const hopId = opts.hopId.trim();
|
|
1833
|
+
const jwt = opts.jwt.trim();
|
|
1834
|
+
if (!dest || !hopId || !jwt) return null;
|
|
1835
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
1836
|
+
const upstream = `${dest}/chat/completions`;
|
|
1837
|
+
const server = import_node_http.default.createServer((req, res) => {
|
|
1838
|
+
void handleDoorRequest(req, res, {
|
|
1839
|
+
upstream,
|
|
1840
|
+
hopId,
|
|
1841
|
+
agentId: opts.agentId,
|
|
1842
|
+
jwt,
|
|
1843
|
+
fetchFn
|
|
1844
|
+
});
|
|
1845
|
+
});
|
|
1846
|
+
try {
|
|
1847
|
+
await new Promise((resolve, reject) => {
|
|
1848
|
+
server.once("error", reject);
|
|
1849
|
+
server.listen(0, "127.0.0.1", () => resolve());
|
|
1850
|
+
});
|
|
1851
|
+
} catch {
|
|
1852
|
+
return null;
|
|
1853
|
+
}
|
|
1854
|
+
const addr = server.address();
|
|
1855
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
1856
|
+
if (!port) {
|
|
1857
|
+
await closeServer(server);
|
|
1858
|
+
return null;
|
|
1859
|
+
}
|
|
1860
|
+
return {
|
|
1861
|
+
baseUrl: `http://127.0.0.1:${port}/v1`,
|
|
1862
|
+
close: () => closeServer(server)
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1660
1866
|
// src/commands/chat-writeback.ts
|
|
1661
1867
|
var DEFAULT_COMPLETE_TIMEOUT_MS = 12e4;
|
|
1662
1868
|
var DEFAULT_WRITEBACK_TIMEOUT_MS = 3e4;
|
|
@@ -1823,6 +2029,34 @@ async function mintAgentJwt(opts, fetchFn = fetch) {
|
|
|
1823
2029
|
function clearAgentJwtCache() {
|
|
1824
2030
|
cachedJwt = null;
|
|
1825
2031
|
}
|
|
2032
|
+
function completeInferenceEnv(event, opts, jwt, door) {
|
|
2033
|
+
const extra = { ACN_AGENT_ID: opts.agentId };
|
|
2034
|
+
const chat = event.chat;
|
|
2035
|
+
if (chat?.hop_id) extra.ACN_CHAT_HOP_ID = chat.hop_id;
|
|
2036
|
+
if (chat?.inference_path) extra.ACN_INFERENCE_PATH = chat.inference_path;
|
|
2037
|
+
if (chat?.host_inference_url) {
|
|
2038
|
+
extra.ACN_HOST_INFERENCE_URL = chat.host_inference_url;
|
|
2039
|
+
}
|
|
2040
|
+
if (jwt) extra.ACN_AGENT_JWT = jwt;
|
|
2041
|
+
if (door?.baseUrl && jwt) {
|
|
2042
|
+
extra.OPENAI_BASE_URL = door.baseUrl;
|
|
2043
|
+
extra.OPENAI_API_KEY = jwt;
|
|
2044
|
+
}
|
|
2045
|
+
return { ...process.env, ...extra };
|
|
2046
|
+
}
|
|
2047
|
+
function completeInferenceHeaders(event, opts) {
|
|
2048
|
+
const headers = {
|
|
2049
|
+
"content-type": "application/json"
|
|
2050
|
+
};
|
|
2051
|
+
if (opts.agentId) headers["X-ACN-Agent-Id"] = opts.agentId;
|
|
2052
|
+
const chat = event.chat;
|
|
2053
|
+
if (chat?.hop_id) headers["X-ACN-Hop-Id"] = chat.hop_id;
|
|
2054
|
+
if (chat?.inference_path) headers["X-ACN-Inference-Path"] = chat.inference_path;
|
|
2055
|
+
if (chat?.host_inference_url) {
|
|
2056
|
+
headers["X-ACN-Host-Inference-Url"] = chat.host_inference_url;
|
|
2057
|
+
}
|
|
2058
|
+
return headers;
|
|
2059
|
+
}
|
|
1826
2060
|
async function completeViaHttp(event, opts, deps) {
|
|
1827
2061
|
const fetchFn = deps.fetchFn ?? fetch;
|
|
1828
2062
|
const timeoutMs = opts.completeTimeoutMs ?? DEFAULT_COMPLETE_TIMEOUT_MS;
|
|
@@ -1831,7 +2065,7 @@ async function completeViaHttp(event, opts, deps) {
|
|
|
1831
2065
|
try {
|
|
1832
2066
|
const res = await fetchFn(opts.completeUrl, {
|
|
1833
2067
|
method: "POST",
|
|
1834
|
-
headers:
|
|
2068
|
+
headers: completeInferenceHeaders(event, opts),
|
|
1835
2069
|
body: JSON.stringify(event),
|
|
1836
2070
|
signal: controller.signal
|
|
1837
2071
|
});
|
|
@@ -1856,13 +2090,16 @@ async function completeViaHttp(event, opts, deps) {
|
|
|
1856
2090
|
clearTimeout(timer);
|
|
1857
2091
|
}
|
|
1858
2092
|
}
|
|
1859
|
-
function
|
|
2093
|
+
function spawnCompleteExec(event, opts, deps, jwt, door) {
|
|
1860
2094
|
const spawnFn = deps.spawnFn ?? import_child_process.spawn;
|
|
1861
2095
|
const timeoutMs = opts.completeTimeoutMs ?? DEFAULT_COMPLETE_TIMEOUT_MS;
|
|
1862
2096
|
const body = Buffer.from(JSON.stringify(event), "utf-8");
|
|
1863
2097
|
return new Promise((resolve) => {
|
|
1864
2098
|
let settled = false;
|
|
1865
|
-
const child = spawnFn(opts.completeExec, {
|
|
2099
|
+
const child = spawnFn(opts.completeExec, {
|
|
2100
|
+
shell: true,
|
|
2101
|
+
env: completeInferenceEnv(event, opts, jwt, door)
|
|
2102
|
+
});
|
|
1866
2103
|
const stdout = [];
|
|
1867
2104
|
const stderr = [];
|
|
1868
2105
|
const finish = (result) => {
|
|
@@ -1901,6 +2138,44 @@ function completeViaExec(event, opts, deps) {
|
|
|
1901
2138
|
child.stdin?.end(body);
|
|
1902
2139
|
});
|
|
1903
2140
|
}
|
|
2141
|
+
async function completeViaExec(event, opts, deps, jwt) {
|
|
2142
|
+
let door = null;
|
|
2143
|
+
const logFn = deps.logFn ?? ((line) => console.error(line));
|
|
2144
|
+
try {
|
|
2145
|
+
if (shouldOpenOfficialDoor({
|
|
2146
|
+
inferencePath: event.chat?.inference_path,
|
|
2147
|
+
hopId: event.chat?.hop_id,
|
|
2148
|
+
hostInferenceUrl: event.chat?.host_inference_url,
|
|
2149
|
+
jwt
|
|
2150
|
+
})) {
|
|
2151
|
+
try {
|
|
2152
|
+
door = await startOfficialHopDoor({
|
|
2153
|
+
hostInferenceUrl: event.chat.host_inference_url,
|
|
2154
|
+
hopId: event.chat.hop_id,
|
|
2155
|
+
agentId: opts.agentId,
|
|
2156
|
+
jwt,
|
|
2157
|
+
fetchFn: deps.fetchFn
|
|
2158
|
+
});
|
|
2159
|
+
} catch {
|
|
2160
|
+
door = null;
|
|
2161
|
+
}
|
|
2162
|
+
if (door) {
|
|
2163
|
+
logFn(
|
|
2164
|
+
`[acn listen] official_door chat_id=${event.chat.chat_id} base=${door.baseUrl}`
|
|
2165
|
+
);
|
|
2166
|
+
} else {
|
|
2167
|
+
logFn(
|
|
2168
|
+
`[acn listen] official_door_skipped chat_id=${event.chat.chat_id}`
|
|
2169
|
+
);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
return await spawnCompleteExec(event, opts, deps, jwt, door);
|
|
2173
|
+
} finally {
|
|
2174
|
+
if (door) {
|
|
2175
|
+
await door.close().catch(() => void 0);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
1904
2179
|
async function postWriteback(event, complete, opts, deps) {
|
|
1905
2180
|
const chat = event.chat;
|
|
1906
2181
|
if (!chat) return { ok: false, reason: "no_chat_envelope" };
|
|
@@ -2019,7 +2294,12 @@ async function postWriteback(event, complete, opts, deps) {
|
|
|
2019
2294
|
async function handleChatWriteback(event, opts, deps = {}) {
|
|
2020
2295
|
const logFn = deps.logFn ?? ((line) => console.error(line));
|
|
2021
2296
|
if (!event.chat) return { ok: false, reason: "no_chat_envelope" };
|
|
2022
|
-
|
|
2297
|
+
let jwt = null;
|
|
2298
|
+
if (event.chat.inference_path === "official" && opts.completeExec) {
|
|
2299
|
+
const minted = await mintAgentJwt(opts, deps.fetchFn ?? fetch);
|
|
2300
|
+
if (minted.ok) jwt = minted.token;
|
|
2301
|
+
}
|
|
2302
|
+
const completed = opts.completeUrl ? await completeViaHttp(event, opts, deps) : await completeViaExec(event, opts, deps, jwt);
|
|
2023
2303
|
if (!completed.ok) {
|
|
2024
2304
|
logFn(
|
|
2025
2305
|
`[acn listen] chat_complete_failed chat_id=${event.chat.chat_id} message_id=${event.message_id} reason=${completed.reason}`
|
|
@@ -2244,7 +2524,7 @@ function formatWakeFailed(event, reason) {
|
|
|
2244
2524
|
function formatDeduped(event) {
|
|
2245
2525
|
return `[acn listen] deduped key=${dedupeKey(event)}`;
|
|
2246
2526
|
}
|
|
2247
|
-
function dispatchLocalReceiver(correlationId, bodyText, opts, dedupeStore,
|
|
2527
|
+
function dispatchLocalReceiver(correlationId, bodyText, opts, dedupeStore, send2, deps = {}) {
|
|
2248
2528
|
const logFn = deps.logFn ?? ((line) => console.error(line));
|
|
2249
2529
|
const result = processIncomingRequest(
|
|
2250
2530
|
correlationId,
|
|
@@ -2253,7 +2533,7 @@ function dispatchLocalReceiver(correlationId, bodyText, opts, dedupeStore, send,
|
|
|
2253
2533
|
dedupeStore,
|
|
2254
2534
|
deps
|
|
2255
2535
|
);
|
|
2256
|
-
|
|
2536
|
+
send2(result.response);
|
|
2257
2537
|
if (result.dedupeHit && result.event) {
|
|
2258
2538
|
logFn(formatDeduped(result.event));
|
|
2259
2539
|
return;
|
|
@@ -2314,7 +2594,7 @@ function errorResponse(id, status, detail) {
|
|
|
2314
2594
|
body: JSON.stringify({ error: detail })
|
|
2315
2595
|
};
|
|
2316
2596
|
}
|
|
2317
|
-
async function dispatchA2aRequest(frame, opts,
|
|
2597
|
+
async function dispatchA2aRequest(frame, opts, send2, deps = {}) {
|
|
2318
2598
|
const bodyBuf = decodeBody(frame);
|
|
2319
2599
|
try {
|
|
2320
2600
|
if (opts.runtime) {
|
|
@@ -2324,7 +2604,7 @@ async function dispatchA2aRequest(frame, opts, send, deps = {}) {
|
|
|
2324
2604
|
bodyBuf.toString("utf-8"),
|
|
2325
2605
|
opts.runtime,
|
|
2326
2606
|
store,
|
|
2327
|
-
|
|
2607
|
+
send2,
|
|
2328
2608
|
{
|
|
2329
2609
|
fetchFn: deps.fetchFn,
|
|
2330
2610
|
spawnFn: deps.spawnFn,
|
|
@@ -2334,17 +2614,17 @@ async function dispatchA2aRequest(frame, opts, send, deps = {}) {
|
|
|
2334
2614
|
return;
|
|
2335
2615
|
}
|
|
2336
2616
|
if (opts.forward) {
|
|
2337
|
-
await forwardToHttp(frame, bodyBuf, opts.forward, deps.fetchFn ?? fetch,
|
|
2617
|
+
await forwardToHttp(frame, bodyBuf, opts.forward, deps.fetchFn ?? fetch, send2);
|
|
2338
2618
|
return;
|
|
2339
2619
|
}
|
|
2340
2620
|
if (opts.exec) {
|
|
2341
|
-
|
|
2621
|
+
send2(await runExec(frame, bodyBuf, opts.exec, deps.spawnFn ?? import_child_process3.spawn));
|
|
2342
2622
|
return;
|
|
2343
2623
|
}
|
|
2344
|
-
|
|
2624
|
+
send2(errorResponse(frame.id, 500, "no handler configured"));
|
|
2345
2625
|
} catch (err) {
|
|
2346
2626
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2347
|
-
|
|
2627
|
+
send2(errorResponse(frame.id, 502, `handler failed: ${msg}`));
|
|
2348
2628
|
}
|
|
2349
2629
|
}
|
|
2350
2630
|
function buildForwardHeaders(frame) {
|
|
@@ -2354,7 +2634,7 @@ function buildForwardHeaders(frame) {
|
|
|
2354
2634
|
}
|
|
2355
2635
|
return headers;
|
|
2356
2636
|
}
|
|
2357
|
-
async function forwardToHttp(frame, bodyBuf, base, fetchFn,
|
|
2637
|
+
async function forwardToHttp(frame, bodyBuf, base, fetchFn, send2) {
|
|
2358
2638
|
const suffix = frame.path && frame.path !== "/" ? "/" + frame.path.replace(/^\//, "") : "";
|
|
2359
2639
|
const targetUrl = base.replace(/\/$/, "") + suffix;
|
|
2360
2640
|
const method = (frame.method ?? "POST").toUpperCase();
|
|
@@ -2372,7 +2652,7 @@ async function forwardToHttp(frame, bodyBuf, base, fetchFn, send) {
|
|
|
2372
2652
|
const { done, value } = await reader.read();
|
|
2373
2653
|
if (done) break;
|
|
2374
2654
|
if (value && value.length > 0) {
|
|
2375
|
-
|
|
2655
|
+
send2({
|
|
2376
2656
|
type: "a2a_stream_chunk",
|
|
2377
2657
|
id: frame.id,
|
|
2378
2658
|
seq: seq++,
|
|
@@ -2381,17 +2661,17 @@ async function forwardToHttp(frame, bodyBuf, base, fetchFn, send) {
|
|
|
2381
2661
|
});
|
|
2382
2662
|
}
|
|
2383
2663
|
}
|
|
2384
|
-
|
|
2664
|
+
send2({ type: "a2a_stream_end", id: frame.id, status: res.status });
|
|
2385
2665
|
} catch (err) {
|
|
2386
2666
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2387
|
-
|
|
2667
|
+
send2({ type: "a2a_stream_end", id: frame.id, error: msg });
|
|
2388
2668
|
} finally {
|
|
2389
2669
|
reader.releaseLock();
|
|
2390
2670
|
}
|
|
2391
2671
|
return;
|
|
2392
2672
|
}
|
|
2393
2673
|
const respText = await res.text();
|
|
2394
|
-
|
|
2674
|
+
send2({
|
|
2395
2675
|
type: "a2a_response",
|
|
2396
2676
|
id: frame.id,
|
|
2397
2677
|
status: res.status,
|
|
@@ -2502,12 +2782,12 @@ function runListener(cfg) {
|
|
|
2502
2782
|
if (!frame || typeof frame !== "object") return;
|
|
2503
2783
|
const f = frame;
|
|
2504
2784
|
if (f.type === "a2a_request" && typeof f.id === "string") {
|
|
2505
|
-
const
|
|
2785
|
+
const send2 = (out) => {
|
|
2506
2786
|
if (ws.readyState === import_ws.default.OPEN) {
|
|
2507
2787
|
ws.send(JSON.stringify(out));
|
|
2508
2788
|
}
|
|
2509
2789
|
};
|
|
2510
|
-
void dispatchA2aRequest(f, cfg,
|
|
2790
|
+
void dispatchA2aRequest(f, cfg, send2, { dedupeStore });
|
|
2511
2791
|
}
|
|
2512
2792
|
});
|
|
2513
2793
|
ws.on("close", (code, reason) => {
|
|
@@ -2556,7 +2836,7 @@ function validateListenHandlerFlags(opts) {
|
|
|
2556
2836
|
});
|
|
2557
2837
|
}
|
|
2558
2838
|
function listenCommand() {
|
|
2559
|
-
const cmd = new
|
|
2839
|
+
const cmd = new import_commander11.Command("listen").description(
|
|
2560
2840
|
"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
2841
|
).option(
|
|
2562
2842
|
"--runtime <id>",
|
|
@@ -2734,7 +3014,7 @@ function listenCommand() {
|
|
|
2734
3014
|
}
|
|
2735
3015
|
|
|
2736
3016
|
// src/commands/delivery.ts
|
|
2737
|
-
var
|
|
3017
|
+
var import_commander12 = require("commander");
|
|
2738
3018
|
var DELIVERY_DESC = {
|
|
2739
3019
|
direct: "direct (Mode A) \u2014 ACN dials your public A2A endpoint over HTTP",
|
|
2740
3020
|
relay: "relay (Mode B) \u2014 hold an outbound WebSocket with `acn listen`; no public URL",
|
|
@@ -2773,7 +3053,7 @@ function formatDelivery(d) {
|
|
|
2773
3053
|
return lines.join("\n");
|
|
2774
3054
|
}
|
|
2775
3055
|
function deliveryCommand() {
|
|
2776
|
-
const cmd = new
|
|
3056
|
+
const cmd = new import_commander12.Command("delivery").description(
|
|
2777
3057
|
"Inbound delivery transport (Mode A direct / Mode B relay). Orthogonal to reception policy (`acn inbox mode`)."
|
|
2778
3058
|
);
|
|
2779
3059
|
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 +3114,7 @@ function deliveryCommand() {
|
|
|
2834
3114
|
}
|
|
2835
3115
|
|
|
2836
3116
|
// src/commands/session.ts
|
|
2837
|
-
var
|
|
3117
|
+
var import_commander13 = require("commander");
|
|
2838
3118
|
function requireAgentId4() {
|
|
2839
3119
|
const config = loadConfig();
|
|
2840
3120
|
if (!config.api_key) {
|
|
@@ -2879,7 +3159,7 @@ function formatEntry2(s, index) {
|
|
|
2879
3159
|
return lines.join("\n");
|
|
2880
3160
|
}
|
|
2881
3161
|
function sessionCommand() {
|
|
2882
|
-
const cmd = new
|
|
3162
|
+
const cmd = new import_commander13.Command("session").description(
|
|
2883
3163
|
"Real-time session layer: bidirectional channel between two agents"
|
|
2884
3164
|
);
|
|
2885
3165
|
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 +3237,7 @@ ${formatEntry2(res)}`);
|
|
|
2957
3237
|
}
|
|
2958
3238
|
|
|
2959
3239
|
// src/commands/subnet.ts
|
|
2960
|
-
var
|
|
3240
|
+
var import_commander14 = require("commander");
|
|
2961
3241
|
function requireAgentId5() {
|
|
2962
3242
|
const config = loadConfig();
|
|
2963
3243
|
if (!config.api_key) {
|
|
@@ -2970,7 +3250,7 @@ function requireAgentId5() {
|
|
|
2970
3250
|
}
|
|
2971
3251
|
return config.agent_id;
|
|
2972
3252
|
}
|
|
2973
|
-
function
|
|
3253
|
+
function requireApiKey2() {
|
|
2974
3254
|
const config = loadConfig();
|
|
2975
3255
|
if (!config.api_key) {
|
|
2976
3256
|
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
@@ -3045,7 +3325,7 @@ function formatSubnet(s, index) {
|
|
|
3045
3325
|
return lines.join("\n");
|
|
3046
3326
|
}
|
|
3047
3327
|
function subnetCommand() {
|
|
3048
|
-
const cmd = new
|
|
3328
|
+
const cmd = new import_commander14.Command("subnet").description("Manage ACN subnets");
|
|
3049
3329
|
cmd.command("list").description(
|
|
3050
3330
|
"List subnets. Without --all/--parent shows only subnets you have joined."
|
|
3051
3331
|
).option("--all", "Show all public subnets on ACN (not just your own)").option(
|
|
@@ -3262,7 +3542,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3262
3542
|
handleError(err);
|
|
3263
3543
|
}
|
|
3264
3544
|
});
|
|
3265
|
-
const requests = new
|
|
3545
|
+
const requests = new import_commander14.Command("requests").description(
|
|
3266
3546
|
"Manage join-requests for a subnet (ADR-0004)"
|
|
3267
3547
|
);
|
|
3268
3548
|
requests.command("list <subnet_id>").description(
|
|
@@ -3276,7 +3556,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3276
3556
|
"join_request"
|
|
3277
3557
|
).option("--limit <n>", "Page size (1-500, default 100)", "100").option("--offset <n>", "Page offset (default 0)", "0").action(
|
|
3278
3558
|
async (subnetId, opts) => {
|
|
3279
|
-
|
|
3559
|
+
requireApiKey2();
|
|
3280
3560
|
const params = {};
|
|
3281
3561
|
if (opts.status) params.status = opts.status;
|
|
3282
3562
|
if (opts.kind) params.kind = opts.kind;
|
|
@@ -3342,7 +3622,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3342
3622
|
});
|
|
3343
3623
|
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
3624
|
async (subnetId, opts) => {
|
|
3345
|
-
|
|
3625
|
+
requireApiKey2();
|
|
3346
3626
|
const body = {};
|
|
3347
3627
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3348
3628
|
try {
|
|
@@ -3361,7 +3641,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3361
3641
|
);
|
|
3362
3642
|
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
3643
|
async (subnetId, opts) => {
|
|
3364
|
-
|
|
3644
|
+
requireApiKey2();
|
|
3365
3645
|
const body = {};
|
|
3366
3646
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3367
3647
|
try {
|
|
@@ -3382,7 +3662,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3382
3662
|
"Applicant-only: withdraw your own pending join_request (CAS pending \u2192 withdrawn)."
|
|
3383
3663
|
).requiredOption("--request-id <rid>", "Your join request ID").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3384
3664
|
async (subnetId, opts) => {
|
|
3385
|
-
|
|
3665
|
+
requireApiKey2();
|
|
3386
3666
|
const body = {};
|
|
3387
3667
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3388
3668
|
try {
|
|
@@ -3404,14 +3684,14 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3404
3684
|
}
|
|
3405
3685
|
);
|
|
3406
3686
|
cmd.addCommand(requests);
|
|
3407
|
-
const invitations = new
|
|
3687
|
+
const invitations = new import_commander14.Command("invitations").description(
|
|
3408
3688
|
"Manage invitations on a subnet (ADR-0004)"
|
|
3409
3689
|
);
|
|
3410
3690
|
invitations.command("send <subnet_id>").description(
|
|
3411
3691
|
"Owner-only: invite an agent to a subnet. Auto-merges with a target's pending join_request (collapses to auto-approval)."
|
|
3412
3692
|
).requiredOption("--agent-id <aid>", "Agent ID to invite").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3413
3693
|
async (subnetId, opts) => {
|
|
3414
|
-
|
|
3694
|
+
requireApiKey2();
|
|
3415
3695
|
const body = { agent_id: opts.agentId };
|
|
3416
3696
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3417
3697
|
try {
|
|
@@ -3430,7 +3710,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3430
3710
|
"Filter by status: pending | approved | rejected | withdrawn"
|
|
3431
3711
|
).option("--limit <n>", "Page size (1-500, default 100)", "100").option("--offset <n>", "Page offset (default 0)", "0").action(
|
|
3432
3712
|
async (subnetId, opts) => {
|
|
3433
|
-
|
|
3713
|
+
requireApiKey2();
|
|
3434
3714
|
const params = {};
|
|
3435
3715
|
if (opts.status) params.status = opts.status;
|
|
3436
3716
|
if (opts.limit) params.limit = opts.limit;
|
|
@@ -3483,7 +3763,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3483
3763
|
"Invitee-only: accept a pending invitation (CAS pending \u2192 approved). Side effect: you join the subnet."
|
|
3484
3764
|
).requiredOption("--invitation-id <iid>", "Invitation ID to accept").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3485
3765
|
async (subnetId, opts) => {
|
|
3486
|
-
|
|
3766
|
+
requireApiKey2();
|
|
3487
3767
|
const body = {};
|
|
3488
3768
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3489
3769
|
try {
|
|
@@ -3504,7 +3784,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3504
3784
|
"Invitee-only: reject a pending invitation (CAS pending \u2192 rejected). No membership change."
|
|
3505
3785
|
).requiredOption("--invitation-id <iid>", "Invitation ID to reject").option("--note <text>", "Optional audit note (\u2264500 chars)").action(
|
|
3506
3786
|
async (subnetId, opts) => {
|
|
3507
|
-
|
|
3787
|
+
requireApiKey2();
|
|
3508
3788
|
const body = {};
|
|
3509
3789
|
if (opts.note !== void 0) body.note = opts.note;
|
|
3510
3790
|
try {
|
|
@@ -3525,7 +3805,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3525
3805
|
"Owner-only: cancel a pending invitation (CAS pending \u2192 withdrawn)."
|
|
3526
3806
|
).requiredOption("--invitation-id <iid>", "Invitation ID to cancel").action(
|
|
3527
3807
|
async (subnetId, opts) => {
|
|
3528
|
-
|
|
3808
|
+
requireApiKey2();
|
|
3529
3809
|
try {
|
|
3530
3810
|
const res = await acnDelete(
|
|
3531
3811
|
`/subnets/${subnetId}/invitations/${opts.invitationId}`
|
|
@@ -3540,12 +3820,12 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3540
3820
|
}
|
|
3541
3821
|
);
|
|
3542
3822
|
cmd.addCommand(invitations);
|
|
3543
|
-
const allowlist = new
|
|
3823
|
+
const allowlist = new import_commander14.Command("allowlist").description(
|
|
3544
3824
|
"Manage a subnet allowlist (ADR-0004)"
|
|
3545
3825
|
);
|
|
3546
3826
|
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
3827
|
async (subnetId, opts) => {
|
|
3548
|
-
|
|
3828
|
+
requireApiKey2();
|
|
3549
3829
|
const params = {};
|
|
3550
3830
|
if (opts.limit) params.limit = opts.limit;
|
|
3551
3831
|
if (opts.offset) params.offset = opts.offset;
|
|
@@ -3574,7 +3854,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3574
3854
|
"Owner-only: pre-authorise an agent on the subnet allowlist. 409 ALREADY_ON_ALLOWLIST on duplicate."
|
|
3575
3855
|
).requiredOption("--agent-id <aid>", "Agent ID to add").action(
|
|
3576
3856
|
async (subnetId, opts) => {
|
|
3577
|
-
|
|
3857
|
+
requireApiKey2();
|
|
3578
3858
|
try {
|
|
3579
3859
|
const res = await acnPost(
|
|
3580
3860
|
`/subnets/${subnetId}/allowlist`,
|
|
@@ -3593,7 +3873,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3593
3873
|
"Owner-only: remove an agent from the subnet allowlist. Idempotent (204 even if missing)."
|
|
3594
3874
|
).requiredOption("--agent-id <aid>", "Agent ID to remove").action(
|
|
3595
3875
|
async (subnetId, opts) => {
|
|
3596
|
-
|
|
3876
|
+
requireApiKey2();
|
|
3597
3877
|
try {
|
|
3598
3878
|
await acnDelete(
|
|
3599
3879
|
`/subnets/${subnetId}/allowlist/${opts.agentId}`
|
|
@@ -3608,7 +3888,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3608
3888
|
}
|
|
3609
3889
|
);
|
|
3610
3890
|
cmd.addCommand(allowlist);
|
|
3611
|
-
const harness = new
|
|
3891
|
+
const harness = new import_commander14.Command("harness").description("Manage Org Harness webhook for a subnet");
|
|
3612
3892
|
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
3893
|
const config = loadConfig();
|
|
3614
3894
|
if (!config.api_key) {
|
|
@@ -3651,7 +3931,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
3651
3931
|
}
|
|
3652
3932
|
|
|
3653
3933
|
// src/commands/org.ts
|
|
3654
|
-
var
|
|
3934
|
+
var import_commander15 = require("commander");
|
|
3655
3935
|
function formatOrg(o) {
|
|
3656
3936
|
const lines = [
|
|
3657
3937
|
` ID : ${o.org_id}`,
|
|
@@ -3668,7 +3948,7 @@ function formatOrg(o) {
|
|
|
3668
3948
|
return lines.join("\n");
|
|
3669
3949
|
}
|
|
3670
3950
|
function orgCommand() {
|
|
3671
|
-
const cmd = new
|
|
3951
|
+
const cmd = new import_commander15.Command("org").description("Manage ACN organisations (Org Harness)");
|
|
3672
3952
|
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
3953
|
async (opts) => {
|
|
3674
3954
|
try {
|
|
@@ -3936,7 +4216,7 @@ function orgCommand() {
|
|
|
3936
4216
|
}
|
|
3937
4217
|
|
|
3938
4218
|
// src/commands/follow.ts
|
|
3939
|
-
var
|
|
4219
|
+
var import_commander16 = require("commander");
|
|
3940
4220
|
function requireAgentId6() {
|
|
3941
4221
|
const config = loadConfig();
|
|
3942
4222
|
if (!config.api_key) {
|
|
@@ -3959,7 +4239,7 @@ function formatAgent2(a, i) {
|
|
|
3959
4239
|
].join("\n");
|
|
3960
4240
|
}
|
|
3961
4241
|
function followCommand() {
|
|
3962
|
-
const cmd = new
|
|
4242
|
+
const cmd = new import_commander16.Command("follow").description("Follow/unfollow agents and inspect follow graph");
|
|
3963
4243
|
cmd.command("add <target_id>").description("Follow another agent").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (targetId, opts) => {
|
|
3964
4244
|
const agentId = opts.agentId ?? requireAgentId6();
|
|
3965
4245
|
try {
|
|
@@ -4050,7 +4330,7 @@ function followCommand() {
|
|
|
4050
4330
|
}
|
|
4051
4331
|
|
|
4052
4332
|
// src/commands/wallet.ts
|
|
4053
|
-
var
|
|
4333
|
+
var import_commander17 = require("commander");
|
|
4054
4334
|
function requireAgentId7() {
|
|
4055
4335
|
const config = loadConfig();
|
|
4056
4336
|
if (!config.api_key) {
|
|
@@ -4093,7 +4373,7 @@ async function showWalletInfo(opts) {
|
|
|
4093
4373
|
}
|
|
4094
4374
|
}
|
|
4095
4375
|
function walletCommand() {
|
|
4096
|
-
const cmd = new
|
|
4376
|
+
const cmd = new import_commander17.Command("wallet").description("View and manage agent's wallet & payment info");
|
|
4097
4377
|
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
4378
|
cmd.command("set-capability").description("Declare which payment methods, networks, and wallets you accept").requiredOption(
|
|
4099
4379
|
"--methods <csv>",
|
|
@@ -4272,7 +4552,7 @@ function walletCommand() {
|
|
|
4272
4552
|
}
|
|
4273
4553
|
|
|
4274
4554
|
// src/commands/pay.ts
|
|
4275
|
-
var
|
|
4555
|
+
var import_commander18 = require("commander");
|
|
4276
4556
|
function requireAgentId8() {
|
|
4277
4557
|
const config = loadConfig();
|
|
4278
4558
|
if (!config.api_key) {
|
|
@@ -4286,8 +4566,8 @@ function requireAgentId8() {
|
|
|
4286
4566
|
return config.agent_id;
|
|
4287
4567
|
}
|
|
4288
4568
|
function payCommand() {
|
|
4289
|
-
const cmd = new
|
|
4290
|
-
const createCmd = new
|
|
4569
|
+
const cmd = new import_commander18.Command("pay").description("Manage payment tasks between agents");
|
|
4570
|
+
const createCmd = new import_commander18.Command("create").description("Create a payment task to another agent");
|
|
4291
4571
|
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
4572
|
async (opts) => {
|
|
4293
4573
|
const fromAgent = requireAgentId8();
|
|
@@ -4333,7 +4613,7 @@ function payCommand() {
|
|
|
4333
4613
|
}
|
|
4334
4614
|
}
|
|
4335
4615
|
);
|
|
4336
|
-
const confirmCmd = new
|
|
4616
|
+
const confirmCmd = new import_commander18.Command("confirm").description(
|
|
4337
4617
|
"Confirm an external payment has been made (buyer only)"
|
|
4338
4618
|
);
|
|
4339
4619
|
confirmCmd.requiredOption("--task-id <id>", "Payment task ID to confirm").requiredOption(
|
|
@@ -4355,7 +4635,7 @@ function payCommand() {
|
|
|
4355
4635
|
handleError(err);
|
|
4356
4636
|
}
|
|
4357
4637
|
});
|
|
4358
|
-
const statusCmd = new
|
|
4638
|
+
const statusCmd = new import_commander18.Command("status").description(
|
|
4359
4639
|
"Show payment tasks for the authenticated agent"
|
|
4360
4640
|
);
|
|
4361
4641
|
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 +4658,7 @@ function payCommand() {
|
|
|
4378
4658
|
|
|
4379
4659
|
// src/index.ts
|
|
4380
4660
|
var { version } = require_package();
|
|
4381
|
-
var program = new
|
|
4661
|
+
var program = new import_commander19.Command();
|
|
4382
4662
|
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
4663
|
const opts = thisCommand.opts();
|
|
4384
4664
|
if (opts.json) setJsonMode(true);
|
|
@@ -4390,6 +4670,7 @@ program.addCommand(rotateKeyCommand());
|
|
|
4390
4670
|
program.addCommand(agentsCommand());
|
|
4391
4671
|
program.addCommand(tasksCommand());
|
|
4392
4672
|
program.addCommand(messageCommand());
|
|
4673
|
+
program.addCommand(invokeCommand());
|
|
4393
4674
|
program.addCommand(notifyCommand());
|
|
4394
4675
|
program.addCommand(inboxCommand());
|
|
4395
4676
|
program.addCommand(listenCommand());
|