@acnlabs/acn-cli 0.13.2 → 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.
Files changed (2) hide show
  1. package/dist/index.js +336 -46
  2. 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.2",
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 import_commander16 = require("commander");
90
+ var import_commander18 = require("commander");
91
91
 
92
92
  // src/output.ts
93
93
  var jsonMode = false;
@@ -1620,9 +1620,108 @@ function listenCommand() {
1620
1620
  return cmd;
1621
1621
  }
1622
1622
 
1623
- // src/commands/session.ts
1623
+ // src/commands/delivery.ts
1624
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
+ };
1625
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() {
1626
1725
  const config = loadConfig();
1627
1726
  if (!config.api_key) {
1628
1727
  console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
@@ -1666,12 +1765,12 @@ function formatEntry2(s, index) {
1666
1765
  return lines.join("\n");
1667
1766
  }
1668
1767
  function sessionCommand() {
1669
- const cmd = new import_commander11.Command("session").description(
1768
+ const cmd = new import_commander12.Command("session").description(
1670
1769
  "Real-time session layer: bidirectional channel between two agents"
1671
1770
  );
1672
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(
1673
1772
  async (targetId, opts) => {
1674
- requireAgentId3();
1773
+ requireAgentId4();
1675
1774
  try {
1676
1775
  const body = {};
1677
1776
  if (opts.ttlSeconds !== void 0) body.ttl_seconds = opts.ttlSeconds;
@@ -1692,7 +1791,7 @@ ${formatEntry2(res)}`
1692
1791
  }
1693
1792
  );
1694
1793
  cmd.command("accept <session_id>").description("Accept a pending session invitation (invitee only)").action(async (sessionId) => {
1695
- requireAgentId3();
1794
+ requireAgentId4();
1696
1795
  try {
1697
1796
  const res = await acnPost(`/sessions/${sessionId}/accept`);
1698
1797
  output(res, `Session accepted.
@@ -1702,7 +1801,7 @@ ${formatEntry2(res)}`);
1702
1801
  }
1703
1802
  });
1704
1803
  cmd.command("reject <session_id>").description("Reject a pending session invitation (invitee only)").action(async (sessionId) => {
1705
- requireAgentId3();
1804
+ requireAgentId4();
1706
1805
  try {
1707
1806
  const res = await acnPost(`/sessions/${sessionId}/reject`);
1708
1807
  output(res, `Session rejected.
@@ -1712,7 +1811,7 @@ ${formatEntry2(res)}`);
1712
1811
  }
1713
1812
  });
1714
1813
  cmd.command("close <session_id>").description("Close an active session (either party may close)").action(async (sessionId) => {
1715
- requireAgentId3();
1814
+ requireAgentId4();
1716
1815
  try {
1717
1816
  const res = await acnDelete(`/sessions/${sessionId}`);
1718
1817
  output(res, `Session closed.
@@ -1722,7 +1821,7 @@ ${formatEntry2(res)}`);
1722
1821
  }
1723
1822
  });
1724
1823
  cmd.command("pending").description("List pending session invitations addressed to you").action(async () => {
1725
- requireAgentId3();
1824
+ requireAgentId4();
1726
1825
  try {
1727
1826
  const res = await acnGet("/sessions/pending");
1728
1827
  const sessions = res.sessions ?? [];
@@ -1744,8 +1843,8 @@ ${formatEntry2(res)}`);
1744
1843
  }
1745
1844
 
1746
1845
  // src/commands/subnet.ts
1747
- var import_commander12 = require("commander");
1748
- function requireAgentId4() {
1846
+ var import_commander13 = require("commander");
1847
+ function requireAgentId5() {
1749
1848
  const config = loadConfig();
1750
1849
  if (!config.api_key) {
1751
1850
  console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
@@ -1832,7 +1931,7 @@ function formatSubnet(s, index) {
1832
1931
  return lines.join("\n");
1833
1932
  }
1834
1933
  function subnetCommand() {
1835
- const cmd = new import_commander12.Command("subnet").description("Manage ACN subnets");
1934
+ const cmd = new import_commander13.Command("subnet").description("Manage ACN subnets");
1836
1935
  cmd.command("list").description(
1837
1936
  "List subnets. Without --all/--parent shows only subnets you have joined."
1838
1937
  ).option("--all", "Show all public subnets on ACN (not just your own)").option(
@@ -1871,7 +1970,7 @@ function subnetCommand() {
1871
1970
  ` + subnets.map((s, i) => formatSubnet(s, i)).join("\n\n")
1872
1971
  );
1873
1972
  } else {
1874
- const agentId = opts.agentId ?? requireAgentId4();
1973
+ const agentId = opts.agentId ?? requireAgentId5();
1875
1974
  const res = await acnGet(
1876
1975
  `/subnets/${agentId}/subnets`
1877
1976
  );
@@ -1910,7 +2009,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
1910
2009
  cmd.command("join <subnet_id>").description(
1911
2010
  "Join a subnet. ADR-0004: branches on response shape (open/allowlist/auto-invite/pending)."
1912
2011
  ).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (subnetId, opts) => {
1913
- const agentId = opts.agentId ?? requireAgentId4();
2012
+ const agentId = opts.agentId ?? requireAgentId5();
1914
2013
  try {
1915
2014
  const res = await acnPost(
1916
2015
  `/agents/${agentId}/subnets/${subnetId}`
@@ -1921,7 +2020,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
1921
2020
  }
1922
2021
  });
1923
2022
  cmd.command("leave <subnet_id>").description("Leave a subnet").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (subnetId, opts) => {
1924
- const agentId = opts.agentId ?? requireAgentId4();
2023
+ const agentId = opts.agentId ?? requireAgentId5();
1925
2024
  try {
1926
2025
  const res = await acnDelete(
1927
2026
  `/agents/${agentId}/subnets/${subnetId}`
@@ -2049,7 +2148,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
2049
2148
  handleError(err);
2050
2149
  }
2051
2150
  });
2052
- const requests = new import_commander12.Command("requests").description(
2151
+ const requests = new import_commander13.Command("requests").description(
2053
2152
  "Manage join-requests for a subnet (ADR-0004)"
2054
2153
  );
2055
2154
  requests.command("list <subnet_id>").description(
@@ -2093,7 +2192,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
2093
2192
  requests.command("pending").description(
2094
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)."
2095
2194
  ).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
2096
- const agentId = opts.agentId ?? requireAgentId4();
2195
+ const agentId = opts.agentId ?? requireAgentId5();
2097
2196
  try {
2098
2197
  const subs = await acnGet(`/agents/${agentId}/subnets`);
2099
2198
  const subnetIds = subs.subnets ?? [];
@@ -2191,7 +2290,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
2191
2290
  }
2192
2291
  );
2193
2292
  cmd.addCommand(requests);
2194
- const invitations = new import_commander12.Command("invitations").description(
2293
+ const invitations = new import_commander13.Command("invitations").description(
2195
2294
  "Manage invitations on a subnet (ADR-0004)"
2196
2295
  );
2197
2296
  invitations.command("send <subnet_id>").description(
@@ -2246,7 +2345,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
2246
2345
  invitations.command("pending").description(
2247
2346
  "Invitee view: list pending invitations addressed to you across all subnets (backed by GET /agents/{aid}/subnet-invitations)."
2248
2347
  ).option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (opts) => {
2249
- const agentId = opts.agentId ?? requireAgentId4();
2348
+ const agentId = opts.agentId ?? requireAgentId5();
2250
2349
  try {
2251
2350
  const res = await acnGet(
2252
2351
  `/agents/${agentId}/subnet-invitations`
@@ -2327,7 +2426,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
2327
2426
  }
2328
2427
  );
2329
2428
  cmd.addCommand(invitations);
2330
- const allowlist = new import_commander12.Command("allowlist").description(
2429
+ const allowlist = new import_commander13.Command("allowlist").description(
2331
2430
  "Manage a subnet allowlist (ADR-0004)"
2332
2431
  );
2333
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(
@@ -2395,7 +2494,7 @@ ${JSON.stringify(res.agents, null, 2)}`);
2395
2494
  }
2396
2495
  );
2397
2496
  cmd.addCommand(allowlist);
2398
- const harness = new import_commander12.Command("harness").description("Manage Org Harness webhook for a subnet");
2497
+ const harness = new import_commander13.Command("harness").description("Manage Org Harness webhook for a subnet");
2399
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) => {
2400
2499
  const config = loadConfig();
2401
2500
  if (!config.api_key) {
@@ -2437,9 +2536,198 @@ ${JSON.stringify(res.agents, null, 2)}`);
2437
2536
  return cmd;
2438
2537
  }
2439
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
+
2440
2728
  // src/commands/follow.ts
2441
- var import_commander13 = require("commander");
2442
- function requireAgentId5() {
2729
+ var import_commander15 = require("commander");
2730
+ function requireAgentId6() {
2443
2731
  const config = loadConfig();
2444
2732
  if (!config.api_key) {
2445
2733
  console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
@@ -2461,9 +2749,9 @@ function formatAgent2(a, i) {
2461
2749
  ].join("\n");
2462
2750
  }
2463
2751
  function followCommand() {
2464
- const cmd = new import_commander13.Command("follow").description("Follow/unfollow agents and inspect follow graph");
2752
+ const cmd = new import_commander15.Command("follow").description("Follow/unfollow agents and inspect follow graph");
2465
2753
  cmd.command("add <target_id>").description("Follow another agent").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (targetId, opts) => {
2466
- const agentId = opts.agentId ?? requireAgentId5();
2754
+ const agentId = opts.agentId ?? requireAgentId6();
2467
2755
  try {
2468
2756
  const res = await acnPost(
2469
2757
  `/agents/${agentId}/follows/${targetId}`
@@ -2475,7 +2763,7 @@ function followCommand() {
2475
2763
  }
2476
2764
  });
2477
2765
  cmd.command("remove <target_id>").description("Unfollow an agent").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(async (targetId, opts) => {
2478
- const agentId = opts.agentId ?? requireAgentId5();
2766
+ const agentId = opts.agentId ?? requireAgentId6();
2479
2767
  try {
2480
2768
  const res = await acnDelete(
2481
2769
  `/agents/${agentId}/follows/${targetId}`
@@ -2487,7 +2775,7 @@ function followCommand() {
2487
2775
  }
2488
2776
  });
2489
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) => {
2490
- const agentId = opts.agentId ?? requireAgentId5();
2778
+ const agentId = opts.agentId ?? requireAgentId6();
2491
2779
  try {
2492
2780
  const params = {};
2493
2781
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -2512,7 +2800,7 @@ function followCommand() {
2512
2800
  }
2513
2801
  });
2514
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) => {
2515
- const agentId = opts.agentId ?? requireAgentId5();
2803
+ const agentId = opts.agentId ?? requireAgentId6();
2516
2804
  try {
2517
2805
  const params = {};
2518
2806
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -2537,7 +2825,7 @@ function followCommand() {
2537
2825
  }
2538
2826
  });
2539
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) => {
2540
- const agentId = opts.agentId ?? requireAgentId5();
2828
+ const agentId = opts.agentId ?? requireAgentId6();
2541
2829
  try {
2542
2830
  const res = await acnGet(
2543
2831
  `/agents/${agentId}/follows/${targetId}`
@@ -2552,8 +2840,8 @@ function followCommand() {
2552
2840
  }
2553
2841
 
2554
2842
  // src/commands/wallet.ts
2555
- var import_commander14 = require("commander");
2556
- function requireAgentId6() {
2843
+ var import_commander16 = require("commander");
2844
+ function requireAgentId7() {
2557
2845
  const config = loadConfig();
2558
2846
  if (!config.api_key) {
2559
2847
  console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
@@ -2569,7 +2857,7 @@ function parseCsv(value) {
2569
2857
  return value.split(",").map((s) => s.trim()).filter(Boolean);
2570
2858
  }
2571
2859
  async function showWalletInfo(opts) {
2572
- const agentId = opts.agentId ?? requireAgentId6();
2860
+ const agentId = opts.agentId ?? requireAgentId7();
2573
2861
  try {
2574
2862
  const res = await acnGet(`/agents/${agentId}/wallets`);
2575
2863
  const lines = [`Agent : ${res.agent_id}`];
@@ -2595,7 +2883,7 @@ async function showWalletInfo(opts) {
2595
2883
  }
2596
2884
  }
2597
2885
  function walletCommand() {
2598
- const cmd = new import_commander14.Command("wallet").description("View and manage agent's wallet & payment info");
2886
+ const cmd = new import_commander16.Command("wallet").description("View and manage agent's wallet & payment info");
2599
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);
2600
2888
  cmd.command("set-capability").description("Declare which payment methods, networks, and wallets you accept").requiredOption(
2601
2889
  "--methods <csv>",
@@ -2605,7 +2893,7 @@ function walletCommand() {
2605
2893
  `Wallet addresses by network, JSON, e.g. '{"ethereum":"0x..."}'`
2606
2894
  ).option("--no-accepts", "Disable accepting payments (default: enabled)").option("-i, --agent-id <id>", "Agent ID (defaults to config)").action(
2607
2895
  async (opts) => {
2608
- const agentId = opts.agentId ?? requireAgentId6();
2896
+ const agentId = opts.agentId ?? requireAgentId7();
2609
2897
  let walletMap = {};
2610
2898
  if (opts.wallets) {
2611
2899
  try {
@@ -2640,7 +2928,7 @@ function walletCommand() {
2640
2928
  );
2641
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(
2642
2930
  async (opts) => {
2643
- const agentId = opts.agentId ?? requireAgentId6();
2931
+ const agentId = opts.agentId ?? requireAgentId7();
2644
2932
  const inputPrice = Number(opts.input);
2645
2933
  const outputPrice = Number(opts.output);
2646
2934
  if (!Number.isFinite(inputPrice) || inputPrice < 0) {
@@ -2668,7 +2956,7 @@ function walletCommand() {
2668
2956
  }
2669
2957
  );
2670
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) => {
2671
- const agentId = opts.agentId ?? requireAgentId6();
2959
+ const agentId = opts.agentId ?? requireAgentId7();
2672
2960
  const params = {};
2673
2961
  if (opts.status) params.status = opts.status;
2674
2962
  if (opts.limit !== void 0) {
@@ -2708,7 +2996,7 @@ function walletCommand() {
2708
2996
  }
2709
2997
  });
2710
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) => {
2711
- const agentId = opts.agentId ?? requireAgentId6();
2999
+ const agentId = opts.agentId ?? requireAgentId7();
2712
3000
  try {
2713
3001
  const res = await acnGet(`/payments/stats/${agentId}`);
2714
3002
  const lines = [`Stats for ${agentId}:`];
@@ -2774,8 +3062,8 @@ function walletCommand() {
2774
3062
  }
2775
3063
 
2776
3064
  // src/commands/pay.ts
2777
- var import_commander15 = require("commander");
2778
- function requireAgentId7() {
3065
+ var import_commander17 = require("commander");
3066
+ function requireAgentId8() {
2779
3067
  const config = loadConfig();
2780
3068
  if (!config.api_key) {
2781
3069
  console.error("No API key found. Run `acn join` first or `acn config set api-key <key>`.");
@@ -2788,11 +3076,11 @@ function requireAgentId7() {
2788
3076
  return config.agent_id;
2789
3077
  }
2790
3078
  function payCommand() {
2791
- const cmd = new import_commander15.Command("pay").description("Manage payment tasks between agents");
2792
- const createCmd = new import_commander15.Command("create").description("Create a payment task to another agent");
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");
2793
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(
2794
3082
  async (opts) => {
2795
- const fromAgent = requireAgentId7();
3083
+ const fromAgent = requireAgentId8();
2796
3084
  const amount = Number(opts.amount);
2797
3085
  if (!Number.isFinite(amount) || amount <= 0) {
2798
3086
  console.error("--amount must be a positive number.");
@@ -2835,7 +3123,7 @@ function payCommand() {
2835
3123
  }
2836
3124
  }
2837
3125
  );
2838
- const confirmCmd = new import_commander15.Command("confirm").description(
3126
+ const confirmCmd = new import_commander17.Command("confirm").description(
2839
3127
  "Confirm an external payment has been made (buyer only)"
2840
3128
  );
2841
3129
  confirmCmd.requiredOption("--task-id <id>", "Payment task ID to confirm").requiredOption(
@@ -2857,11 +3145,11 @@ function payCommand() {
2857
3145
  handleError(err);
2858
3146
  }
2859
3147
  });
2860
- const statusCmd = new import_commander15.Command("status").description(
3148
+ const statusCmd = new import_commander17.Command("status").description(
2861
3149
  "Show payment tasks for the authenticated agent"
2862
3150
  );
2863
3151
  statusCmd.option("--status <s>", "Filter by status (e.g. created, payment_confirmed)").option("--limit <n>", "Max results (default 50)", "50").action(async (opts) => {
2864
- const agentId = requireAgentId7();
3152
+ const agentId = requireAgentId8();
2865
3153
  try {
2866
3154
  const res = await acnGet(
2867
3155
  `/payments/tasks/agent/${agentId}`,
@@ -2880,7 +3168,7 @@ function payCommand() {
2880
3168
 
2881
3169
  // src/index.ts
2882
3170
  var { version } = require_package();
2883
- var program = new import_commander16.Command();
3171
+ var program = new import_commander18.Command();
2884
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) => {
2885
3173
  const opts = thisCommand.opts();
2886
3174
  if (opts.json) setJsonMode(true);
@@ -2895,8 +3183,10 @@ program.addCommand(messageCommand());
2895
3183
  program.addCommand(notifyCommand());
2896
3184
  program.addCommand(inboxCommand());
2897
3185
  program.addCommand(listenCommand());
3186
+ program.addCommand(deliveryCommand());
2898
3187
  program.addCommand(sessionCommand());
2899
3188
  program.addCommand(subnetCommand());
3189
+ program.addCommand(orgCommand());
2900
3190
  program.addCommand(followCommand());
2901
3191
  program.addCommand(walletCommand());
2902
3192
  program.addCommand(payCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acnlabs/acn-cli",
3
- "version": "0.13.2",
3
+ "version": "0.13.3",
4
4
  "description": "Official CLI for ACN (Agent Collaboration Network) — zero-integration agent access",
5
5
  "main": "dist/index.js",
6
6
  "bin": {