agent-comms 8.6.2 → 8.8.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +34 -3
- package/dist/account-cli.d.ts +34 -0
- package/dist/account-cli.d.ts.map +1 -0
- package/dist/account-cli.js +140 -0
- package/dist/account-cli.js.map +1 -0
- package/dist/account-join-cli.d.ts +17 -0
- package/dist/account-join-cli.d.ts.map +1 -0
- package/dist/account-join-cli.js +144 -0
- package/dist/account-join-cli.js.map +1 -0
- package/dist/bridges/mcp/server.d.ts +1 -4
- package/dist/bridges/mcp/server.d.ts.map +1 -1
- package/dist/bridges/mcp/server.js +1 -1
- package/dist/bridges/mcp/server.js.map +1 -1
- package/dist/bridges/user/web/dist/mesh-worker.js +1 -1
- package/dist/bridges/user/web/dist/sw.js +1 -1
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +24 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/account-bundle.d.ts +27 -0
- package/dist/core/account-bundle.d.ts.map +1 -0
- package/dist/core/account-bundle.js +173 -0
- package/dist/core/account-bundle.js.map +1 -0
- package/dist/core/account-join.d.ts +70 -0
- package/dist/core/account-join.d.ts.map +1 -0
- package/dist/core/account-join.js +183 -0
- package/dist/core/account-join.js.map +1 -0
- package/dist/core/account-ledger-crypto.d.ts +28 -0
- package/dist/core/account-ledger-crypto.d.ts.map +1 -0
- package/dist/core/account-ledger-crypto.js +101 -0
- package/dist/core/account-ledger-crypto.js.map +1 -0
- package/dist/core/account-ledger-store.d.ts +21 -0
- package/dist/core/account-ledger-store.d.ts.map +1 -0
- package/dist/core/account-ledger-store.js +34 -0
- package/dist/core/account-ledger-store.js.map +1 -0
- package/dist/core/account-ledger.d.ts +80 -0
- package/dist/core/account-ledger.d.ts.map +1 -0
- package/dist/core/account-ledger.js +247 -0
- package/dist/core/account-ledger.js.map +1 -0
- package/dist/core/agent-registry.d.ts.map +1 -1
- package/dist/core/agent-registry.js +2 -0
- package/dist/core/agent-registry.js.map +1 -1
- package/dist/core/bridge-mesh.d.ts.map +1 -1
- package/dist/core/bridge-mesh.js +12 -1
- package/dist/core/bridge-mesh.js.map +1 -1
- package/dist/core/bridge.d.ts +1 -0
- package/dist/core/bridge.d.ts.map +1 -1
- package/dist/core/bridge.js +6 -0
- package/dist/core/bridge.js.map +1 -1
- package/dist/core/data-frame-routing.d.ts +50 -3
- package/dist/core/data-frame-routing.d.ts.map +1 -1
- package/dist/core/data-frame-routing.js +112 -5
- package/dist/core/data-frame-routing.js.map +1 -1
- package/dist/core/device-membership.d.ts +8 -8
- package/dist/core/device-membership.d.ts.map +1 -1
- package/dist/core/device-membership.js +17 -16
- package/dist/core/device-membership.js.map +1 -1
- package/dist/core/dm-send-delegation.d.ts +4 -4
- package/dist/core/dm-send-delegation.d.ts.map +1 -1
- package/dist/core/dm-send-delegation.js +2 -3
- package/dist/core/dm-send-delegation.js.map +1 -1
- package/dist/core/gossip-directory.d.ts +4 -2
- package/dist/core/gossip-directory.d.ts.map +1 -1
- package/dist/core/gossip-directory.js +4 -5
- package/dist/core/gossip-directory.js.map +1 -1
- package/dist/core/gossip-extensions.d.ts +2 -0
- package/dist/core/gossip-extensions.d.ts.map +1 -1
- package/dist/core/gossip-extensions.js +3 -0
- package/dist/core/gossip-extensions.js.map +1 -1
- package/dist/core/group-proofs.d.ts +15 -6
- package/dist/core/group-proofs.d.ts.map +1 -1
- package/dist/core/group-proofs.js +73 -18
- package/dist/core/group-proofs.js.map +1 -1
- package/dist/core/identity-store.d.ts.map +1 -1
- package/dist/core/identity-store.js +2 -62
- package/dist/core/identity-store.js.map +1 -1
- package/dist/core/issuer-grouping.d.ts +52 -0
- package/dist/core/issuer-grouping.d.ts.map +1 -0
- package/dist/core/{machine-grouping.js → issuer-grouping.js} +33 -33
- package/dist/core/issuer-grouping.js.map +1 -0
- package/dist/core/issuer-identity-file.d.ts +4 -0
- package/dist/core/issuer-identity-file.d.ts.map +1 -1
- package/dist/core/issuer-identity-file.js +7 -5
- package/dist/core/issuer-identity-file.js.map +1 -1
- package/dist/core/ledger-lock.d.ts +12 -0
- package/dist/core/ledger-lock.d.ts.map +1 -0
- package/dist/core/ledger-lock.js +62 -0
- package/dist/core/ledger-lock.js.map +1 -0
- package/dist/core/membership-proofs.d.ts +7 -0
- package/dist/core/membership-proofs.d.ts.map +1 -1
- package/dist/core/membership-proofs.js +26 -1
- package/dist/core/membership-proofs.js.map +1 -1
- package/dist/core/mesh-store-shared.d.ts +4 -1
- package/dist/core/mesh-store-shared.d.ts.map +1 -1
- package/dist/core/mesh-store-shared.js.map +1 -1
- package/dist/core/mesh-store.d.ts +17 -8
- package/dist/core/mesh-store.d.ts.map +1 -1
- package/dist/core/mesh-store.js +44 -42
- package/dist/core/mesh-store.js.map +1 -1
- package/dist/core/naming-actions.d.ts +5 -1
- package/dist/core/naming-actions.d.ts.map +1 -1
- package/dist/core/naming-actions.js +13 -1
- package/dist/core/naming-actions.js.map +1 -1
- package/dist/core/naming.d.ts +9 -5
- package/dist/core/naming.d.ts.map +1 -1
- package/dist/core/naming.js +14 -4
- package/dist/core/naming.js.map +1 -1
- package/dist/core/peer-versions.d.ts +11 -0
- package/dist/core/peer-versions.d.ts.map +1 -1
- package/dist/core/peer-versions.js +9 -0
- package/dist/core/peer-versions.js.map +1 -1
- package/dist/core/pid-lock-file.d.ts +20 -0
- package/dist/core/pid-lock-file.d.ts.map +1 -0
- package/dist/core/pid-lock-file.js +115 -0
- package/dist/core/pid-lock-file.js.map +1 -0
- package/dist/core/room-lifecycle.d.ts +2 -2
- package/dist/core/room-lifecycle.d.ts.map +1 -1
- package/dist/core/room-lifecycle.js +18 -19
- package/dist/core/room-lifecycle.js.map +1 -1
- package/dist/core/self-name-claim.d.ts +27 -0
- package/dist/core/self-name-claim.d.ts.map +1 -0
- package/dist/core/{machine-name-claim.js → self-name-claim.js} +7 -8
- package/dist/core/self-name-claim.js.map +1 -0
- package/dist/core/tool.d.ts.map +1 -1
- package/dist/core/tool.js +11 -7
- package/dist/core/tool.js.map +1 -1
- package/dist/core/transport-queries.d.ts +11 -0
- package/dist/core/transport-queries.d.ts.map +1 -0
- package/dist/core/transport-queries.js +30 -0
- package/dist/core/transport-queries.js.map +1 -0
- package/dist/core/types.d.ts +6 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/user-identity.d.ts +28 -18
- package/dist/core/user-identity.d.ts.map +1 -1
- package/dist/core/user-identity.js +126 -59
- package/dist/core/user-identity.js.map +1 -1
- package/dist/core/wire-mesh-transport-options.d.ts +11 -2
- package/dist/core/wire-mesh-transport-options.d.ts.map +1 -1
- package/dist/core/wire-mesh-transport-options.js.map +1 -1
- package/dist/core/wire-mesh-transport.d.ts +4 -6
- package/dist/core/wire-mesh-transport.d.ts.map +1 -1
- package/dist/core/wire-mesh-transport.js +16 -20
- package/dist/core/wire-mesh-transport.js.map +1 -1
- package/dist/test/account-join.integration.test.d.ts +5 -0
- package/dist/test/account-join.integration.test.d.ts.map +1 -0
- package/dist/test/account-join.integration.test.js +280 -0
- package/dist/test/account-join.integration.test.js.map +1 -0
- package/dist/test/account-ledger-lock-worker.d.ts +9 -0
- package/dist/test/account-ledger-lock-worker.d.ts.map +1 -0
- package/dist/test/account-ledger-lock-worker.js +34 -0
- package/dist/test/account-ledger-lock-worker.js.map +1 -0
- package/dist/test/account-ledger-lock.integration.test.d.ts +5 -0
- package/dist/test/account-ledger-lock.integration.test.d.ts.map +1 -0
- package/dist/test/account-ledger-lock.integration.test.js +71 -0
- package/dist/test/account-ledger-lock.integration.test.js.map +1 -0
- package/dist/test/account-ledger-replication.integration.test.d.ts +5 -0
- package/dist/test/account-ledger-replication.integration.test.d.ts.map +1 -0
- package/dist/test/account-ledger-replication.integration.test.js +145 -0
- package/dist/test/account-ledger-replication.integration.test.js.map +1 -0
- package/dist/test/account-ledger.unit.test.d.ts +5 -0
- package/dist/test/account-ledger.unit.test.d.ts.map +1 -0
- package/dist/test/account-ledger.unit.test.js +317 -0
- package/dist/test/account-ledger.unit.test.js.map +1 -0
- package/dist/test/account-transfer.unit.test.d.ts +5 -0
- package/dist/test/account-transfer.unit.test.d.ts.map +1 -0
- package/dist/test/account-transfer.unit.test.js +232 -0
- package/dist/test/account-transfer.unit.test.js.map +1 -0
- package/dist/test/delivery-engine-delivery.unit.test.js +1 -0
- package/dist/test/delivery-engine-delivery.unit.test.js.map +1 -1
- package/dist/test/delivery-engine-directed-notify.unit.test.js +1 -0
- package/dist/test/delivery-engine-directed-notify.unit.test.js.map +1 -1
- package/dist/test/delivery-engine-own-agent.unit.test.js +1 -0
- package/dist/test/delivery-engine-own-agent.unit.test.js.map +1 -1
- package/dist/test/delivery-engine.unit.test.js +1 -0
- package/dist/test/delivery-engine.unit.test.js.map +1 -1
- package/dist/test/device-membership.unit.test.js +81 -30
- package/dist/test/device-membership.unit.test.js.map +1 -1
- package/dist/test/dm-send-delegation.unit.test.js +25 -14
- package/dist/test/dm-send-delegation.unit.test.js.map +1 -1
- package/dist/test/dm-send-principal-delegation.integration.test.js +9 -2
- package/dist/test/dm-send-principal-delegation.integration.test.js.map +1 -1
- package/dist/test/hidden-line.unit.test.d.ts +5 -0
- package/dist/test/hidden-line.unit.test.d.ts.map +1 -0
- package/dist/test/hidden-line.unit.test.js +40 -0
- package/dist/test/hidden-line.unit.test.js.map +1 -0
- package/dist/test/identity-restart.integration.test.js +8 -1
- package/dist/test/identity-restart.integration.test.js.map +1 -1
- package/dist/test/issuer-grouping.unit.test.d.ts +2 -0
- package/dist/test/issuer-grouping.unit.test.d.ts.map +1 -0
- package/dist/test/issuer-grouping.unit.test.js +137 -0
- package/dist/test/issuer-grouping.unit.test.js.map +1 -0
- package/dist/test/mcp-stdout-channel.integration.test.js +2 -2
- package/dist/test/mcp-stdout-channel.integration.test.js.map +1 -1
- package/dist/test/mesh-smoke.runner.js +2 -1
- package/dist/test/mesh-smoke.runner.js.map +1 -1
- package/dist/test/naming.integration.test.d.ts +1 -1
- package/dist/test/naming.integration.test.js +45 -1
- package/dist/test/naming.integration.test.js.map +1 -1
- package/dist/test/room-join-admission.integration.test.js +8 -1
- package/dist/test/room-join-admission.integration.test.js.map +1 -1
- package/dist/test/room-lifecycle-bare-name.unit.test.js +1 -0
- package/dist/test/room-lifecycle-bare-name.unit.test.js.map +1 -1
- package/dist/test/room-lifecycle-membership.unit.test.js +1 -0
- package/dist/test/room-lifecycle-membership.unit.test.js.map +1 -1
- package/dist/test/room-lifecycle-remote.unit.test.js +1 -0
- package/dist/test/room-lifecycle-remote.unit.test.js.map +1 -1
- package/dist/test/room-lifecycle.unit.test.js +1 -0
- package/dist/test/room-lifecycle.unit.test.js.map +1 -1
- package/dist/test/room-messaging-durable-send.unit.test.js +1 -0
- package/dist/test/room-messaging-durable-send.unit.test.js.map +1 -1
- package/dist/test/room-messaging.unit.test.js +1 -0
- package/dist/test/room-messaging.unit.test.js.map +1 -1
- package/dist/test/room-protocol-notify.unit.test.js +1 -0
- package/dist/test/room-protocol-notify.unit.test.js.map +1 -1
- package/dist/test/room-protocol.helper.d.ts.map +1 -1
- package/dist/test/room-protocol.helper.js +1 -0
- package/dist/test/room-protocol.helper.js.map +1 -1
- package/dist/test/room-send-retry.integration.test.js +8 -1
- package/dist/test/room-send-retry.integration.test.js.map +1 -1
- package/dist/test/test-transport.d.ts +9 -0
- package/dist/test/test-transport.d.ts.map +1 -1
- package/dist/test/test-transport.js +14 -5
- package/dist/test/test-transport.js.map +1 -1
- package/dist/test/user-identity.unit.test.js +92 -99
- package/dist/test/user-identity.unit.test.js.map +1 -1
- package/package.json +1 -1
- package/dist/core/machine-grouping.d.ts +0 -47
- package/dist/core/machine-grouping.d.ts.map +0 -1
- package/dist/core/machine-grouping.js.map +0 -1
- package/dist/core/machine-name-claim.d.ts +0 -22
- package/dist/core/machine-name-claim.d.ts.map +0 -1
- package/dist/core/machine-name-claim.js.map +0 -1
- package/dist/test/machine-grouping.unit.test.d.ts +0 -2
- package/dist/test/machine-grouping.unit.test.d.ts.map +0 -1
- package/dist/test/machine-grouping.unit.test.js +0 -68
- package/dist/test/machine-grouping.unit.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/ExaDev/agent-comms)
|
|
4
4
|
[](https://www.npmjs.com/package/agent-comms)
|
|
5
|
-
[](https://github.com/ExaDev/agent-comms/releases/tag/v8.8.0)
|
|
6
6
|
[](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.
|
|
@@ -347,7 +347,7 @@ To let a device DM you without deciding on the spot, admit it ahead of time. `dm
|
|
|
347
347
|
|
|
348
348
|
Everything identified by a device-id, an agent, a machine, a principal or a trusted device, is shown the same way everywhere: your own name for it first, then the name it gives itself in quotes, then a short id, as in `work laptop "joe-mbp" 3a8b8ebc6dd3`. The short id is a prefix; tool actions take the full id, so listings whose entries you act on print the full id followed by the names alone, without a short id that would only repeat its start.
|
|
349
349
|
|
|
350
|
-
An agent names itself with `register` and `update`. A machine names itself with `machine_name`, which every bridge the account runs on the host then signs with the machine key and gossips beside its machine proof, so peers see the name the machine chose and know which key chose it; what the name says is still the machine's own claim.
|
|
350
|
+
An agent names itself with `register` and `update`. A machine names itself with `machine_name`, which every bridge the account runs on the host then signs with the machine key and gossips beside its machine proof, so peers see the name the machine chose and know which key chose it; what the name says is still the machine's own claim. An account names itself the same way with `principal_name`: the name is kept in `user-identity.json`, signed with the user key beside the membership proof, and shown next to the principal id (in `whoami`, `gateway_list_trusted` and the "vouched for by" column) only when it verifies against the principal that device's proof names. Because the name belongs to the account, an account export and an account join carry it to the new machine; a rename made afterwards is not replicated, so it is made again wherever it is wanted.
|
|
351
351
|
|
|
352
352
|
Your own names, petnames, are yours alone. They live in `~/.agent-comms/petnames.json`, shared by your bridges on this machine, and are never gossiped or sent to anyone. A petname is set for a full device-id only, since a label on a typo or a short id would apply to nothing. An entry in the file that is not a usable name for a full device-id is ignored on its own, and a file that is not a JSON object is reported as an error rather than written over.
|
|
353
353
|
|
|
@@ -355,13 +355,16 @@ Your own names, petnames, are yours alone. They live in `~/.agent-comms/petnames
|
|
|
355
355
|
# Name this machine for everyone who can see it (omit name to clear it)
|
|
356
356
|
agent_comms({ action: "machine_name", name: "joe-mbp" })
|
|
357
357
|
|
|
358
|
+
# Name the account every one of your machines shares (omit name to clear it)
|
|
359
|
+
agent_comms({ action: "principal_name", name: "work account" })
|
|
360
|
+
|
|
358
361
|
# Give any id your own name, and take it away again
|
|
359
362
|
agent_comms({ action: "petname_set", device: "3a8b8e...", name: "work laptop" })
|
|
360
363
|
agent_comms({ action: "petname_clear", device: "3a8b8e..." })
|
|
361
364
|
agent_comms({ action: "petname_list" })
|
|
362
365
|
```
|
|
363
366
|
|
|
364
|
-
Names must be non-empty, at most 64 characters, and free of control characters. `register`, `update`, `machine_name` and `petname_set` refuse a name that breaks those rules, an agent that gossips one is not listed, and any other name that breaks them is left out wherever it would be shown. A name shown in quotes has any quote inside it escaped, so it cannot pass part of itself off as a separate label.
|
|
367
|
+
Names must be non-empty, at most 64 characters, and free of control characters. `register`, `update`, `machine_name`, `principal_name` and `petname_set` refuse a name that breaks those rules, an agent that gossips one is not listed, and any other name that breaks them is left out wherever it would be shown. A name shown in quotes has any quote inside it escaped, so it cannot pass part of itself off as a separate label.
|
|
365
368
|
|
|
366
369
|
## Room types
|
|
367
370
|
|
|
@@ -519,3 +522,31 @@ agent_comms({
|
|
|
519
522
|
```
|
|
520
523
|
|
|
521
524
|
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.
|
|
525
|
+
|
|
526
|
+
### One account on several machines
|
|
527
|
+
|
|
528
|
+
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.
|
|
529
|
+
|
|
530
|
+
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:
|
|
531
|
+
|
|
532
|
+
```bash
|
|
533
|
+
npx agent-comms account invite # on a machine that holds the account; keep it running
|
|
534
|
+
npx agent-comms account join # on the new machine; paste the invite at the prompt
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
`account join --label <name>` also tells the issuing machine what you call the new one: it keeps the label as its own petname for that machine (see Names), so the machine you just admitted is listed by that name from then on. The label follows the ordinary name rules and is refused before anything is redeemed when it breaks them; it never leaves the issuing machine's petnames file.
|
|
538
|
+
|
|
539
|
+
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.
|
|
540
|
+
|
|
541
|
+
`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.
|
|
542
|
+
|
|
543
|
+
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:
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
npx agent-comms account export ~/account.bundle # on a machine that holds the account
|
|
547
|
+
npx agent-comms account import ~/account.bundle # on the other machine, then delete the file
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
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.
|
|
551
|
+
|
|
552
|
+
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, readAccountContents, } 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>] [--label <name>]",
|
|
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(readAccountContents(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 contents = openAccountBundle(fs.readFileSync(file, "utf-8"), await passphrase(io, false));
|
|
61
|
+
const { identity, replacedFile } = importAccountKey(userIdentityOptions, contents);
|
|
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. With --label, the issuing machine keeps the label as its own name for this one. */
|
|
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,wKAAwK;AACxK,wBAAsB,WAAW,CAC/B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,QAAQ,CAAC,YAAY,CAAC,GACzB,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|
|
@@ -0,0 +1,144 @@
|
|
|
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. With --label, the issuing machine keeps the label as its own name for this one. */
|
|
123
|
+
export async function joinAccount(args, io) {
|
|
124
|
+
const options = parseOptions(args, ["public-key", "fingerprint", "label"]);
|
|
125
|
+
const label = options.get("label");
|
|
126
|
+
const joinOptions = {
|
|
127
|
+
...verifyingOptions(options),
|
|
128
|
+
...(label !== undefined && { label }),
|
|
129
|
+
};
|
|
130
|
+
const invite = parseInvite(await io.readSecret("Account invite: "));
|
|
131
|
+
const store = await io.openStore();
|
|
132
|
+
try {
|
|
133
|
+
const result = await store.account.join(invite, joinOptions);
|
|
134
|
+
io.log(`This machine now holds account ${result.principal}.`);
|
|
135
|
+
if (result.replacedFile !== undefined) {
|
|
136
|
+
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.`);
|
|
137
|
+
}
|
|
138
|
+
io.log("Restart running agent-comms bridges so they use it.");
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
await store.close();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# 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
|
|
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,
|
|
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(
|
|
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":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,6BAA6B,EAC7B,eAAe,GAEhB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/bridges/mcp/server.ts"],"names":[],"mappings":"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"}
|