agent-comms 8.6.2 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +27 -1
  4. package/dist/account-cli.d.ts +34 -0
  5. package/dist/account-cli.d.ts.map +1 -0
  6. package/dist/account-cli.js +140 -0
  7. package/dist/account-cli.js.map +1 -0
  8. package/dist/account-join-cli.d.ts +17 -0
  9. package/dist/account-join-cli.d.ts.map +1 -0
  10. package/dist/account-join-cli.js +140 -0
  11. package/dist/account-join-cli.js.map +1 -0
  12. package/dist/bridges/mcp/server.d.ts +1 -4
  13. package/dist/bridges/mcp/server.d.ts.map +1 -1
  14. package/dist/bridges/mcp/server.js +1 -1
  15. package/dist/bridges/mcp/server.js.map +1 -1
  16. package/dist/cli.d.ts +4 -0
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +24 -1
  19. package/dist/cli.js.map +1 -1
  20. package/dist/core/account-bundle.d.ts +22 -0
  21. package/dist/core/account-bundle.d.ts.map +1 -0
  22. package/dist/core/account-bundle.js +143 -0
  23. package/dist/core/account-bundle.js.map +1 -0
  24. package/dist/core/account-join.d.ts +62 -0
  25. package/dist/core/account-join.d.ts.map +1 -0
  26. package/dist/core/account-join.js +150 -0
  27. package/dist/core/account-join.js.map +1 -0
  28. package/dist/core/account-ledger-crypto.d.ts +28 -0
  29. package/dist/core/account-ledger-crypto.d.ts.map +1 -0
  30. package/dist/core/account-ledger-crypto.js +101 -0
  31. package/dist/core/account-ledger-crypto.js.map +1 -0
  32. package/dist/core/account-ledger-store.d.ts +21 -0
  33. package/dist/core/account-ledger-store.d.ts.map +1 -0
  34. package/dist/core/account-ledger-store.js +34 -0
  35. package/dist/core/account-ledger-store.js.map +1 -0
  36. package/dist/core/account-ledger.d.ts +80 -0
  37. package/dist/core/account-ledger.d.ts.map +1 -0
  38. package/dist/core/account-ledger.js +247 -0
  39. package/dist/core/account-ledger.js.map +1 -0
  40. package/dist/core/bridge-mesh.d.ts.map +1 -1
  41. package/dist/core/bridge-mesh.js +12 -1
  42. package/dist/core/bridge-mesh.js.map +1 -1
  43. package/dist/core/data-frame-routing.d.ts +50 -3
  44. package/dist/core/data-frame-routing.d.ts.map +1 -1
  45. package/dist/core/data-frame-routing.js +112 -5
  46. package/dist/core/data-frame-routing.js.map +1 -1
  47. package/dist/core/device-membership.d.ts +8 -8
  48. package/dist/core/device-membership.d.ts.map +1 -1
  49. package/dist/core/device-membership.js +17 -16
  50. package/dist/core/device-membership.js.map +1 -1
  51. package/dist/core/dm-send-delegation.d.ts +4 -4
  52. package/dist/core/dm-send-delegation.d.ts.map +1 -1
  53. package/dist/core/dm-send-delegation.js +2 -3
  54. package/dist/core/dm-send-delegation.js.map +1 -1
  55. package/dist/core/group-proofs.d.ts +5 -0
  56. package/dist/core/group-proofs.d.ts.map +1 -1
  57. package/dist/core/group-proofs.js +4 -0
  58. package/dist/core/group-proofs.js.map +1 -1
  59. package/dist/core/identity-store.d.ts.map +1 -1
  60. package/dist/core/identity-store.js +2 -62
  61. package/dist/core/identity-store.js.map +1 -1
  62. package/dist/core/issuer-identity-file.d.ts +4 -0
  63. package/dist/core/issuer-identity-file.d.ts.map +1 -1
  64. package/dist/core/issuer-identity-file.js +7 -5
  65. package/dist/core/issuer-identity-file.js.map +1 -1
  66. package/dist/core/ledger-lock.d.ts +12 -0
  67. package/dist/core/ledger-lock.d.ts.map +1 -0
  68. package/dist/core/ledger-lock.js +62 -0
  69. package/dist/core/ledger-lock.js.map +1 -0
  70. package/dist/core/membership-proofs.d.ts +7 -0
  71. package/dist/core/membership-proofs.d.ts.map +1 -1
  72. package/dist/core/membership-proofs.js +26 -1
  73. package/dist/core/membership-proofs.js.map +1 -1
  74. package/dist/core/mesh-store-shared.d.ts +4 -1
  75. package/dist/core/mesh-store-shared.d.ts.map +1 -1
  76. package/dist/core/mesh-store-shared.js.map +1 -1
  77. package/dist/core/mesh-store.d.ts +17 -8
  78. package/dist/core/mesh-store.d.ts.map +1 -1
  79. package/dist/core/mesh-store.js +41 -41
  80. package/dist/core/mesh-store.js.map +1 -1
  81. package/dist/core/peer-versions.d.ts +11 -0
  82. package/dist/core/peer-versions.d.ts.map +1 -1
  83. package/dist/core/peer-versions.js +9 -0
  84. package/dist/core/peer-versions.js.map +1 -1
  85. package/dist/core/pid-lock-file.d.ts +20 -0
  86. package/dist/core/pid-lock-file.d.ts.map +1 -0
  87. package/dist/core/pid-lock-file.js +115 -0
  88. package/dist/core/pid-lock-file.js.map +1 -0
  89. package/dist/core/room-lifecycle.d.ts +2 -2
  90. package/dist/core/room-lifecycle.d.ts.map +1 -1
  91. package/dist/core/room-lifecycle.js +18 -19
  92. package/dist/core/room-lifecycle.js.map +1 -1
  93. package/dist/core/transport-queries.d.ts +11 -0
  94. package/dist/core/transport-queries.d.ts.map +1 -0
  95. package/dist/core/transport-queries.js +30 -0
  96. package/dist/core/transport-queries.js.map +1 -0
  97. package/dist/core/user-identity.d.ts +23 -18
  98. package/dist/core/user-identity.d.ts.map +1 -1
  99. package/dist/core/user-identity.js +99 -61
  100. package/dist/core/user-identity.js.map +1 -1
  101. package/dist/core/wire-mesh-transport-options.d.ts +11 -2
  102. package/dist/core/wire-mesh-transport-options.d.ts.map +1 -1
  103. package/dist/core/wire-mesh-transport-options.js.map +1 -1
  104. package/dist/core/wire-mesh-transport.d.ts +4 -6
  105. package/dist/core/wire-mesh-transport.d.ts.map +1 -1
  106. package/dist/core/wire-mesh-transport.js +16 -20
  107. package/dist/core/wire-mesh-transport.js.map +1 -1
  108. package/dist/test/account-join.integration.test.d.ts +5 -0
  109. package/dist/test/account-join.integration.test.d.ts.map +1 -0
  110. package/dist/test/account-join.integration.test.js +183 -0
  111. package/dist/test/account-join.integration.test.js.map +1 -0
  112. package/dist/test/account-ledger-lock-worker.d.ts +9 -0
  113. package/dist/test/account-ledger-lock-worker.d.ts.map +1 -0
  114. package/dist/test/account-ledger-lock-worker.js +34 -0
  115. package/dist/test/account-ledger-lock-worker.js.map +1 -0
  116. package/dist/test/account-ledger-lock.integration.test.d.ts +5 -0
  117. package/dist/test/account-ledger-lock.integration.test.d.ts.map +1 -0
  118. package/dist/test/account-ledger-lock.integration.test.js +71 -0
  119. package/dist/test/account-ledger-lock.integration.test.js.map +1 -0
  120. package/dist/test/account-ledger-replication.integration.test.d.ts +5 -0
  121. package/dist/test/account-ledger-replication.integration.test.d.ts.map +1 -0
  122. package/dist/test/account-ledger-replication.integration.test.js +145 -0
  123. package/dist/test/account-ledger-replication.integration.test.js.map +1 -0
  124. package/dist/test/account-ledger.unit.test.d.ts +5 -0
  125. package/dist/test/account-ledger.unit.test.d.ts.map +1 -0
  126. package/dist/test/account-ledger.unit.test.js +317 -0
  127. package/dist/test/account-ledger.unit.test.js.map +1 -0
  128. package/dist/test/account-transfer.unit.test.d.ts +5 -0
  129. package/dist/test/account-transfer.unit.test.d.ts.map +1 -0
  130. package/dist/test/account-transfer.unit.test.js +204 -0
  131. package/dist/test/account-transfer.unit.test.js.map +1 -0
  132. package/dist/test/delivery-engine-delivery.unit.test.js +1 -0
  133. package/dist/test/delivery-engine-delivery.unit.test.js.map +1 -1
  134. package/dist/test/delivery-engine-directed-notify.unit.test.js +1 -0
  135. package/dist/test/delivery-engine-directed-notify.unit.test.js.map +1 -1
  136. package/dist/test/delivery-engine-own-agent.unit.test.js +1 -0
  137. package/dist/test/delivery-engine-own-agent.unit.test.js.map +1 -1
  138. package/dist/test/delivery-engine.unit.test.js +1 -0
  139. package/dist/test/delivery-engine.unit.test.js.map +1 -1
  140. package/dist/test/device-membership.unit.test.js +81 -30
  141. package/dist/test/device-membership.unit.test.js.map +1 -1
  142. package/dist/test/dm-send-delegation.unit.test.js +25 -14
  143. package/dist/test/dm-send-delegation.unit.test.js.map +1 -1
  144. package/dist/test/dm-send-principal-delegation.integration.test.js +9 -2
  145. package/dist/test/dm-send-principal-delegation.integration.test.js.map +1 -1
  146. package/dist/test/hidden-line.unit.test.d.ts +5 -0
  147. package/dist/test/hidden-line.unit.test.d.ts.map +1 -0
  148. package/dist/test/hidden-line.unit.test.js +40 -0
  149. package/dist/test/hidden-line.unit.test.js.map +1 -0
  150. package/dist/test/identity-restart.integration.test.js +8 -1
  151. package/dist/test/identity-restart.integration.test.js.map +1 -1
  152. package/dist/test/mcp-stdout-channel.integration.test.js +2 -2
  153. package/dist/test/mcp-stdout-channel.integration.test.js.map +1 -1
  154. package/dist/test/mesh-smoke.runner.js +2 -1
  155. package/dist/test/mesh-smoke.runner.js.map +1 -1
  156. package/dist/test/room-join-admission.integration.test.js +8 -1
  157. package/dist/test/room-join-admission.integration.test.js.map +1 -1
  158. package/dist/test/room-lifecycle-bare-name.unit.test.js +1 -0
  159. package/dist/test/room-lifecycle-bare-name.unit.test.js.map +1 -1
  160. package/dist/test/room-lifecycle-membership.unit.test.js +1 -0
  161. package/dist/test/room-lifecycle-membership.unit.test.js.map +1 -1
  162. package/dist/test/room-lifecycle-remote.unit.test.js +1 -0
  163. package/dist/test/room-lifecycle-remote.unit.test.js.map +1 -1
  164. package/dist/test/room-lifecycle.unit.test.js +1 -0
  165. package/dist/test/room-lifecycle.unit.test.js.map +1 -1
  166. package/dist/test/room-messaging-durable-send.unit.test.js +1 -0
  167. package/dist/test/room-messaging-durable-send.unit.test.js.map +1 -1
  168. package/dist/test/room-messaging.unit.test.js +1 -0
  169. package/dist/test/room-messaging.unit.test.js.map +1 -1
  170. package/dist/test/room-protocol-notify.unit.test.js +1 -0
  171. package/dist/test/room-protocol-notify.unit.test.js.map +1 -1
  172. package/dist/test/room-protocol.helper.d.ts.map +1 -1
  173. package/dist/test/room-protocol.helper.js +1 -0
  174. package/dist/test/room-protocol.helper.js.map +1 -1
  175. package/dist/test/room-send-retry.integration.test.js +8 -1
  176. package/dist/test/room-send-retry.integration.test.js.map +1 -1
  177. package/dist/test/test-transport.d.ts +9 -0
  178. package/dist/test/test-transport.d.ts.map +1 -1
  179. package/dist/test/test-transport.js +14 -5
  180. package/dist/test/test-transport.js.map +1 -1
  181. package/dist/test/user-identity.unit.test.js +75 -106
  182. package/dist/test/user-identity.unit.test.js.map +1 -1
  183. package/package.json +1 -1
@@ -15,7 +15,7 @@
15
15
  "source": "url",
16
16
  "url": "https://github.com/ExaDev/agent-comms.git"
17
17
  },
18
- "version": "8.6.2"
18
+ "version": "8.7.0"
19
19
  }
20
20
  ]
21
21
  }
@@ -18,5 +18,5 @@
18
18
  },
19
19
  "name": "agent-comms",
20
20
  "repository": "https://github.com/ExaDev/agent-comms",
21
- "version": "8.6.2"
21
+ "version": "8.7.0"
22
22
  }
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/agent-comms)
4
4
  [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/agent-comms)
5
- [![version](https://img.shields.io/badge/version-8.6.2-blue)](https://github.com/ExaDev/agent-comms/releases/tag/v8.6.2)
5
+ [![version](https://img.shields.io/badge/version-8.7.0-blue)](https://github.com/ExaDev/agent-comms/releases/tag/v8.7.0)
6
6
  [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/agent-comms/ci.yml?branch=main)](https://github.com/ExaDev/agent-comms/actions)
7
7
 
8
8
  Cross-harness communication mesh for LLM agents: rooms, DMs, presence, and visibility over TCP with zero filesystem dependencies.
@@ -519,3 +519,29 @@ agent_comms({
519
519
  ```
520
520
 
521
521
  The fingerprint is never a trust anchor supplied by the keyserver — it's the thing the redeemer already independently trusts (from a business card, a prior verification, wherever), and the redeemer's own check is that the key actually fetched or pasted verifies to that exact fingerprint, not merely that _some_ key was found. Redemption never calls back to whoever generated the code: the whole point is bootstrapping trust before any connection between the two devices exists.
522
+
523
+ ### One account on several machines
524
+
525
+ Your user principal is your account: the key in `~/.agent-comms/user-identity.json` that signs your devices' membership proofs and every DM grant you issue. The same account can live on several machines, and each of them then vouches for its own devices as that one principal, so anyone who trusts your principal covers every machine you run with no per-machine or per-pair step.
526
+
527
+ A new machine joins with one deliberate act. On a machine that already holds the account, issue an invite, which is a connection code, and carry it to the new machine out of band:
528
+
529
+ ```bash
530
+ npx agent-comms account invite # on a machine that holds the account; keep it running
531
+ npx agent-comms account join # on the new machine; paste the invite at the prompt
532
+ ```
533
+
534
+ Both are commands you run, not `agent_comms` tool actions: an invite is the account key to whoever redeems it first, and a join replaces the account the machine holds, so nothing an agent is told can do either, and the invite is printed only to your terminal, never into an agent's transcript. `join` reads the invite at a prompt that does not echo, so it stays out of shell history.
535
+
536
+ `account invite` runs a store of its own and keeps it up until the invite is redeemed or expires, since the issuing device keeps invites only in memory and answers each one once and never after it expires. An invite is valid for as long as a connection code, and can be made shorter with `--ttl-minutes <n>` but not longer. Redeeming it trusts the issuing device, exactly as `gateway_redeem_connection_code` does, then asks that device for the account key over the mesh's end-to-end authenticated request path, directly or relayed by the hub; the key comes back sealed under a key derived from the invite, which only its holder can open. A join the issuing device refuses or never answers withdraws that trust again, so a failed join leaves the new machine trusting no one it did not trust before. An invite can be PGP-signed with `--sign-key <armored private key file>`, and a signed one is checked on `join` against `--public-key <file>`, pinned to `--fingerprint <hex>` when you give one. Issuing an invite also trusts your own principal on the issuing machine, and joining trusts it on the new one, so the two list each other's devices from then on. The account the new machine held before is kept beside it as `user-identity.replaced-<id>.json`, since its key is still the only one that can revoke what it issued, and the machine's running bridges pick up the account when they restart.
537
+
538
+ To copy the account without the mesh, export it to a passphrase-sealed file and import that on the other machine. The key is never printed; the passphrase is read from `AGENT_COMMS_ACCOUNT_PASSPHRASE` or asked for without echo, and the file is written owner-only and never over an existing one:
539
+
540
+ ```bash
541
+ npx agent-comms account export ~/account.bundle # on a machine that holds the account
542
+ npx agent-comms account import ~/account.bundle # on the other machine, then delete the file
543
+ ```
544
+
545
+ Copy the account this way or by joining, never by copying `~/.agent-comms` between machines: each machine keeps a writer id of its own for the grant ledger below, and two machines sharing one would corrupt it.
546
+
547
+ Every grant your account issues, and every revocation of one, is recorded in a replicated ledger rather than on the machine that minted it: each machine appends to a data-domain log of its own (wire-mesh's replicated issuer grant ledger pattern, `spec/PATTERNS.md`), and the logs replicate to every machine holding the account, so `dm_revoke` on any of them finds and revokes a grant another one issued. Entries are sealed under a key derived from the account key, so a device that stores or relays them without holding the account sees only ciphertext, and writing to the ledger still needs the account's private key. The ledger replicates over direct peer connections (the local mesh, or machines that reach each other directly), not yet through the relay hub, which does not forward data-domain frames between devices; a revocation itself is also announced to every connected peer the moment it is made. Grants a build before the ledger recorded in `user-identity.json` are moved into it the first time a bridge starts, with nothing to do by hand.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `agent-comms account <export|import|invite|join>` (agent-comms#344): the deliberate, consented ways the account key that lets one user principal span machines leaves or reaches a machine. Export and import carry the key as a passphrase-sealed bundle (account-bundle.ts), written to a new owner-only file and never printed; the passphrase comes from AGENT_COMMS_ACCOUNT_PASSPHRASE when set, else from a prompt that does not echo. Invite and join carry it over the mesh (account-join-cli.ts). All four are commands a person runs, never agent_comms tool actions, so nothing an agent is told can move the account and no key or invite lands in an agent's transcript.
3
+ */
4
+ import { type AccountCliStore } from "./account-join-cli.js";
5
+ import { type UserIdentityOptions } from "./core/user-identity.js";
6
+ /** Where a script supplies the passphrase instead of typing it. */
7
+ export declare const ACCOUNT_PASSPHRASE_ENV = "AGENT_COMMS_ACCOUNT_PASSPHRASE";
8
+ export declare const ACCOUNT_USAGE: string;
9
+ export interface AccountCliIo {
10
+ /** Reads a secret (a passphrase, an invite) without echoing it. */
11
+ readSecret: (prompt: string) => Promise<string>;
12
+ log: (line: string) => void;
13
+ env: Readonly<Record<string, string | undefined>>;
14
+ /** Starts a store on this machine's mesh for invite and join, which need one to reach the other machine. */
15
+ openStore: () => Promise<AccountCliStore>;
16
+ }
17
+ /** Runs one `account` subcommand. Throws with a message fit to show the person on any failure: an unknown subcommand or option, a file that already exists (an export never overwrites), a weak or wrong passphrase, a file that is not a bundle, or an invite that is malformed or refused. */
18
+ export declare function runAccountCommand(args: readonly string[], io: Readonly<AccountCliIo>, userIdentityOptions?: Readonly<UserIdentityOptions>): Promise<void>;
19
+ /** What one keypress does to a hidden line being typed. */
20
+ export type HiddenLineStep = {
21
+ kind: "typing";
22
+ value: string;
23
+ } | {
24
+ kind: "done";
25
+ value: string;
26
+ } | {
27
+ kind: "failed";
28
+ message: string;
29
+ };
30
+ /** Applies one character typed at a hidden prompt to the line so far. Enter, or Ctrl-D on a line with something on it, ends the line; Ctrl-C, and Ctrl-D on an empty line, cancel it. Backspace and Delete remove the last character. An escape sequence (an arrow or function key) or any other control character is refused rather than kept, since it would end up in the value invisibly and could never be typed the same way again. */
31
+ export declare function hiddenLineStep(value: string, character: string): HiddenLineStep;
32
+ /** Reads one line from a terminal with echo off, keystroke by keystroke as hiddenLineStep describes. Throws when stdin is not a terminal, since there is nowhere to prompt; a bundle passphrase can then come from ACCOUNT_PASSPHRASE_ENV instead. */
33
+ export declare function readHiddenLine(prompt: string): Promise<string>;
34
+ //# sourceMappingURL=account-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-cli.d.ts","sourceRoot":"","sources":["../src/account-cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAC;AAEjC,mEAAmE;AACnE,eAAO,MAAM,sBAAsB,mCAAmC,CAAC;AAKvE,eAAO,MAAM,aAAa,QAKd,CAAC;AAEb,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAClD,4GAA4G;IAC5G,SAAS,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;CAC3C;AAmBD,gSAAgS;AAChS,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC1B,mBAAmB,GAAE,QAAQ,CAAC,mBAAmB,CAAM,GACtD,OAAO,CAAC,IAAI,CAAC,CA+Cf;AAED,2DAA2D;AAC3D,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AASxC,6aAA6a;AAC7a,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,cAAc,CA0BhB;AAED,sPAAsP;AACtP,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoCpE"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * `agent-comms account <export|import|invite|join>` (agent-comms#344): the deliberate, consented ways the account key that lets one user principal span machines leaves or reaches a machine. Export and import carry the key as a passphrase-sealed bundle (account-bundle.ts), written to a new owner-only file and never printed; the passphrase comes from AGENT_COMMS_ACCOUNT_PASSPHRASE when set, else from a prompt that does not echo. Invite and join carry it over the mesh (account-join-cli.ts). All four are commands a person runs, never agent_comms tool actions, so nothing an agent is told can move the account and no key or invite lands in an agent's transcript.
3
+ */
4
+ import * as fs from "node:fs";
5
+ import { deviceIdToHex } from "wire-mesh-core/domain/device-id";
6
+ import { inviteToAccount, joinAccount, } from "./account-join-cli.js";
7
+ import { openAccountBundle, sealAccountBundle } from "./core/account-bundle.js";
8
+ import { importAccountKey, loadOrCreateUserIdentity, readAccountPrivateKey, } from "./core/user-identity.js";
9
+ /** Where a script supplies the passphrase instead of typing it. */
10
+ export const ACCOUNT_PASSPHRASE_ENV = "AGENT_COMMS_ACCOUNT_PASSPHRASE";
11
+ /** A bundle holds the account key, so its file is readable by its owner alone. */
12
+ const BUNDLE_FILE_MODE = 0o600;
13
+ export const ACCOUNT_USAGE = [
14
+ "Usage: agent-comms account export <file>",
15
+ " agent-comms account import <file>",
16
+ " agent-comms account invite [--ttl-minutes <n>] [--sign-key <file>]",
17
+ " agent-comms account join [--public-key <file>] [--fingerprint <hex>]",
18
+ ].join("\n");
19
+ async function passphrase(io, confirm) {
20
+ const fromEnv = io.env[ACCOUNT_PASSPHRASE_ENV];
21
+ if (fromEnv !== undefined)
22
+ return fromEnv;
23
+ const first = await io.readSecret("Account bundle passphrase: ");
24
+ if (!confirm)
25
+ return first;
26
+ const second = await io.readSecret("Repeat the passphrase: ");
27
+ if (first !== second)
28
+ throw new Error("The passphrases do not match");
29
+ return first;
30
+ }
31
+ function principalOf(identity) {
32
+ return deviceIdToHex(Uint8Array.from(identity.deviceId));
33
+ }
34
+ /** Runs one `account` subcommand. Throws with a message fit to show the person on any failure: an unknown subcommand or option, a file that already exists (an export never overwrites), a weak or wrong passphrase, a file that is not a bundle, or an invite that is malformed or refused. */
35
+ export async function runAccountCommand(args, io, userIdentityOptions = {}) {
36
+ const [subcommand, ...rest] = args;
37
+ if (subcommand === "invite") {
38
+ await inviteToAccount(rest, io);
39
+ return;
40
+ }
41
+ if (subcommand === "join") {
42
+ await joinAccount(rest, io);
43
+ return;
44
+ }
45
+ const [file, ...extra] = rest;
46
+ if (file === undefined || extra.length > 0)
47
+ throw new Error(ACCOUNT_USAGE);
48
+ if (subcommand === "export") {
49
+ const identity = loadOrCreateUserIdentity(userIdentityOptions);
50
+ const bundle = sealAccountBundle(readAccountPrivateKey(userIdentityOptions), await passphrase(io, true));
51
+ fs.writeFileSync(file, `${bundle}\n`, {
52
+ encoding: "utf-8",
53
+ mode: BUNDLE_FILE_MODE,
54
+ flag: "wx",
55
+ });
56
+ io.log(`Exported account ${principalOf(identity)} to ${file}. Anyone with this file and its passphrase holds the account; import it on your other machine with \`agent-comms account import ${file}\`, then delete it.`);
57
+ return;
58
+ }
59
+ if (subcommand === "import") {
60
+ const privateKeyPem = openAccountBundle(fs.readFileSync(file, "utf-8"), await passphrase(io, false));
61
+ const { identity, replacedFile } = importAccountKey(userIdentityOptions, privateKeyPem);
62
+ io.log(`This machine now holds account ${principalOf(identity)}.`);
63
+ if (replacedFile !== undefined) {
64
+ io.log(`The account it held before was moved to ${replacedFile}; it is still the only key that can revoke what that account issued.`);
65
+ }
66
+ io.log("Restart running agent-comms bridges so they use it.");
67
+ return;
68
+ }
69
+ throw new Error(ACCOUNT_USAGE);
70
+ }
71
+ const END_OF_TEXT = "\u0003";
72
+ const END_OF_TRANSMISSION = "\u0004";
73
+ const BACKSPACE = "\b";
74
+ const DELETE = "\u007f";
75
+ /** Every character ordered before this one is a C0 control character, none of which a passphrase can hold. */
76
+ const FIRST_PRINTABLE = " ";
77
+ /** Applies one character typed at a hidden prompt to the line so far. Enter, or Ctrl-D on a line with something on it, ends the line; Ctrl-C, and Ctrl-D on an empty line, cancel it. Backspace and Delete remove the last character. An escape sequence (an arrow or function key) or any other control character is refused rather than kept, since it would end up in the value invisibly and could never be typed the same way again. */
78
+ export function hiddenLineStep(value, character) {
79
+ if (character === "\r" || character === "\n")
80
+ return { kind: "done", value };
81
+ if (character === END_OF_TEXT)
82
+ return { kind: "failed", message: "Cancelled" };
83
+ if (character === END_OF_TRANSMISSION) {
84
+ return value === ""
85
+ ? { kind: "failed", message: "Cancelled: no input before end of input" }
86
+ : { kind: "done", value };
87
+ }
88
+ if (character === BACKSPACE || character === DELETE) {
89
+ // A terminal's backspace removes one visible character, which may be several code points.
90
+ const graphemes = Array.from(new Intl.Segmenter().segment(value), ({ segment }) => segment);
91
+ return { kind: "typing", value: graphemes.slice(0, -1).join("") };
92
+ }
93
+ // Escape, which starts every arrow and function key's sequence, is one of these.
94
+ if (character < FIRST_PRINTABLE) {
95
+ return {
96
+ kind: "failed",
97
+ message: "Arrow keys, Escape and other control keys cannot be used at this prompt, since they would be kept in it invisibly; start again and type it plainly",
98
+ };
99
+ }
100
+ return { kind: "typing", value: value + character };
101
+ }
102
+ /** Reads one line from a terminal with echo off, keystroke by keystroke as hiddenLineStep describes. Throws when stdin is not a terminal, since there is nowhere to prompt; a bundle passphrase can then come from ACCOUNT_PASSPHRASE_ENV instead. */
103
+ export async function readHiddenLine(prompt) {
104
+ const { stdin, stderr } = process;
105
+ if (!stdin.isTTY) {
106
+ throw new Error(`No terminal to ask on (${prompt.trim()}); a bundle passphrase can be set in ${ACCOUNT_PASSPHRASE_ENV} instead`);
107
+ }
108
+ stderr.write(prompt);
109
+ stdin.setRawMode(true);
110
+ stdin.setEncoding("utf-8");
111
+ stdin.resume();
112
+ return new Promise((resolve, reject) => {
113
+ let value = "";
114
+ // Replaced once the listener exists, so the listener can detach itself.
115
+ let finish = () => undefined;
116
+ const onData = (chunk) => {
117
+ for (const character of chunk) {
118
+ const step = hiddenLineStep(value, character);
119
+ if (step.kind === "typing") {
120
+ value = step.value;
121
+ continue;
122
+ }
123
+ finish();
124
+ if (step.kind === "done")
125
+ resolve(step.value);
126
+ else
127
+ reject(new Error(step.message));
128
+ return;
129
+ }
130
+ };
131
+ finish = () => {
132
+ stdin.off("data", onData);
133
+ stdin.setRawMode(false);
134
+ stdin.pause();
135
+ stderr.write("\n");
136
+ };
137
+ stdin.on("data", onData);
138
+ });
139
+ }
140
+ //# sourceMappingURL=account-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-cli.js","sourceRoot":"","sources":["../src/account-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `agent-comms account invite` and `agent-comms account join` (agent-comms#344): joining a new machine to the account over the mesh (see core/account-join.ts for the flow). Each runs a store of its own for as long as the command runs. An invite is printed to this terminal only, and the command keeps its store up until the invite is redeemed or expires, since invites live only in the issuing store's memory. A join reads the invite at a prompt that does not echo, so it never sits in shell history.
3
+ */
4
+ import type { AccountJoin } from "./core/account-join.js";
5
+ import { type AccountCliIo } from "./account-cli.js";
6
+ /** A store started for one invite or join, and its shutdown. */
7
+ export interface AccountCliStore {
8
+ account: Pick<AccountJoin, "invite" | "join">;
9
+ close: () => Promise<void>;
10
+ }
11
+ /** Starts a store on this machine's mesh, holding the machine's account, with one hidden agent: that is what gives it a hub session once it trusts the other machine, and a hidden agent is reachable by device id without being listed. */
12
+ export declare function openMachineAccountStore(): Promise<AccountCliStore>;
13
+ /** Issues an invite, prints it, and returns once it has been redeemed or has expired. */
14
+ export declare function inviteToAccount(args: readonly string[], io: Readonly<AccountCliIo>): Promise<void>;
15
+ /** Reads an invite at a prompt and makes this machine hold the account it came from. */
16
+ export declare function joinAccount(args: readonly string[], io: Readonly<AccountCliIo>): Promise<void>;
17
+ //# sourceMappingURL=account-join-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-join-cli.d.ts","sourceRoot":"","sources":["../src/account-join-cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAU1D,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEpE,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,MAAM,CAAC,CAAC;IAC9C,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAKD,4OAA4O;AAC5O,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,eAAe,CAAC,CAwBxE;AAwDD,yFAAyF;AACzF,wBAAsB,eAAe,CACnC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,QAAQ,CAAC,YAAY,CAAC,GACzB,OAAO,CAAC,IAAI,CAAC,CAuBf;AA+BD,wFAAwF;AACxF,wBAAsB,WAAW,CAC/B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,QAAQ,CAAC,YAAY,CAAC,GACzB,OAAO,CAAC,IAAI,CAAC,CAiBf"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * `agent-comms account invite` and `agent-comms account join` (agent-comms#344): joining a new machine to the account over the mesh (see core/account-join.ts for the flow). Each runs a store of its own for as long as the command runs. An invite is printed to this terminal only, and the command keeps its store up until the invite is redeemed or expires, since invites live only in the issuing store's memory. A join reads the invite at a prompt that does not echo, so it never sits in shell history.
3
+ */
4
+ import * as fs from "node:fs";
5
+ import { createBridgeMesh } from "./core/bridge-mesh.js";
6
+ import { createMeshErrorReporter } from "./core/error-reporting.js";
7
+ import { releaseIdentityLock, } from "./core/identity-store.js";
8
+ import { ConnectionCodeSchema } from "./core/types.js";
9
+ import { ACCOUNT_USAGE } from "./account-cli.js";
10
+ /** The identity slot harness these commands' own store runs under, apart from every bridge's. */
11
+ const ACCOUNT_CLI_HARNESS = "account";
12
+ /** Starts a store on this machine's mesh, holding the machine's account, with one hidden agent: that is what gives it a hub session once it trusts the other machine, and a hidden agent is reachable by device id without being listed. */
13
+ export async function openMachineAccountStore() {
14
+ const slot = {
15
+ harness: ACCOUNT_CLI_HARNESS,
16
+ cwd: process.cwd(),
17
+ };
18
+ const { store } = await createBridgeMesh(slot);
19
+ store.onError = createMeshErrorReporter();
20
+ await store.init();
21
+ const agent = await store.registerAgent({
22
+ name: ACCOUNT_CLI_HARNESS,
23
+ harness: ACCOUNT_CLI_HARNESS,
24
+ cwd: slot.cwd,
25
+ pid: process.pid,
26
+ visibility: "hidden",
27
+ tags: [],
28
+ });
29
+ return {
30
+ account: store.account,
31
+ close: async () => {
32
+ await store.setAgentOffline(agent.id);
33
+ await store.shutdown();
34
+ releaseIdentityLock(slot);
35
+ },
36
+ };
37
+ }
38
+ const MS_PER_SECOND = 1000;
39
+ const SECONDS_PER_MINUTE = 60;
40
+ const MS_PER_MINUTE = SECONDS_PER_MINUTE * MS_PER_SECOND;
41
+ /** Parses `--name value` pairs, allowing only `allowed` names, each at most once. */
42
+ function parseOptions(args, allowed) {
43
+ const options = new Map();
44
+ for (let i = 0; i < args.length; i += 2) {
45
+ const name = args[i];
46
+ const value = args[i + 1];
47
+ if (name === undefined ||
48
+ !name.startsWith("--") ||
49
+ !allowed.includes(name.slice(2)) ||
50
+ options.has(name.slice(2)) ||
51
+ value === undefined) {
52
+ throw new Error(ACCOUNT_USAGE);
53
+ }
54
+ options.set(name.slice(2), value);
55
+ }
56
+ return options;
57
+ }
58
+ function ttlMsFrom(minutes) {
59
+ if (minutes === undefined)
60
+ return undefined;
61
+ const parsed = Number(minutes);
62
+ if (!Number.isInteger(parsed) || parsed <= 0) {
63
+ throw new Error(`--ttl-minutes must be a whole number of minutes above zero, not ${minutes}`);
64
+ }
65
+ return parsed * MS_PER_MINUTE;
66
+ }
67
+ async function signingOptions(keyFile, io) {
68
+ if (keyFile === undefined)
69
+ return {};
70
+ const privateKeyArmored = fs.readFileSync(keyFile, "utf-8");
71
+ const passphrase = await io.readSecret("PGP key passphrase (press Enter if it has none): ");
72
+ return passphrase === ""
73
+ ? { privateKeyArmored }
74
+ : { privateKeyArmored, passphrase };
75
+ }
76
+ /** Issues an invite, prints it, and returns once it has been redeemed or has expired. */
77
+ export async function inviteToAccount(args, io) {
78
+ const options = parseOptions(args, ["ttl-minutes", "sign-key"]);
79
+ const ttlMs = ttlMsFrom(options.get("ttl-minutes"));
80
+ const signing = await signingOptions(options.get("sign-key"), io);
81
+ const store = await io.openStore();
82
+ try {
83
+ const { code, settled } = await store.account.invite({
84
+ ...(ttlMs !== undefined && { ttlMs }),
85
+ ...signing,
86
+ });
87
+ io.log(`Account invite, valid until ${code.expiresAt} and for one use. Whoever redeems it takes a full copy of this account, so give it only to your own new machine, out of band, and run \`agent-comms account join\` there. Keep this command running until then.`);
88
+ io.log(JSON.stringify(code));
89
+ const outcome = await settled;
90
+ io.log(outcome === "redeemed"
91
+ ? "The invite was redeemed: the new machine now holds this account."
92
+ : "The invite expired unused.");
93
+ }
94
+ finally {
95
+ await store.close();
96
+ }
97
+ }
98
+ const NOT_AN_INVITE = "That is not an account invite: paste the whole line `agent-comms account invite` printed";
99
+ function parseInvite(raw) {
100
+ let parsed;
101
+ try {
102
+ parsed = JSON.parse(raw);
103
+ }
104
+ catch {
105
+ throw new Error(NOT_AN_INVITE);
106
+ }
107
+ if (!ConnectionCodeSchema.is(parsed)) {
108
+ throw new Error(NOT_AN_INVITE);
109
+ }
110
+ return parsed;
111
+ }
112
+ function verifyingOptions(options) {
113
+ const keyFile = options.get("public-key");
114
+ const fingerprint = options.get("fingerprint");
115
+ return {
116
+ ...(keyFile !== undefined && {
117
+ publicKeyArmored: fs.readFileSync(keyFile, "utf-8"),
118
+ }),
119
+ ...(fingerprint !== undefined && { expectedFingerprint: fingerprint }),
120
+ };
121
+ }
122
+ /** Reads an invite at a prompt and makes this machine hold the account it came from. */
123
+ export async function joinAccount(args, io) {
124
+ const options = parseOptions(args, ["public-key", "fingerprint"]);
125
+ const redeemOptions = verifyingOptions(options);
126
+ const invite = parseInvite(await io.readSecret("Account invite: "));
127
+ const store = await io.openStore();
128
+ try {
129
+ const result = await store.account.join(invite, redeemOptions);
130
+ io.log(`This machine now holds account ${result.principal}.`);
131
+ if (result.replacedFile !== undefined) {
132
+ io.log(`The account it held before was moved to ${result.replacedFile}; it is still the only key that can revoke what that account issued.`);
133
+ }
134
+ io.log("Restart running agent-comms bridges so they use it.");
135
+ }
136
+ finally {
137
+ await store.close();
138
+ }
139
+ }
140
+ //# sourceMappingURL=account-join-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-join-cli.js","sourceRoot":"","sources":["../src/account-join-cli.ts"],"names":[],"mappings":"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"}
@@ -8,16 +8,13 @@
8
8
  * Run via: npx agent-comms bridge mcp
9
9
  */
10
10
  import { type BridgeMeshOptions } from "../../core/index.js";
11
- import type { Readable } from "node:stream";
12
11
  import type { IdentitySlot } from "../../core/identity-store.js";
13
- /** Seams that let a test run the real bridge against an isolated mesh and a piped stdin; every real launch omits them. */
12
+ /** Seams that let a test run the real bridge against an isolated mesh; every real launch omits them. */
14
13
  export interface McpBridgeOptions {
15
14
  /** Ports and hub for the bridge's own mesh store; see BridgeMeshOptions. */
16
15
  mesh?: BridgeMeshOptions | undefined;
17
16
  /** The identity slot. Defaults to this process's working directory under the `mcp` harness. */
18
17
  slot?: IdentitySlot | undefined;
19
- /** The stream JSON-RPC requests are read from. Defaults to process.stdin. */
20
- input?: Readable | undefined;
21
18
  }
22
19
  export declare function run(options?: Readonly<McpBridgeOptions>): Promise<void>;
23
20
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/bridges/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAQL,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAgBjE,0HAA0H;AAC1H,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACrC,+FAA+F;IAC/F,IAAI,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAChC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC9B;AAED,wBAAsB,GAAG,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiG7E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/bridges/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAQL,KAAK,iBAAiB,EACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAgBjE,wGAAwG;AACxG,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACrC,+FAA+F;IAC/F,IAAI,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACjC;AAED,wBAAsB,GAAG,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiG7E"}
@@ -77,7 +77,7 @@ export async function run(options) {
77
77
  await store.init();
78
78
  const webHandle = await tryStartBridgeWebServer(store, "mcp");
79
79
  tool.getWebUrlStatus = () => getWebUrlStatus(webHandle);
80
- await mcp.connect(new StdioServerTransport(options?.input));
80
+ await mcp.connect(new StdioServerTransport());
81
81
  const reg = await ensureRegistered({
82
82
  cwd: process.cwd(),
83
83
  store,
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/bridges/mcp/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/bridges/mcp/server.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts CHANGED
@@ -13,6 +13,10 @@
13
13
  * npx agent-comms rooms # list rooms
14
14
  * npx agent-comms agents # list agents
15
15
  * npx agent-comms read <room> # read room messages
16
+ * npx agent-comms account export <file> # write this machine's account key, passphrase-sealed
17
+ * npx agent-comms account import <file> # make this machine hold an exported account
18
+ * npx agent-comms account invite # print a one-use invite that joins another machine to this account
19
+ * npx agent-comms account join # join this machine to an account with an invite
16
20
  *
17
21
  * The bridge subcommand lets harnesses invoke the bridge via npx:
18
22
  * .mcp.json: \{ "command": "npx", "args": ["agent-comms", "bridge", "claude-code"] \}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
package/dist/cli.js CHANGED
@@ -14,6 +14,10 @@
14
14
  * npx agent-comms rooms # list rooms
15
15
  * npx agent-comms agents # list agents
16
16
  * npx agent-comms read <room> # read room messages
17
+ * npx agent-comms account export <file> # write this machine's account key, passphrase-sealed
18
+ * npx agent-comms account import <file> # make this machine hold an exported account
19
+ * npx agent-comms account invite # print a one-use invite that joins another machine to this account
20
+ * npx agent-comms account join # join this machine to an account with an invite
17
21
  *
18
22
  * The bridge subcommand lets harnesses invoke the bridge via npx:
19
23
  * .mcp.json: \{ "command": "npx", "args": ["agent-comms", "bridge", "claude-code"] \}
@@ -28,6 +32,8 @@ import { bridges } from "./bridges/registry.js";
28
32
  import { resolveDefaultCommand } from "./core/default-command.js";
29
33
  import { runTui } from "./bridges/user/tui.js";
30
34
  import { runCli } from "./bridges/user/cli.js";
35
+ import { readHiddenLine, runAccountCommand } from "./account-cli.js";
36
+ import { openMachineAccountStore } from "./account-join-cli.js";
31
37
  // ---------------------------------------------------------------------------
32
38
  // Zod schemas for config files
33
39
  // ---------------------------------------------------------------------------
@@ -190,8 +196,25 @@ switch (command) {
190
196
  runUserCli(command, cliArgs);
191
197
  break;
192
198
  }
199
+ case "account": {
200
+ runAccountCommand(resolvedArgs.slice(SUBCOMMAND_ARGS_START_INDEX), {
201
+ readSecret: readHiddenLine,
202
+ log: (line) => {
203
+ console.log(line);
204
+ },
205
+ env: process.env,
206
+ openStore: openMachineAccountStore,
207
+ }).then(() => {
208
+ // The store an invite or join ran leaves timers and sockets behind it, so the command ends the process itself once it is done.
209
+ process.exit(0);
210
+ }, (err) => {
211
+ console.error(err instanceof Error ? err.message : String(err));
212
+ process.exit(1);
213
+ });
214
+ break;
215
+ }
193
216
  default:
194
- console.log("Usage: agent-comms [setup|status|remove|bridge <id>|chat|send|dm|rooms|agents|read]");
217
+ console.log("Usage: agent-comms [setup|status|remove|bridge <id>|chat|send|dm|rooms|agents|read|account <export|import|invite|join>]");
195
218
  console.log("With no subcommand: setup when stdin is a terminal, the MCP server when it is not.");
196
219
  process.exit(1);
197
220
  }