@acnlabs/acn-cli 0.13.0 → 0.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +478 -77
- package/package.json +1 -1
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: "0.13.
|
|
34
|
+
version: "0.13.3",
|
|
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_commander18 = require("commander");
|
|
91
91
|
|
|
92
92
|
// src/output.ts
|
|
93
93
|
var jsonMode = false;
|
|
@@ -124,32 +124,91 @@ var import_path = require("path");
|
|
|
124
124
|
var import_fs = require("fs");
|
|
125
125
|
var CONFIG_DIR = (0, import_path.join)((0, import_os.homedir)(), ".acn");
|
|
126
126
|
var CONFIG_FILE = (0, import_path.join)(CONFIG_DIR, "config.json");
|
|
127
|
-
var
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
var REGION_BASE_URLS = {
|
|
128
|
+
global: "https://api.acnlabs.dev",
|
|
129
|
+
cn: "https://acn.acnlabs.cn"
|
|
130
|
+
};
|
|
131
|
+
var DEFAULT_BASE_URL = REGION_BASE_URLS.global;
|
|
132
|
+
function normalizeBaseUrl(url) {
|
|
133
|
+
let u = url.trim().replace(/\/+$/, "");
|
|
134
|
+
u = u.replace(/\/api\/v1$/i, "");
|
|
135
|
+
return u.replace(/\/+$/, "");
|
|
136
|
+
}
|
|
137
|
+
function baseUrlForRegion(region) {
|
|
138
|
+
const key = region.trim().toLowerCase();
|
|
139
|
+
if (key === "global" || key === "cn") {
|
|
140
|
+
return REGION_BASE_URLS[key];
|
|
131
141
|
}
|
|
142
|
+
throw new Error(`Unknown region "${region}". Valid: global | cn`);
|
|
143
|
+
}
|
|
144
|
+
function inferRegion(baseUrl) {
|
|
145
|
+
const u = normalizeBaseUrl(baseUrl);
|
|
146
|
+
if (u === REGION_BASE_URLS.global) return "global";
|
|
147
|
+
if (u === REGION_BASE_URLS.cn) return "cn";
|
|
148
|
+
return void 0;
|
|
149
|
+
}
|
|
150
|
+
function readConfigFile() {
|
|
151
|
+
if (!(0, import_fs.existsSync)(CONFIG_FILE)) return {};
|
|
132
152
|
try {
|
|
133
153
|
const raw = (0, import_fs.readFileSync)(CONFIG_FILE, "utf-8");
|
|
134
|
-
|
|
135
|
-
return {
|
|
136
|
-
base_url: parsed.base_url ?? DEFAULT_BASE_URL,
|
|
137
|
-
api_key: parsed.api_key,
|
|
138
|
-
agent_id: parsed.agent_id
|
|
139
|
-
};
|
|
154
|
+
return JSON.parse(raw);
|
|
140
155
|
} catch {
|
|
141
|
-
return {
|
|
156
|
+
return {};
|
|
142
157
|
}
|
|
143
158
|
}
|
|
159
|
+
function resolveBaseUrl(overrides) {
|
|
160
|
+
if (overrides?.base_url) {
|
|
161
|
+
return normalizeBaseUrl(overrides.base_url);
|
|
162
|
+
}
|
|
163
|
+
if (overrides?.region) {
|
|
164
|
+
return baseUrlForRegion(overrides.region);
|
|
165
|
+
}
|
|
166
|
+
const env = process.env.ACN_BASE_URL?.trim();
|
|
167
|
+
if (env) {
|
|
168
|
+
return normalizeBaseUrl(env);
|
|
169
|
+
}
|
|
170
|
+
const file = readConfigFile();
|
|
171
|
+
if (file.base_url) {
|
|
172
|
+
return normalizeBaseUrl(file.base_url);
|
|
173
|
+
}
|
|
174
|
+
if (file.region) {
|
|
175
|
+
return baseUrlForRegion(file.region);
|
|
176
|
+
}
|
|
177
|
+
return DEFAULT_BASE_URL;
|
|
178
|
+
}
|
|
179
|
+
function loadConfig() {
|
|
180
|
+
const file = readConfigFile();
|
|
181
|
+
const base_url = resolveBaseUrl();
|
|
182
|
+
return {
|
|
183
|
+
base_url,
|
|
184
|
+
api_key: file.api_key,
|
|
185
|
+
agent_id: file.agent_id,
|
|
186
|
+
region: inferRegion(base_url)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
144
189
|
function saveConfig(updates) {
|
|
145
190
|
if (!(0, import_fs.existsSync)(CONFIG_DIR)) {
|
|
146
191
|
(0, import_fs.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
147
192
|
}
|
|
148
|
-
const
|
|
193
|
+
const file = readConfigFile();
|
|
194
|
+
const current = {
|
|
195
|
+
base_url: file.base_url ? normalizeBaseUrl(file.base_url) : DEFAULT_BASE_URL,
|
|
196
|
+
api_key: file.api_key,
|
|
197
|
+
agent_id: file.agent_id,
|
|
198
|
+
region: file.region === "global" || file.region === "cn" ? file.region : void 0
|
|
199
|
+
};
|
|
149
200
|
const next = { ...current, ...updates };
|
|
150
|
-
|
|
201
|
+
if (updates.region && !updates.base_url) {
|
|
202
|
+
next.base_url = baseUrlForRegion(updates.region);
|
|
203
|
+
}
|
|
204
|
+
if (updates.base_url && updates.region === void 0) {
|
|
205
|
+
next.region = inferRegion(updates.base_url);
|
|
206
|
+
}
|
|
207
|
+
const clean = { base_url: normalizeBaseUrl(next.base_url) };
|
|
151
208
|
if (next.api_key !== void 0) clean.api_key = next.api_key;
|
|
152
209
|
if (next.agent_id !== void 0) clean.agent_id = next.agent_id;
|
|
210
|
+
const region = next.region ?? inferRegion(clean.base_url);
|
|
211
|
+
if (region !== void 0) clean.region = region;
|
|
153
212
|
(0, import_fs.writeFileSync)(CONFIG_FILE, JSON.stringify(clean, null, 2), "utf-8");
|
|
154
213
|
}
|
|
155
214
|
function getConfigPath() {
|
|
@@ -157,7 +216,7 @@ function getConfigPath() {
|
|
|
157
216
|
}
|
|
158
217
|
|
|
159
218
|
// src/commands/config.ts
|
|
160
|
-
var VALID_KEYS = ["api-key", "agent-id", "base-url"];
|
|
219
|
+
var VALID_KEYS = ["api-key", "agent-id", "base-url", "region"];
|
|
161
220
|
var KEY_MAP = {
|
|
162
221
|
"api-key": "api_key",
|
|
163
222
|
"agent-id": "agent_id",
|
|
@@ -165,11 +224,25 @@ var KEY_MAP = {
|
|
|
165
224
|
};
|
|
166
225
|
function configCommand() {
|
|
167
226
|
const cmd = new import_commander.Command("config").description("Manage local ACN configuration");
|
|
168
|
-
cmd.command("set <key> <value>").description(
|
|
227
|
+
cmd.command("set <key> <value>").description(
|
|
228
|
+
`Set a config value. Keys: ${VALID_KEYS.join(", ")}. region is global|cn (sets base-url). Env ACN_BASE_URL overrides base-url at runtime.`
|
|
229
|
+
).action((key, value) => {
|
|
169
230
|
if (!VALID_KEYS.includes(key)) {
|
|
170
231
|
console.error(`Unknown key "${key}". Valid keys: ${VALID_KEYS.join(", ")}`);
|
|
171
232
|
process.exit(1);
|
|
172
233
|
}
|
|
234
|
+
if (key === "region") {
|
|
235
|
+
try {
|
|
236
|
+
const base_url = baseUrlForRegion(value);
|
|
237
|
+
const region = value.trim().toLowerCase();
|
|
238
|
+
saveConfig({ region, base_url });
|
|
239
|
+
output({ key, value: region, base_url }, `Set region = ${region} (base-url = ${base_url})`);
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
173
246
|
saveConfig({ [KEY_MAP[key]]: value });
|
|
174
247
|
output({ key, value }, `Set ${key} = ${value}`);
|
|
175
248
|
});
|
|
@@ -179,19 +252,21 @@ function configCommand() {
|
|
|
179
252
|
process.exit(1);
|
|
180
253
|
}
|
|
181
254
|
const config = loadConfig();
|
|
182
|
-
const val = config[KEY_MAP[key]];
|
|
255
|
+
const val = key === "region" ? config.region : config[KEY_MAP[key]];
|
|
183
256
|
if (val === void 0) {
|
|
184
257
|
console.error(`Key "${key}" is not set.`);
|
|
185
258
|
process.exit(1);
|
|
186
259
|
}
|
|
187
|
-
output({ key, value: val }, val);
|
|
260
|
+
output({ key, value: val }, String(val));
|
|
188
261
|
});
|
|
189
262
|
cmd.command("show").description("Show all config values").action(() => {
|
|
190
263
|
const config = loadConfig();
|
|
191
264
|
const path = getConfigPath();
|
|
265
|
+
const envOverride = process.env.ACN_BASE_URL?.trim() ? ` (ACN_BASE_URL override active)` : "";
|
|
192
266
|
output(config, [
|
|
193
267
|
`Config file: ${path}`,
|
|
194
|
-
`
|
|
268
|
+
` region : ${config.region ?? "(custom / unknown)"}`,
|
|
269
|
+
` base-url : ${config.base_url}${envOverride}`,
|
|
195
270
|
` api-key : ${config.api_key ? maskKey(config.api_key) : "(not set)"}`,
|
|
196
271
|
` agent-id : ${config.agent_id ?? "(not set)"}`
|
|
197
272
|
].join("\n"));
|
|
@@ -228,8 +303,9 @@ function extractDetail(body) {
|
|
|
228
303
|
}
|
|
229
304
|
async function acnFetch(path, options = {}) {
|
|
230
305
|
const config = loadConfig();
|
|
231
|
-
const { params, ...fetchOptions } = options;
|
|
232
|
-
const
|
|
306
|
+
const { params, baseUrl: baseUrlOverride, ...fetchOptions } = options;
|
|
307
|
+
const origin = baseUrlOverride ? normalizeBaseUrl(baseUrlOverride) : config.base_url;
|
|
308
|
+
const url = new URL(`${origin}/api/v1${path}`);
|
|
233
309
|
if (params) {
|
|
234
310
|
for (const [k, v] of Object.entries(params)) {
|
|
235
311
|
if (v !== void 0) url.searchParams.set(k, String(v));
|
|
@@ -257,23 +333,25 @@ async function acnFetch(path, options = {}) {
|
|
|
257
333
|
}
|
|
258
334
|
return res.json();
|
|
259
335
|
}
|
|
260
|
-
function acnGet(path, params) {
|
|
261
|
-
return acnFetch(path, { method: "GET", params });
|
|
336
|
+
function acnGet(path, params, opts) {
|
|
337
|
+
return acnFetch(path, { method: "GET", params, baseUrl: opts?.baseUrl });
|
|
262
338
|
}
|
|
263
|
-
function acnPost(path, body) {
|
|
339
|
+
function acnPost(path, body, opts) {
|
|
264
340
|
return acnFetch(path, {
|
|
265
341
|
method: "POST",
|
|
266
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
342
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
343
|
+
baseUrl: opts?.baseUrl
|
|
267
344
|
});
|
|
268
345
|
}
|
|
269
|
-
function acnPatch(path, body) {
|
|
346
|
+
function acnPatch(path, body, opts) {
|
|
270
347
|
return acnFetch(path, {
|
|
271
348
|
method: "PATCH",
|
|
272
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
349
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
350
|
+
baseUrl: opts?.baseUrl
|
|
273
351
|
});
|
|
274
352
|
}
|
|
275
|
-
function acnDelete(path) {
|
|
276
|
-
return acnFetch(path, { method: "DELETE" });
|
|
353
|
+
function acnDelete(path, opts) {
|
|
354
|
+
return acnFetch(path, { method: "DELETE", baseUrl: opts?.baseUrl });
|
|
277
355
|
}
|
|
278
356
|
|
|
279
357
|
// src/commands/join.ts
|
|
@@ -281,8 +359,30 @@ function joinCommand() {
|
|
|
281
359
|
return new import_commander2.Command("join").description("Register this agent with ACN and save credentials locally").requiredOption("-n, --name <name>", "Agent name").requiredOption("-t, --tags <tags>", "Comma-separated capability tags (e.g. coding,review)").option("-e, --endpoint <url>", "Public A2A endpoint URL of this agent").option("-d, --description <text>", "Agent description").option(
|
|
282
360
|
"--relay",
|
|
283
361
|
"Receive messages in real time over an outbound WebSocket (run `acn listen`) instead of hosting a public endpoint. Registers in open/push mode with no delivery URL."
|
|
362
|
+
).option(
|
|
363
|
+
"--region <region>",
|
|
364
|
+
"ACN deployment to join: global (api.acnlabs.dev) or cn (acn.acnlabs.cn). Pick by where the agent is hosted \u2014 not by user nationality."
|
|
365
|
+
).option(
|
|
366
|
+
"--base-url <url>",
|
|
367
|
+
"Override ACN origin (no /api/v1). Overrides --region and ACN_BASE_URL for this join."
|
|
284
368
|
).action(
|
|
285
369
|
async (opts) => {
|
|
370
|
+
if (opts.region && opts.baseUrl) {
|
|
371
|
+
console.error("Use either --region or --base-url, not both.");
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
if (opts.region) {
|
|
375
|
+
const r = opts.region.trim().toLowerCase();
|
|
376
|
+
if (r !== "global" && r !== "cn") {
|
|
377
|
+
console.error(`Unknown --region "${opts.region}". Valid: global | cn`);
|
|
378
|
+
process.exit(1);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const base_url = resolveBaseUrl({
|
|
382
|
+
base_url: opts.baseUrl,
|
|
383
|
+
region: opts.region
|
|
384
|
+
});
|
|
385
|
+
const region = opts.region?.trim().toLowerCase() === "cn" || opts.region?.trim().toLowerCase() === "global" ? opts.region.trim().toLowerCase() : inferRegion(base_url);
|
|
286
386
|
const tags = opts.tags.split(",").map((s) => s.trim()).filter(Boolean);
|
|
287
387
|
const body = {
|
|
288
388
|
name: opts.name,
|
|
@@ -295,19 +395,30 @@ function joinCommand() {
|
|
|
295
395
|
...opts.relay ? { delivery: "relay", communication_policy: { mode: "open" } } : {}
|
|
296
396
|
};
|
|
297
397
|
try {
|
|
298
|
-
const res = await acnPost("/agents/join", body
|
|
299
|
-
|
|
398
|
+
const res = await acnPost("/agents/join", body, {
|
|
399
|
+
baseUrl: base_url
|
|
400
|
+
});
|
|
401
|
+
saveConfig({
|
|
402
|
+
api_key: res.api_key,
|
|
403
|
+
agent_id: res.agent_id,
|
|
404
|
+
base_url,
|
|
405
|
+
...region ? { region } : {}
|
|
406
|
+
});
|
|
300
407
|
const claimLine = res.claim_url ? `
|
|
301
408
|
Claim URL: ${res.claim_url}` : "";
|
|
302
409
|
const verifyLine = res.verification_code ? `
|
|
303
410
|
Verify : ${res.verification_code}` : "";
|
|
411
|
+
const regionLine = region ? `
|
|
412
|
+
Region : ${region}` : "";
|
|
304
413
|
output(res, [
|
|
305
414
|
`Registered successfully!`,
|
|
306
415
|
` Agent ID : ${res.agent_id}`,
|
|
307
416
|
` API Key : ${res.api_key}`,
|
|
417
|
+
` ACN : ${base_url}${regionLine}`,
|
|
308
418
|
` Status : ${res.status}${claimLine}${verifyLine}`,
|
|
309
419
|
``,
|
|
310
|
-
`Credentials saved to ~/.acn/config.json
|
|
420
|
+
`Credentials saved to ~/.acn/config.json`,
|
|
421
|
+
`Do not reuse this api_key against another region \u2014 re-join instead.`
|
|
311
422
|
].join("\n"));
|
|
312
423
|
} catch (err) {
|
|
313
424
|
handleError(err);
|
|
@@ -1509,9 +1620,108 @@ function listenCommand() {
|
|
|
1509
1620
|
return cmd;
|
|
1510
1621
|
}
|
|
1511
1622
|
|
|
1512
|
-
// src/commands/
|
|
1623
|
+
// src/commands/delivery.ts
|
|
1513
1624
|
var import_commander11 = require("commander");
|
|
1625
|
+
var DELIVERY_DESC = {
|
|
1626
|
+
direct: "direct (Mode A) \u2014 ACN dials your public A2A endpoint over HTTP",
|
|
1627
|
+
relay: "relay (Mode B) \u2014 hold an outbound WebSocket with `acn listen`; no public URL",
|
|
1628
|
+
none: "none \u2014 pull/reject only (communication_policy is manifest or closed; not Mode A/B)"
|
|
1629
|
+
};
|
|
1514
1630
|
function requireAgentId3() {
|
|
1631
|
+
const config = loadConfig();
|
|
1632
|
+
if (!config.api_key) {
|
|
1633
|
+
console.error(
|
|
1634
|
+
"No API key found. Run `acn join` first or `acn config set api-key <key>`."
|
|
1635
|
+
);
|
|
1636
|
+
process.exit(1);
|
|
1637
|
+
}
|
|
1638
|
+
if (!config.agent_id) {
|
|
1639
|
+
console.error(
|
|
1640
|
+
"No agent ID found. Run `acn join` first or `acn config set agent-id <id>`."
|
|
1641
|
+
);
|
|
1642
|
+
process.exit(1);
|
|
1643
|
+
}
|
|
1644
|
+
return config.agent_id;
|
|
1645
|
+
}
|
|
1646
|
+
function formatDelivery(d) {
|
|
1647
|
+
const lines = [
|
|
1648
|
+
`Delivery : ${DELIVERY_DESC[d.delivery] ?? d.delivery}`,
|
|
1649
|
+
`Policy : ${d.communication_mode ?? "?"} (reception \u2014 not the same as delivery)`,
|
|
1650
|
+
`Endpoint : ${d.endpoint ?? "(none)"}`
|
|
1651
|
+
];
|
|
1652
|
+
if (d.a2a_handshake_ok === false) {
|
|
1653
|
+
lines.push("A2A probe: false \u2014 URL reachable but not JSON-RPC; fix the path");
|
|
1654
|
+
} else if (d.a2a_handshake_ok === true) {
|
|
1655
|
+
lines.push("A2A probe: ok");
|
|
1656
|
+
}
|
|
1657
|
+
if (d.next_step_hint) {
|
|
1658
|
+
lines.push("", d.next_step_hint);
|
|
1659
|
+
}
|
|
1660
|
+
return lines.join("\n");
|
|
1661
|
+
}
|
|
1662
|
+
function deliveryCommand() {
|
|
1663
|
+
const cmd = new import_commander11.Command("delivery").description(
|
|
1664
|
+
"Inbound delivery transport (Mode A direct / Mode B relay). Orthogonal to reception policy (`acn inbox mode`)."
|
|
1665
|
+
);
|
|
1666
|
+
cmd.command("get").description("Show derived delivery transport (direct | relay | none)").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
1667
|
+
const agentId = opts.agentId ?? requireAgentId3();
|
|
1668
|
+
try {
|
|
1669
|
+
const res = await acnGet(`/agents/${agentId}/delivery`);
|
|
1670
|
+
output(res, formatDelivery(res));
|
|
1671
|
+
} catch (err) {
|
|
1672
|
+
handleError(err);
|
|
1673
|
+
}
|
|
1674
|
+
});
|
|
1675
|
+
cmd.command("set <transport>").description(
|
|
1676
|
+
"Switch delivery without re-registering: relay (Mode B) or direct (Mode A). Requires push reception policy (open / allowlist)."
|
|
1677
|
+
).option(
|
|
1678
|
+
"-e, --endpoint <url>",
|
|
1679
|
+
"Required for direct: public A2A JSON-RPC URL (e.g. https://host/a2a)"
|
|
1680
|
+
).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(
|
|
1681
|
+
async (transport, opts) => {
|
|
1682
|
+
const agentId = opts.agentId ?? requireAgentId3();
|
|
1683
|
+
const normalized = transport.trim().toLowerCase();
|
|
1684
|
+
if (normalized !== "relay" && normalized !== "direct") {
|
|
1685
|
+
console.error(
|
|
1686
|
+
`Unknown transport "${transport}". Use: relay | direct`
|
|
1687
|
+
);
|
|
1688
|
+
process.exit(1);
|
|
1689
|
+
}
|
|
1690
|
+
if (normalized === "direct" && !opts.endpoint) {
|
|
1691
|
+
console.error(
|
|
1692
|
+
"direct requires --endpoint <url> (full A2A path, e.g. https://host/a2a)."
|
|
1693
|
+
);
|
|
1694
|
+
process.exit(1);
|
|
1695
|
+
}
|
|
1696
|
+
if (normalized === "relay" && opts.endpoint) {
|
|
1697
|
+
console.error(
|
|
1698
|
+
"relay must not include --endpoint (clear the public URL; use `acn listen`)."
|
|
1699
|
+
);
|
|
1700
|
+
process.exit(1);
|
|
1701
|
+
}
|
|
1702
|
+
const body = normalized === "relay" ? { delivery: "relay" } : { delivery: "direct", endpoint: opts.endpoint };
|
|
1703
|
+
try {
|
|
1704
|
+
const res = await acnPatch(
|
|
1705
|
+
`/agents/${agentId}/delivery`,
|
|
1706
|
+
body
|
|
1707
|
+
);
|
|
1708
|
+
const followUp = res.delivery === "relay" ? [
|
|
1709
|
+
"",
|
|
1710
|
+
"Next: keep a local A2A handler up, then:",
|
|
1711
|
+
" acn listen --forward http://localhost:PORT"
|
|
1712
|
+
] : [];
|
|
1713
|
+
output(res, [formatDelivery(res), ...followUp].join("\n"));
|
|
1714
|
+
} catch (err) {
|
|
1715
|
+
handleError(err);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
);
|
|
1719
|
+
return cmd;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// src/commands/session.ts
|
|
1723
|
+
var import_commander12 = require("commander");
|
|
1724
|
+
function requireAgentId4() {
|
|
1515
1725
|
const config = loadConfig();
|
|
1516
1726
|
if (!config.api_key) {
|
|
1517
1727
|
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
@@ -1555,12 +1765,12 @@ function formatEntry2(s, index) {
|
|
|
1555
1765
|
return lines.join("\n");
|
|
1556
1766
|
}
|
|
1557
1767
|
function sessionCommand() {
|
|
1558
|
-
const cmd = new
|
|
1768
|
+
const cmd = new import_commander12.Command("session").description(
|
|
1559
1769
|
"Real-time session layer: bidirectional channel between two agents"
|
|
1560
1770
|
);
|
|
1561
1771
|
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(
|
|
1562
1772
|
async (targetId, opts) => {
|
|
1563
|
-
|
|
1773
|
+
requireAgentId4();
|
|
1564
1774
|
try {
|
|
1565
1775
|
const body = {};
|
|
1566
1776
|
if (opts.ttlSeconds !== void 0) body.ttl_seconds = opts.ttlSeconds;
|
|
@@ -1581,7 +1791,7 @@ ${formatEntry2(res)}`
|
|
|
1581
1791
|
}
|
|
1582
1792
|
);
|
|
1583
1793
|
cmd.command("accept <session_id>").description("Accept a pending session invitation (invitee only)").action(async (sessionId) => {
|
|
1584
|
-
|
|
1794
|
+
requireAgentId4();
|
|
1585
1795
|
try {
|
|
1586
1796
|
const res = await acnPost(`/sessions/${sessionId}/accept`);
|
|
1587
1797
|
output(res, `Session accepted.
|
|
@@ -1591,7 +1801,7 @@ ${formatEntry2(res)}`);
|
|
|
1591
1801
|
}
|
|
1592
1802
|
});
|
|
1593
1803
|
cmd.command("reject <session_id>").description("Reject a pending session invitation (invitee only)").action(async (sessionId) => {
|
|
1594
|
-
|
|
1804
|
+
requireAgentId4();
|
|
1595
1805
|
try {
|
|
1596
1806
|
const res = await acnPost(`/sessions/${sessionId}/reject`);
|
|
1597
1807
|
output(res, `Session rejected.
|
|
@@ -1601,7 +1811,7 @@ ${formatEntry2(res)}`);
|
|
|
1601
1811
|
}
|
|
1602
1812
|
});
|
|
1603
1813
|
cmd.command("close <session_id>").description("Close an active session (either party may close)").action(async (sessionId) => {
|
|
1604
|
-
|
|
1814
|
+
requireAgentId4();
|
|
1605
1815
|
try {
|
|
1606
1816
|
const res = await acnDelete(`/sessions/${sessionId}`);
|
|
1607
1817
|
output(res, `Session closed.
|
|
@@ -1611,7 +1821,7 @@ ${formatEntry2(res)}`);
|
|
|
1611
1821
|
}
|
|
1612
1822
|
});
|
|
1613
1823
|
cmd.command("pending").description("List pending session invitations addressed to you").action(async () => {
|
|
1614
|
-
|
|
1824
|
+
requireAgentId4();
|
|
1615
1825
|
try {
|
|
1616
1826
|
const res = await acnGet("/sessions/pending");
|
|
1617
1827
|
const sessions = res.sessions ?? [];
|
|
@@ -1633,8 +1843,8 @@ ${formatEntry2(res)}`);
|
|
|
1633
1843
|
}
|
|
1634
1844
|
|
|
1635
1845
|
// src/commands/subnet.ts
|
|
1636
|
-
var
|
|
1637
|
-
function
|
|
1846
|
+
var import_commander13 = require("commander");
|
|
1847
|
+
function requireAgentId5() {
|
|
1638
1848
|
const config = loadConfig();
|
|
1639
1849
|
if (!config.api_key) {
|
|
1640
1850
|
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
@@ -1721,7 +1931,7 @@ function formatSubnet(s, index) {
|
|
|
1721
1931
|
return lines.join("\n");
|
|
1722
1932
|
}
|
|
1723
1933
|
function subnetCommand() {
|
|
1724
|
-
const cmd = new
|
|
1934
|
+
const cmd = new import_commander13.Command("subnet").description("Manage ACN subnets");
|
|
1725
1935
|
cmd.command("list").description(
|
|
1726
1936
|
"List subnets. Without --all/--parent shows only subnets you have joined."
|
|
1727
1937
|
).option("--all", "Show all public subnets on ACN (not just your own)").option(
|
|
@@ -1760,7 +1970,7 @@ function subnetCommand() {
|
|
|
1760
1970
|
` + subnets.map((s, i) => formatSubnet(s, i)).join("\n\n")
|
|
1761
1971
|
);
|
|
1762
1972
|
} else {
|
|
1763
|
-
const agentId = opts.agentId ??
|
|
1973
|
+
const agentId = opts.agentId ?? requireAgentId5();
|
|
1764
1974
|
const res = await acnGet(
|
|
1765
1975
|
`/subnets/${agentId}/subnets`
|
|
1766
1976
|
);
|
|
@@ -1799,7 +2009,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
1799
2009
|
cmd.command("join <subnet_id>").description(
|
|
1800
2010
|
"Join a subnet. ADR-0004: branches on response shape (open/allowlist/auto-invite/pending)."
|
|
1801
2011
|
).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (subnetId, opts) => {
|
|
1802
|
-
const agentId = opts.agentId ??
|
|
2012
|
+
const agentId = opts.agentId ?? requireAgentId5();
|
|
1803
2013
|
try {
|
|
1804
2014
|
const res = await acnPost(
|
|
1805
2015
|
`/agents/${agentId}/subnets/${subnetId}`
|
|
@@ -1810,7 +2020,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
1810
2020
|
}
|
|
1811
2021
|
});
|
|
1812
2022
|
cmd.command("leave <subnet_id>").description("Leave a subnet").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (subnetId, opts) => {
|
|
1813
|
-
const agentId = opts.agentId ??
|
|
2023
|
+
const agentId = opts.agentId ?? requireAgentId5();
|
|
1814
2024
|
try {
|
|
1815
2025
|
const res = await acnDelete(
|
|
1816
2026
|
`/agents/${agentId}/subnets/${subnetId}`
|
|
@@ -1938,7 +2148,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
1938
2148
|
handleError(err);
|
|
1939
2149
|
}
|
|
1940
2150
|
});
|
|
1941
|
-
const requests = new
|
|
2151
|
+
const requests = new import_commander13.Command("requests").description(
|
|
1942
2152
|
"Manage join-requests for a subnet (ADR-0004)"
|
|
1943
2153
|
);
|
|
1944
2154
|
requests.command("list <subnet_id>").description(
|
|
@@ -1982,7 +2192,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
1982
2192
|
requests.command("pending").description(
|
|
1983
2193
|
"Owner-side convenience: list pending join_requests across every subnet you own. Client-side aggregation \u2014 issues N+1 calls (one per owned subnet)."
|
|
1984
2194
|
).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
1985
|
-
const agentId = opts.agentId ??
|
|
2195
|
+
const agentId = opts.agentId ?? requireAgentId5();
|
|
1986
2196
|
try {
|
|
1987
2197
|
const subs = await acnGet(`/agents/${agentId}/subnets`);
|
|
1988
2198
|
const subnetIds = subs.subnets ?? [];
|
|
@@ -2080,7 +2290,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
2080
2290
|
}
|
|
2081
2291
|
);
|
|
2082
2292
|
cmd.addCommand(requests);
|
|
2083
|
-
const invitations = new
|
|
2293
|
+
const invitations = new import_commander13.Command("invitations").description(
|
|
2084
2294
|
"Manage invitations on a subnet (ADR-0004)"
|
|
2085
2295
|
);
|
|
2086
2296
|
invitations.command("send <subnet_id>").description(
|
|
@@ -2135,7 +2345,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
2135
2345
|
invitations.command("pending").description(
|
|
2136
2346
|
"Invitee view: list pending invitations addressed to you across all subnets (backed by GET /agents/{aid}/subnet-invitations)."
|
|
2137
2347
|
).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
2138
|
-
const agentId = opts.agentId ??
|
|
2348
|
+
const agentId = opts.agentId ?? requireAgentId5();
|
|
2139
2349
|
try {
|
|
2140
2350
|
const res = await acnGet(
|
|
2141
2351
|
`/agents/${agentId}/subnet-invitations`
|
|
@@ -2216,7 +2426,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
2216
2426
|
}
|
|
2217
2427
|
);
|
|
2218
2428
|
cmd.addCommand(invitations);
|
|
2219
|
-
const allowlist = new
|
|
2429
|
+
const allowlist = new import_commander13.Command("allowlist").description(
|
|
2220
2430
|
"Manage a subnet allowlist (ADR-0004)"
|
|
2221
2431
|
);
|
|
2222
2432
|
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(
|
|
@@ -2284,7 +2494,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
2284
2494
|
}
|
|
2285
2495
|
);
|
|
2286
2496
|
cmd.addCommand(allowlist);
|
|
2287
|
-
const harness = new
|
|
2497
|
+
const harness = new import_commander13.Command("harness").description("Manage Org Harness webhook for a subnet");
|
|
2288
2498
|
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) => {
|
|
2289
2499
|
const config = loadConfig();
|
|
2290
2500
|
if (!config.api_key) {
|
|
@@ -2326,9 +2536,198 @@ ${JSON.stringify(res.agents, null, 2)}`);
|
|
|
2326
2536
|
return cmd;
|
|
2327
2537
|
}
|
|
2328
2538
|
|
|
2539
|
+
// src/commands/org.ts
|
|
2540
|
+
var import_commander14 = require("commander");
|
|
2541
|
+
function formatOrg(o) {
|
|
2542
|
+
const lines = [
|
|
2543
|
+
` ID : ${o.org_id}`,
|
|
2544
|
+
` Name : ${o.display_name}`,
|
|
2545
|
+
` Status : ${o.status ?? "\u2014"}`,
|
|
2546
|
+
` Owner : ${o.owner?.kind ?? "none"}${o.owner?.subject ? ` (${o.owner.subject})` : ""}`,
|
|
2547
|
+
` Steward : ${o.steward_agent_id ?? "\u2014"}`,
|
|
2548
|
+
` Subnet : ${o.fencing?.subnet_id ?? o.subnet_id ?? "\u2014"}`
|
|
2549
|
+
];
|
|
2550
|
+
if (o.fencing?.join_policy) lines.push(` Join : ${o.fencing.join_policy}`);
|
|
2551
|
+
if (o.harness_webhook?.registered) {
|
|
2552
|
+
lines.push(` Harness : ${o.harness_webhook.url ?? "(registered)"}`);
|
|
2553
|
+
}
|
|
2554
|
+
return lines.join("\n");
|
|
2555
|
+
}
|
|
2556
|
+
function orgCommand() {
|
|
2557
|
+
const cmd = new import_commander14.Command("org").description("Manage ACN organisations (Org Harness)");
|
|
2558
|
+
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(
|
|
2559
|
+
async (opts) => {
|
|
2560
|
+
try {
|
|
2561
|
+
const body = {
|
|
2562
|
+
display_name: opts.name,
|
|
2563
|
+
is_private: Boolean(opts.private),
|
|
2564
|
+
join_policy: opts.joinPolicy ?? "open"
|
|
2565
|
+
};
|
|
2566
|
+
if (opts.steward) body.steward_agent_id = opts.steward;
|
|
2567
|
+
if (opts.subnet) body.subnet_id = opts.subnet;
|
|
2568
|
+
if (opts.harnessUrl) body.harness_url = opts.harnessUrl;
|
|
2569
|
+
if (opts.harnessSecret) body.harness_secret = opts.harnessSecret;
|
|
2570
|
+
const org = await acnPost("/orgs", body);
|
|
2571
|
+
output(org, formatOrg(org));
|
|
2572
|
+
} catch (err) {
|
|
2573
|
+
handleError(err);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
);
|
|
2577
|
+
cmd.command("show <orgId>").description("Show Org details").action(async (orgId) => {
|
|
2578
|
+
try {
|
|
2579
|
+
const org = await acnGet(`/orgs/${orgId}`);
|
|
2580
|
+
output(org, formatOrg(org));
|
|
2581
|
+
} catch (err) {
|
|
2582
|
+
handleError(err);
|
|
2583
|
+
}
|
|
2584
|
+
});
|
|
2585
|
+
cmd.command("update <orgId>").description("Update Org charter / plugins / display name").option("--name <name>", "New display name").option("--charter <json>", "Charter JSON object").option("--plugins <json>", "Plugins JSON object (merged)").action(
|
|
2586
|
+
async (orgId, opts) => {
|
|
2587
|
+
try {
|
|
2588
|
+
const body = {};
|
|
2589
|
+
if (opts.name) body.display_name = opts.name;
|
|
2590
|
+
if (opts.charter) body.charter = JSON.parse(opts.charter);
|
|
2591
|
+
if (opts.plugins) body.plugins = JSON.parse(opts.plugins);
|
|
2592
|
+
const org = await acnPatch(`/orgs/${orgId}`, body);
|
|
2593
|
+
output(org, formatOrg(org));
|
|
2594
|
+
} catch (err) {
|
|
2595
|
+
handleError(err);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
);
|
|
2599
|
+
const members = cmd.command("members").description("Manage Org members");
|
|
2600
|
+
members.command("list <orgId>").description("List active members (marks degraded vs subnet fence)").action(async (orgId) => {
|
|
2601
|
+
try {
|
|
2602
|
+
const res = await acnGet(`/orgs/${orgId}/members`);
|
|
2603
|
+
const text = (res.members ?? []).map((m) => {
|
|
2604
|
+
const flags = [];
|
|
2605
|
+
if (m.acn?.degraded) flags.push("degraded");
|
|
2606
|
+
if (m.acn && !m.acn.subnet_member) flags.push("not-in-subnet");
|
|
2607
|
+
const flagStr = flags.length ? ` [${flags.join(",")}]` : "";
|
|
2608
|
+
return ` ${m.agent_id} role=${m.role} status=${m.status}${flagStr}`;
|
|
2609
|
+
}).join("\n");
|
|
2610
|
+
const header = res.degraded_count || res.fence_missing ? ` (degraded=${res.degraded_count} fence_missing=${res.fence_missing})
|
|
2611
|
+
` : "";
|
|
2612
|
+
output(res, header + (text || " (no members)"));
|
|
2613
|
+
} catch (err) {
|
|
2614
|
+
handleError(err);
|
|
2615
|
+
}
|
|
2616
|
+
});
|
|
2617
|
+
members.command("add <orgId> <agentId>").description("Add an agent member").option("--role <role>", "Member role", "worker").action(async (orgId, agentId, opts) => {
|
|
2618
|
+
try {
|
|
2619
|
+
const m = await acnPost(`/orgs/${orgId}/members`, {
|
|
2620
|
+
agent_id: agentId,
|
|
2621
|
+
role: opts.role
|
|
2622
|
+
});
|
|
2623
|
+
output(m, `Added ${m.agent_id} as ${m.role}`);
|
|
2624
|
+
} catch (err) {
|
|
2625
|
+
handleError(err);
|
|
2626
|
+
}
|
|
2627
|
+
});
|
|
2628
|
+
members.command("remove <orgId> <agentId>").description("Remove an agent member").action(async (orgId, agentId) => {
|
|
2629
|
+
try {
|
|
2630
|
+
const m = await acnDelete(`/orgs/${orgId}/members/${agentId}`);
|
|
2631
|
+
output(m, `Removed ${m.agent_id}`);
|
|
2632
|
+
} catch (err) {
|
|
2633
|
+
handleError(err);
|
|
2634
|
+
}
|
|
2635
|
+
});
|
|
2636
|
+
cmd.command("claim <orgId>").description("Claim ownership of an unclaimed Org (created_by only)").option("--as <kind>", "human | agent").option("--subject <id>", "Owner subject (defaults to caller)").action(async (orgId, opts) => {
|
|
2637
|
+
try {
|
|
2638
|
+
const body = {};
|
|
2639
|
+
if (opts.as) body.owner_kind = opts.as;
|
|
2640
|
+
if (opts.subject) body.owner_subject = opts.subject;
|
|
2641
|
+
const org = await acnPost(`/orgs/${orgId}/claim`, body);
|
|
2642
|
+
output(org, formatOrg(org));
|
|
2643
|
+
} catch (err) {
|
|
2644
|
+
handleError(err);
|
|
2645
|
+
}
|
|
2646
|
+
});
|
|
2647
|
+
cmd.command("transfer <orgId>").description("Transfer Org ownership").requiredOption("--kind <kind>", "human | agent").requiredOption("--subject <id>", "New owner subject").action(async (orgId, opts) => {
|
|
2648
|
+
try {
|
|
2649
|
+
const org = await acnPost(`/orgs/${orgId}/transfer`, {
|
|
2650
|
+
new_owner_kind: opts.kind,
|
|
2651
|
+
new_owner_subject: opts.subject
|
|
2652
|
+
});
|
|
2653
|
+
output(org, formatOrg(org));
|
|
2654
|
+
} catch (err) {
|
|
2655
|
+
handleError(err);
|
|
2656
|
+
}
|
|
2657
|
+
});
|
|
2658
|
+
cmd.command("release <orgId>").description("Release Org ownership back to none").action(async (orgId) => {
|
|
2659
|
+
try {
|
|
2660
|
+
const org = await acnPost(`/orgs/${orgId}/release`, {});
|
|
2661
|
+
output(org, formatOrg(org));
|
|
2662
|
+
} catch (err) {
|
|
2663
|
+
handleError(err);
|
|
2664
|
+
}
|
|
2665
|
+
});
|
|
2666
|
+
cmd.command("dissolve <orgId>").description("Dissolve an Org (owner or created_by when unclaimed)").action(async (orgId) => {
|
|
2667
|
+
try {
|
|
2668
|
+
const org = await acnPost(`/orgs/${orgId}/dissolve`, {});
|
|
2669
|
+
output(org, formatOrg(org));
|
|
2670
|
+
} catch (err) {
|
|
2671
|
+
handleError(err);
|
|
2672
|
+
}
|
|
2673
|
+
});
|
|
2674
|
+
const work = cmd.command("work").description("Minimal Org work queue");
|
|
2675
|
+
work.command("list <orgId>").description("List work items").option("--open", "Only open (todo / in_progress)", false).action(async (orgId, opts) => {
|
|
2676
|
+
try {
|
|
2677
|
+
const q = opts.open ? "?open_only=true" : "";
|
|
2678
|
+
const res = await acnGet(
|
|
2679
|
+
`/orgs/${orgId}/work${q}`
|
|
2680
|
+
);
|
|
2681
|
+
const text = (res.work ?? []).map(
|
|
2682
|
+
(w) => ` ${w.work_id} [${w.status}] ${w.title}` + (w.assignee_agent_id ? ` \u2192 ${w.assignee_agent_id}` : "")
|
|
2683
|
+
).join("\n");
|
|
2684
|
+
output(res, text || " (no work)");
|
|
2685
|
+
} catch (err) {
|
|
2686
|
+
handleError(err);
|
|
2687
|
+
}
|
|
2688
|
+
});
|
|
2689
|
+
work.command("create <orgId>").description("Create a work item").requiredOption("--title <title>", "Work title").option("--assignee <agent_id>", "Assignee agent").action(async (orgId, opts) => {
|
|
2690
|
+
try {
|
|
2691
|
+
const body = { title: opts.title };
|
|
2692
|
+
if (opts.assignee) body.assignee_agent_id = opts.assignee;
|
|
2693
|
+
const w = await acnPost(`/orgs/${orgId}/work`, body);
|
|
2694
|
+
output(w, `Created ${w.work_id}: ${w.title}`);
|
|
2695
|
+
} catch (err) {
|
|
2696
|
+
handleError(err);
|
|
2697
|
+
}
|
|
2698
|
+
});
|
|
2699
|
+
work.command("update <orgId> <workId>").description("Update work status").requiredOption("--status <status>", "todo | in_progress | done | cancelled").option("--assignee <agent_id>", "Assignee agent").action(
|
|
2700
|
+
async (orgId, workId, opts) => {
|
|
2701
|
+
try {
|
|
2702
|
+
const body = { status: opts.status };
|
|
2703
|
+
if (opts.assignee) body.assignee_agent_id = opts.assignee;
|
|
2704
|
+
const w = await acnPatch(
|
|
2705
|
+
`/orgs/${orgId}/work/${workId}`,
|
|
2706
|
+
body
|
|
2707
|
+
);
|
|
2708
|
+
output(w, `Updated ${w.work_id} \u2192 ${w.status}`);
|
|
2709
|
+
} catch (err) {
|
|
2710
|
+
handleError(err);
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
);
|
|
2714
|
+
cmd.command("tick <orgId>").description("Thin Loop tick (lists open work, emits org.loop_tick)").action(async (orgId) => {
|
|
2715
|
+
try {
|
|
2716
|
+
const res = await acnPost(
|
|
2717
|
+
`/orgs/${orgId}/loop/tick`,
|
|
2718
|
+
{}
|
|
2719
|
+
);
|
|
2720
|
+
output(res, `Loop tick: ${res.open_count} open work item(s)`);
|
|
2721
|
+
} catch (err) {
|
|
2722
|
+
handleError(err);
|
|
2723
|
+
}
|
|
2724
|
+
});
|
|
2725
|
+
return cmd;
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2329
2728
|
// src/commands/follow.ts
|
|
2330
|
-
var
|
|
2331
|
-
function
|
|
2729
|
+
var import_commander15 = require("commander");
|
|
2730
|
+
function requireAgentId6() {
|
|
2332
2731
|
const config = loadConfig();
|
|
2333
2732
|
if (!config.api_key) {
|
|
2334
2733
|
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
@@ -2350,9 +2749,9 @@ function formatAgent2(a, i) {
|
|
|
2350
2749
|
].join("\n");
|
|
2351
2750
|
}
|
|
2352
2751
|
function followCommand() {
|
|
2353
|
-
const cmd = new
|
|
2752
|
+
const cmd = new import_commander15.Command("follow").description("Follow/unfollow agents and inspect follow graph");
|
|
2354
2753
|
cmd.command("add <target_id>").description("Follow another agent").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (targetId, opts) => {
|
|
2355
|
-
const agentId = opts.agentId ??
|
|
2754
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
2356
2755
|
try {
|
|
2357
2756
|
const res = await acnPost(
|
|
2358
2757
|
`/agents/${agentId}/follows/${targetId}`
|
|
@@ -2364,7 +2763,7 @@ function followCommand() {
|
|
|
2364
2763
|
}
|
|
2365
2764
|
});
|
|
2366
2765
|
cmd.command("remove <target_id>").description("Unfollow an agent").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (targetId, opts) => {
|
|
2367
|
-
const agentId = opts.agentId ??
|
|
2766
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
2368
2767
|
try {
|
|
2369
2768
|
const res = await acnDelete(
|
|
2370
2769
|
`/agents/${agentId}/follows/${targetId}`
|
|
@@ -2376,7 +2775,7 @@ function followCommand() {
|
|
|
2376
2775
|
}
|
|
2377
2776
|
});
|
|
2378
2777
|
cmd.command("list").description("List agents you follow").option("--limit <n>", "Max results", parseInt).option("--offset <n>", "Pagination offset", parseInt).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
2379
|
-
const agentId = opts.agentId ??
|
|
2778
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
2380
2779
|
try {
|
|
2381
2780
|
const params = {};
|
|
2382
2781
|
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
@@ -2401,7 +2800,7 @@ function followCommand() {
|
|
|
2401
2800
|
}
|
|
2402
2801
|
});
|
|
2403
2802
|
cmd.command("followers").description("List agents that follow you").option("--limit <n>", "Max results", parseInt).option("--offset <n>", "Pagination offset", parseInt).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
2404
|
-
const agentId = opts.agentId ??
|
|
2803
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
2405
2804
|
try {
|
|
2406
2805
|
const params = {};
|
|
2407
2806
|
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
@@ -2426,7 +2825,7 @@ function followCommand() {
|
|
|
2426
2825
|
}
|
|
2427
2826
|
});
|
|
2428
2827
|
cmd.command("check <target_id>").description("Check whether you are following a specific agent").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (targetId, opts) => {
|
|
2429
|
-
const agentId = opts.agentId ??
|
|
2828
|
+
const agentId = opts.agentId ?? requireAgentId6();
|
|
2430
2829
|
try {
|
|
2431
2830
|
const res = await acnGet(
|
|
2432
2831
|
`/agents/${agentId}/follows/${targetId}`
|
|
@@ -2441,8 +2840,8 @@ function followCommand() {
|
|
|
2441
2840
|
}
|
|
2442
2841
|
|
|
2443
2842
|
// src/commands/wallet.ts
|
|
2444
|
-
var
|
|
2445
|
-
function
|
|
2843
|
+
var import_commander16 = require("commander");
|
|
2844
|
+
function requireAgentId7() {
|
|
2446
2845
|
const config = loadConfig();
|
|
2447
2846
|
if (!config.api_key) {
|
|
2448
2847
|
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
@@ -2458,7 +2857,7 @@ function parseCsv(value) {
|
|
|
2458
2857
|
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2459
2858
|
}
|
|
2460
2859
|
async function showWalletInfo(opts) {
|
|
2461
|
-
const agentId = opts.agentId ??
|
|
2860
|
+
const agentId = opts.agentId ?? requireAgentId7();
|
|
2462
2861
|
try {
|
|
2463
2862
|
const res = await acnGet(`/agents/${agentId}/wallets`);
|
|
2464
2863
|
const lines = [`Agent : ${res.agent_id}`];
|
|
@@ -2484,7 +2883,7 @@ async function showWalletInfo(opts) {
|
|
|
2484
2883
|
}
|
|
2485
2884
|
}
|
|
2486
2885
|
function walletCommand() {
|
|
2487
|
-
const cmd = new
|
|
2886
|
+
const cmd = new import_commander16.Command("wallet").description("View and manage agent's wallet & payment info");
|
|
2488
2887
|
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);
|
|
2489
2888
|
cmd.command("set-capability").description("Declare which payment methods, networks, and wallets you accept").requiredOption(
|
|
2490
2889
|
"--methods <csv>",
|
|
@@ -2494,7 +2893,7 @@ function walletCommand() {
|
|
|
2494
2893
|
`Wallet addresses by network, JSON, e.g. '{"ethereum":"0x..."}'`
|
|
2495
2894
|
).option("--no-accepts", "Disable accepting payments (default: enabled)").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(
|
|
2496
2895
|
async (opts) => {
|
|
2497
|
-
const agentId = opts.agentId ??
|
|
2896
|
+
const agentId = opts.agentId ?? requireAgentId7();
|
|
2498
2897
|
let walletMap = {};
|
|
2499
2898
|
if (opts.wallets) {
|
|
2500
2899
|
try {
|
|
@@ -2529,7 +2928,7 @@ function walletCommand() {
|
|
|
2529
2928
|
);
|
|
2530
2929
|
cmd.command("set-pricing").description("Set OpenAI-style per-million-token pricing for your agent (USD)").requiredOption("--input <usd>", "USD per 1M input tokens").requiredOption("--output <usd>", "USD per 1M output tokens").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(
|
|
2531
2930
|
async (opts) => {
|
|
2532
|
-
const agentId = opts.agentId ??
|
|
2931
|
+
const agentId = opts.agentId ?? requireAgentId7();
|
|
2533
2932
|
const inputPrice = Number(opts.input);
|
|
2534
2933
|
const outputPrice = Number(opts.output);
|
|
2535
2934
|
if (!Number.isFinite(inputPrice) || inputPrice < 0) {
|
|
@@ -2557,7 +2956,7 @@ function walletCommand() {
|
|
|
2557
2956
|
}
|
|
2558
2957
|
);
|
|
2559
2958
|
cmd.command("tasks").description("List the payment tasks the current agent is involved in").option("--status <s>", "Filter by status (e.g. created, payment_confirmed, task_completed)").option("--limit <n>", "Max number of tasks to return (default 50)").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
2560
|
-
const agentId = opts.agentId ??
|
|
2959
|
+
const agentId = opts.agentId ?? requireAgentId7();
|
|
2561
2960
|
const params = {};
|
|
2562
2961
|
if (opts.status) params.status = opts.status;
|
|
2563
2962
|
if (opts.limit !== void 0) {
|
|
@@ -2597,7 +2996,7 @@ function walletCommand() {
|
|
|
2597
2996
|
}
|
|
2598
2997
|
});
|
|
2599
2998
|
cmd.command("stats").description("Show the current agent's payment statistics").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
|
|
2600
|
-
const agentId = opts.agentId ??
|
|
2999
|
+
const agentId = opts.agentId ?? requireAgentId7();
|
|
2601
3000
|
try {
|
|
2602
3001
|
const res = await acnGet(`/payments/stats/${agentId}`);
|
|
2603
3002
|
const lines = [`Stats for ${agentId}:`];
|
|
@@ -2663,8 +3062,8 @@ function walletCommand() {
|
|
|
2663
3062
|
}
|
|
2664
3063
|
|
|
2665
3064
|
// src/commands/pay.ts
|
|
2666
|
-
var
|
|
2667
|
-
function
|
|
3065
|
+
var import_commander17 = require("commander");
|
|
3066
|
+
function requireAgentId8() {
|
|
2668
3067
|
const config = loadConfig();
|
|
2669
3068
|
if (!config.api_key) {
|
|
2670
3069
|
console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
|
|
@@ -2677,11 +3076,11 @@ function requireAgentId7() {
|
|
|
2677
3076
|
return config.agent_id;
|
|
2678
3077
|
}
|
|
2679
3078
|
function payCommand() {
|
|
2680
|
-
const cmd = new
|
|
2681
|
-
const createCmd = new
|
|
3079
|
+
const cmd = new import_commander17.Command("pay").description("Manage payment tasks between agents");
|
|
3080
|
+
const createCmd = new import_commander17.Command("create").description("Create a payment task to another agent");
|
|
2682
3081
|
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(
|
|
2683
3082
|
async (opts) => {
|
|
2684
|
-
const fromAgent =
|
|
3083
|
+
const fromAgent = requireAgentId8();
|
|
2685
3084
|
const amount = Number(opts.amount);
|
|
2686
3085
|
if (!Number.isFinite(amount) || amount <= 0) {
|
|
2687
3086
|
console.error("--amount must be a positive number.");
|
|
@@ -2724,7 +3123,7 @@ function payCommand() {
|
|
|
2724
3123
|
}
|
|
2725
3124
|
}
|
|
2726
3125
|
);
|
|
2727
|
-
const confirmCmd = new
|
|
3126
|
+
const confirmCmd = new import_commander17.Command("confirm").description(
|
|
2728
3127
|
"Confirm an external payment has been made (buyer only)"
|
|
2729
3128
|
);
|
|
2730
3129
|
confirmCmd.requiredOption("--task-id <id>", "Payment task ID to confirm").requiredOption(
|
|
@@ -2746,11 +3145,11 @@ function payCommand() {
|
|
|
2746
3145
|
handleError(err);
|
|
2747
3146
|
}
|
|
2748
3147
|
});
|
|
2749
|
-
const statusCmd = new
|
|
3148
|
+
const statusCmd = new import_commander17.Command("status").description(
|
|
2750
3149
|
"Show payment tasks for the authenticated agent"
|
|
2751
3150
|
);
|
|
2752
3151
|
statusCmd.option("--status <s>", "Filter by status (e.g. created, payment_confirmed)").option("--limit <n>", "Max results (default 50)", "50").action(async (opts) => {
|
|
2753
|
-
const agentId =
|
|
3152
|
+
const agentId = requireAgentId8();
|
|
2754
3153
|
try {
|
|
2755
3154
|
const res = await acnGet(
|
|
2756
3155
|
`/payments/tasks/agent/${agentId}`,
|
|
@@ -2769,7 +3168,7 @@ function payCommand() {
|
|
|
2769
3168
|
|
|
2770
3169
|
// src/index.ts
|
|
2771
3170
|
var { version } = require_package();
|
|
2772
|
-
var program = new
|
|
3171
|
+
var program = new import_commander18.Command();
|
|
2773
3172
|
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) => {
|
|
2774
3173
|
const opts = thisCommand.opts();
|
|
2775
3174
|
if (opts.json) setJsonMode(true);
|
|
@@ -2784,8 +3183,10 @@ program.addCommand(messageCommand());
|
|
|
2784
3183
|
program.addCommand(notifyCommand());
|
|
2785
3184
|
program.addCommand(inboxCommand());
|
|
2786
3185
|
program.addCommand(listenCommand());
|
|
3186
|
+
program.addCommand(deliveryCommand());
|
|
2787
3187
|
program.addCommand(sessionCommand());
|
|
2788
3188
|
program.addCommand(subnetCommand());
|
|
3189
|
+
program.addCommand(orgCommand());
|
|
2789
3190
|
program.addCommand(followCommand());
|
|
2790
3191
|
program.addCommand(walletCommand());
|
|
2791
3192
|
program.addCommand(payCommand());
|