@xmtp/convos-cli 0.1.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/LICENSE +21 -0
- package/README.md +572 -0
- package/bin/dev.js +4 -0
- package/bin/run.js +4 -0
- package/dist/baseCommand.d.ts +46 -0
- package/dist/baseCommand.js +171 -0
- package/dist/commands/agent/serve.d.ts +67 -0
- package/dist/commands/agent/serve.js +662 -0
- package/dist/commands/conversation/add-members.d.ts +19 -0
- package/dist/commands/conversation/add-members.js +39 -0
- package/dist/commands/conversation/consent-state.d.ts +18 -0
- package/dist/commands/conversation/consent-state.js +24 -0
- package/dist/commands/conversation/download-attachment.d.ts +28 -0
- package/dist/commands/conversation/download-attachment.js +164 -0
- package/dist/commands/conversation/explode.d.ts +24 -0
- package/dist/commands/conversation/explode.js +156 -0
- package/dist/commands/conversation/info.d.ts +22 -0
- package/dist/commands/conversation/info.js +79 -0
- package/dist/commands/conversation/invite.d.ts +26 -0
- package/dist/commands/conversation/invite.js +137 -0
- package/dist/commands/conversation/lock.d.ts +24 -0
- package/dist/commands/conversation/lock.js +98 -0
- package/dist/commands/conversation/members.d.ts +22 -0
- package/dist/commands/conversation/members.js +39 -0
- package/dist/commands/conversation/messages.d.ts +31 -0
- package/dist/commands/conversation/messages.js +141 -0
- package/dist/commands/conversation/permissions.d.ts +18 -0
- package/dist/commands/conversation/permissions.js +33 -0
- package/dist/commands/conversation/profiles.d.ts +22 -0
- package/dist/commands/conversation/profiles.js +80 -0
- package/dist/commands/conversation/remove-members.d.ts +19 -0
- package/dist/commands/conversation/remove-members.js +36 -0
- package/dist/commands/conversation/send-attachment.d.ts +30 -0
- package/dist/commands/conversation/send-attachment.js +187 -0
- package/dist/commands/conversation/send-reaction.d.ts +21 -0
- package/dist/commands/conversation/send-reaction.js +38 -0
- package/dist/commands/conversation/send-remote-attachment.d.ts +30 -0
- package/dist/commands/conversation/send-remote-attachment.js +96 -0
- package/dist/commands/conversation/send-reply.d.ts +32 -0
- package/dist/commands/conversation/send-reply.js +170 -0
- package/dist/commands/conversation/send-text.d.ts +24 -0
- package/dist/commands/conversation/send-text.js +64 -0
- package/dist/commands/conversation/stream.d.ts +24 -0
- package/dist/commands/conversation/stream.js +81 -0
- package/dist/commands/conversation/sync.d.ts +18 -0
- package/dist/commands/conversation/sync.js +25 -0
- package/dist/commands/conversation/update-consent.d.ts +19 -0
- package/dist/commands/conversation/update-consent.js +35 -0
- package/dist/commands/conversation/update-description.d.ts +19 -0
- package/dist/commands/conversation/update-description.js +28 -0
- package/dist/commands/conversation/update-name.d.ts +19 -0
- package/dist/commands/conversation/update-name.js +29 -0
- package/dist/commands/conversation/update-profile.d.ts +24 -0
- package/dist/commands/conversation/update-profile.js +97 -0
- package/dist/commands/conversations/create.d.ts +26 -0
- package/dist/commands/conversations/create.js +165 -0
- package/dist/commands/conversations/join.d.ts +27 -0
- package/dist/commands/conversations/join.js +232 -0
- package/dist/commands/conversations/list.d.ts +20 -0
- package/dist/commands/conversations/list.js +109 -0
- package/dist/commands/conversations/process-join-requests.d.ts +26 -0
- package/dist/commands/conversations/process-join-requests.js +261 -0
- package/dist/commands/conversations/sync.d.ts +19 -0
- package/dist/commands/conversations/sync.js +50 -0
- package/dist/commands/identity/create.d.ts +21 -0
- package/dist/commands/identity/create.js +56 -0
- package/dist/commands/identity/info.d.ts +22 -0
- package/dist/commands/identity/info.js +63 -0
- package/dist/commands/identity/list.d.ts +19 -0
- package/dist/commands/identity/list.js +59 -0
- package/dist/commands/identity/remove.d.ts +23 -0
- package/dist/commands/identity/remove.js +51 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/init.js +91 -0
- package/dist/commands/reset.d.ts +17 -0
- package/dist/commands/reset.js +93 -0
- package/dist/help.d.ts +4 -0
- package/dist/help.js +31 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +15 -0
- package/dist/utils/client.d.ts +8 -0
- package/dist/utils/client.js +58 -0
- package/dist/utils/config.d.ts +15 -0
- package/dist/utils/config.js +1 -0
- package/dist/utils/identities.d.ts +49 -0
- package/dist/utils/identities.js +92 -0
- package/dist/utils/invite.d.ts +70 -0
- package/dist/utils/invite.js +339 -0
- package/dist/utils/metadata.d.ts +39 -0
- package/dist/utils/metadata.js +180 -0
- package/dist/utils/mime.d.ts +2 -0
- package/dist/utils/mime.js +42 -0
- package/dist/utils/random.d.ts +5 -0
- package/dist/utils/random.js +19 -0
- package/dist/utils/upload.d.ts +14 -0
- package/dist/utils/upload.js +51 -0
- package/dist/utils/xmtp.d.ts +45 -0
- package/dist/utils/xmtp.js +298 -0
- package/oclif.manifest.json +5562 -0
- package/package.json +124 -0
- package/skills/convos-cli/SKILL.md +588 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 XMTP Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
# @xmtp/convos-cli
|
|
2
|
+
|
|
3
|
+
> [!CAUTION]
|
|
4
|
+
> This CLI is in beta status and ready for you to use. Software in this status may contain bugs or change based on feedback.
|
|
5
|
+
|
|
6
|
+
A command-line interface for [Convos](https://convos.org) — privacy-focused ephemeral messaging built on [XMTP](https://xmtp.org).
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Per-conversation identities**: Every conversation gets its own XMTP inbox — no linkability across conversations
|
|
11
|
+
- **Invite system**: Generate QR codes and invite links; join conversations without knowing the creator's address
|
|
12
|
+
- **Per-conversation profiles**: Different display name and avatar in each conversation
|
|
13
|
+
- **Explode**: Permanently destroy a conversation and all its cryptographic keys
|
|
14
|
+
- **Lock**: Prevent new members from being added to a conversation
|
|
15
|
+
- **Agent mode**: Single long-running process for bots — streams messages, auto-processes joins, accepts commands via stdin
|
|
16
|
+
- **JSON output**: Every command supports `--json` for scripting and automation
|
|
17
|
+
|
|
18
|
+
## How Convos Differs from Standard XMTP
|
|
19
|
+
|
|
20
|
+
Standard XMTP uses a single identity (wallet + inbox) across all conversations. Convos creates a **unique identity per conversation** for maximum privacy:
|
|
21
|
+
|
|
22
|
+
| Property | How |
|
|
23
|
+
| -------- | --- |
|
|
24
|
+
| **No linkability** | Conversations cannot be correlated by external observers |
|
|
25
|
+
| **Isolated keys** | Each conversation has its own wallet key, encryption key, and database |
|
|
26
|
+
| **Ephemeral** | Exploding a conversation destroys the cryptographic identity permanently |
|
|
27
|
+
| **Per-conversation profiles** | Different display names and avatars per conversation |
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
- Node.js >= 22
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# npm
|
|
37
|
+
npm install -g @xmtp/convos-cli
|
|
38
|
+
|
|
39
|
+
# pnpm
|
|
40
|
+
pnpm add -g @xmtp/convos-cli
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Run Without Installing
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# npx
|
|
47
|
+
npx @xmtp/convos-cli --help
|
|
48
|
+
|
|
49
|
+
# pnpx
|
|
50
|
+
pnpx @xmtp/convos-cli --help
|
|
51
|
+
|
|
52
|
+
# yarn
|
|
53
|
+
yarn dlx @xmtp/convos-cli --help
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# 1. Initialize configuration
|
|
60
|
+
convos init
|
|
61
|
+
|
|
62
|
+
# 2. Create a conversation (auto-creates a per-conversation identity)
|
|
63
|
+
convos conversations create --name "My Group" --profile-name "Alice"
|
|
64
|
+
|
|
65
|
+
# 3. Send a message
|
|
66
|
+
convos conversation send-text <conversation-id> "Hello!"
|
|
67
|
+
|
|
68
|
+
# 4. Generate an invite QR code for others to join
|
|
69
|
+
convos conversation invite <conversation-id>
|
|
70
|
+
|
|
71
|
+
# 5. List all conversations across all identities
|
|
72
|
+
convos conversations list
|
|
73
|
+
|
|
74
|
+
# 6. Stream messages in real-time
|
|
75
|
+
convos conversation stream <conversation-id>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
Running `convos init` creates `~/.convos/.env` with:
|
|
81
|
+
|
|
82
|
+
| Variable | Description |
|
|
83
|
+
| ------------------------------ | ------------------------------------------------ |
|
|
84
|
+
| `CONVOS_ENV` | Network: `local`, `dev`, or `production` |
|
|
85
|
+
| `CONVOS_UPLOAD_PROVIDER` | Upload provider for attachments (e.g., `pinata`) |
|
|
86
|
+
| `CONVOS_UPLOAD_PROVIDER_TOKEN` | Authentication token for upload provider |
|
|
87
|
+
| `CONVOS_UPLOAD_PROVIDER_GATEWAY` | Custom gateway URL for upload provider |
|
|
88
|
+
|
|
89
|
+
Unlike standard XMTP, there is **no global wallet key**. Each conversation creates its own identity stored in `~/.convos/identities/`.
|
|
90
|
+
|
|
91
|
+
The default environment is `dev`. Use `--env` to change it:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
convos init --env production
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Configuration is loaded in priority order:
|
|
98
|
+
|
|
99
|
+
1. CLI flags (highest)
|
|
100
|
+
2. `--env-file <path>`
|
|
101
|
+
3. `.env` in current directory
|
|
102
|
+
4. `~/.convos/.env` (default)
|
|
103
|
+
|
|
104
|
+
## Command Topics
|
|
105
|
+
|
|
106
|
+
| Topic | Purpose |
|
|
107
|
+
| ----- | ------- |
|
|
108
|
+
| `agent` | Agent mode — long-running sessions with streaming I/O |
|
|
109
|
+
| `identity` | Manage per-conversation identities (inboxes) |
|
|
110
|
+
| `conversations` | List, create, join, and stream conversations |
|
|
111
|
+
| `conversation` | Interact with a specific conversation |
|
|
112
|
+
|
|
113
|
+
Run `convos --help` for all commands, or `convos <command> --help` for details on a specific command.
|
|
114
|
+
|
|
115
|
+
## Agent Mode
|
|
116
|
+
|
|
117
|
+
The `agent serve` command runs a single long-running process that combines conversation management, message streaming, join request processing, and command handling — purpose-built for AI agents and bots.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Create a new conversation and start serving
|
|
121
|
+
convos agent serve --name "My Bot" --profile-name "Assistant"
|
|
122
|
+
|
|
123
|
+
# Attach to an existing conversation
|
|
124
|
+
convos agent serve <conversation-id>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Why Agent Mode?
|
|
128
|
+
|
|
129
|
+
Without `agent serve`, an agent has to juggle multiple processes:
|
|
130
|
+
- `convos conversation stream` for incoming messages
|
|
131
|
+
- `convos conversations process-join-requests --watch` for new members
|
|
132
|
+
- `convos conversation send-text` for each outgoing message (spawning a new process each time)
|
|
133
|
+
|
|
134
|
+
`agent serve` replaces all of that with a single process using an **ndjson** (newline-delimited JSON) protocol on stdin/stdout.
|
|
135
|
+
|
|
136
|
+
### Protocol
|
|
137
|
+
|
|
138
|
+
**stdout** emits one JSON object per line:
|
|
139
|
+
|
|
140
|
+
| Event | Description | Key Fields |
|
|
141
|
+
| ----- | ----------- | ---------- |
|
|
142
|
+
| `ready` | Session initialized | `conversationId`, `inviteUrl`, `inboxId` |
|
|
143
|
+
| `message` | Incoming message | `id`, `senderInboxId`, `content`, `contentType`, `sentAt` |
|
|
144
|
+
| `member_joined` | New member added | `inboxId`, `conversationId` |
|
|
145
|
+
| `sent` | Outgoing message confirmed | `id`, `text` or `type` + details |
|
|
146
|
+
| `error` | Something went wrong | `message` |
|
|
147
|
+
|
|
148
|
+
**stdin** accepts one JSON command per line:
|
|
149
|
+
|
|
150
|
+
| Command | Required Fields | Optional Fields |
|
|
151
|
+
| ------- | --------------- | --------------- |
|
|
152
|
+
| `send` | `text` | `replyTo` (message ID) |
|
|
153
|
+
| `react` | `messageId`, `emoji` | `action` (`add`/`remove`, default `add`) |
|
|
154
|
+
| `attach` | `file` (local path) | `mimeType`, `replyTo` |
|
|
155
|
+
| `remote-attach` | `url`, `contentDigest`, `secret`, `salt`, `nonce`, `contentLength` | `filename`, `scheme` |
|
|
156
|
+
| `stop` | — | — |
|
|
157
|
+
|
|
158
|
+
**stderr** receives the QR code and diagnostic logs (never interferes with the JSON protocol).
|
|
159
|
+
|
|
160
|
+
### Example: Echo Bot
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
#!/usr/bin/env bash
|
|
164
|
+
# Start agent, read events, echo back every message
|
|
165
|
+
convos agent serve --name "Echo Bot" --profile-name "🤖 Echo" | \
|
|
166
|
+
while IFS= read -r event; do
|
|
167
|
+
type=$(echo "$event" | jq -r '.event')
|
|
168
|
+
case "$type" in
|
|
169
|
+
ready)
|
|
170
|
+
echo "Bot ready! Invite: $(echo "$event" | jq -r '.inviteUrl')" >&2
|
|
171
|
+
;;
|
|
172
|
+
message)
|
|
173
|
+
content=$(echo "$event" | jq -r '.content')
|
|
174
|
+
msg_id=$(echo "$event" | jq -r '.id')
|
|
175
|
+
# Echo the message back as a reply
|
|
176
|
+
echo "{\"type\":\"send\",\"text\":\"You said: $content\",\"replyTo\":\"$msg_id\"}"
|
|
177
|
+
;;
|
|
178
|
+
member_joined)
|
|
179
|
+
echo '{"type":"send","text":"Welcome! 👋"}'
|
|
180
|
+
;;
|
|
181
|
+
esac
|
|
182
|
+
done
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Sending Reactions
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# React to a message
|
|
189
|
+
echo '{"type":"react","messageId":"abc123","emoji":"👍"}'
|
|
190
|
+
|
|
191
|
+
# Remove a reaction
|
|
192
|
+
echo '{"type":"react","messageId":"abc123","emoji":"👍","action":"remove"}'
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Sending Attachments
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Send a file (≤1MB sent inline, larger files auto-uploaded via provider)
|
|
199
|
+
echo '{"type":"attach","file":"./chart.png"}'
|
|
200
|
+
|
|
201
|
+
# Reply with an attachment
|
|
202
|
+
echo '{"type":"attach","file":"./report.pdf","replyTo":"abc123"}'
|
|
203
|
+
|
|
204
|
+
# Send a pre-uploaded encrypted file
|
|
205
|
+
echo '{"type":"remote-attach","url":"https://...","contentDigest":"...","secret":"...","salt":"...","nonce":"...","contentLength":12345}'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Agent Flags
|
|
209
|
+
|
|
210
|
+
| Flag | Description |
|
|
211
|
+
| ---- | ----------- |
|
|
212
|
+
| `--name` | Conversation name (when creating new) |
|
|
213
|
+
| `--description` | Conversation description (when creating new) |
|
|
214
|
+
| `--permissions` | `all-members` or `admin-only` (when creating new) |
|
|
215
|
+
| `--profile-name` | Display name for this conversation |
|
|
216
|
+
| `--identity` | Use an existing unlinked identity |
|
|
217
|
+
| `--label` | Local label for the identity |
|
|
218
|
+
| `--no-invite` | Skip generating an invite (attach mode only) |
|
|
219
|
+
|
|
220
|
+
## Usage Examples
|
|
221
|
+
|
|
222
|
+
### Identity Management
|
|
223
|
+
|
|
224
|
+
Each conversation has its own XMTP identity (wallet + inbox). Identities are created automatically when you create or join a conversation, but you can also manage them directly.
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# List all identities
|
|
228
|
+
convos identity list
|
|
229
|
+
|
|
230
|
+
# Create an identity manually
|
|
231
|
+
convos identity create --label "Work Chat" --profile-name "Alice"
|
|
232
|
+
|
|
233
|
+
# View identity details (connects to XMTP to show inbox ID)
|
|
234
|
+
convos identity info <identity-id>
|
|
235
|
+
|
|
236
|
+
# Remove an identity (destroys all keys — irreversible)
|
|
237
|
+
convos identity remove <identity-id> --force
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Conversations
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Create a conversation (auto-creates per-conversation identity)
|
|
244
|
+
convos conversations create --name "Project Team" --profile-name "Alice"
|
|
245
|
+
|
|
246
|
+
# Create with admin-only permissions
|
|
247
|
+
convos conversations create --name "Announcement Channel" --permissions admin-only
|
|
248
|
+
|
|
249
|
+
# List all conversations across all identities
|
|
250
|
+
convos conversations list --sync
|
|
251
|
+
|
|
252
|
+
# Sync all conversations from the network
|
|
253
|
+
convos conversations sync
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Invites
|
|
257
|
+
|
|
258
|
+
Convos uses a serverless invite system. The creator generates a cryptographic invite slug; the joiner sends a DM join request; the creator's client processes it and adds them to the group.
|
|
259
|
+
|
|
260
|
+
#### Creating Invites
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
# Generate an invite — displays a QR code in the terminal
|
|
264
|
+
convos conversation invite <conversation-id>
|
|
265
|
+
|
|
266
|
+
# Invite that expires in 1 hour
|
|
267
|
+
convos conversation invite <conversation-id> --expires-in 3600
|
|
268
|
+
|
|
269
|
+
# Single-use invite
|
|
270
|
+
convos conversation invite <conversation-id> --single-use
|
|
271
|
+
|
|
272
|
+
# JSON output (suppresses QR code)
|
|
273
|
+
convos conversation invite <conversation-id> --json
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### Joining via Invite
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# Join using a raw invite slug
|
|
280
|
+
convos conversations join <invite-slug>
|
|
281
|
+
|
|
282
|
+
# Join using a full invite URL
|
|
283
|
+
convos conversations join "https://dev.convos.org/v2?i=<slug>"
|
|
284
|
+
|
|
285
|
+
# Join with a display name
|
|
286
|
+
convos conversations join <slug> --profile-name "Bob"
|
|
287
|
+
|
|
288
|
+
# Send join request without waiting for acceptance
|
|
289
|
+
convos conversations join <slug> --no-wait
|
|
290
|
+
|
|
291
|
+
# Wait up to 2 minutes
|
|
292
|
+
convos conversations join <slug> --timeout 120
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
#### Processing Join Requests (Creator Side)
|
|
296
|
+
|
|
297
|
+
The creator's client must be running to process incoming join requests:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
# Process all pending join requests
|
|
301
|
+
convos conversations process-join-requests
|
|
302
|
+
|
|
303
|
+
# Continuously watch for join requests
|
|
304
|
+
convos conversations process-join-requests --watch
|
|
305
|
+
|
|
306
|
+
# Process for a specific conversation only
|
|
307
|
+
convos conversations process-join-requests --conversation <id>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Messages
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
# Send different message types
|
|
314
|
+
convos conversation send-text <id> "Hello!"
|
|
315
|
+
convos conversation send-reaction <id> <message-id> add "👍"
|
|
316
|
+
convos conversation send-reply <id> <message-id> "I agree!"
|
|
317
|
+
|
|
318
|
+
# Read messages
|
|
319
|
+
convos conversation messages <id> --sync --limit 10
|
|
320
|
+
|
|
321
|
+
# Stream messages in real-time
|
|
322
|
+
convos conversation stream <id>
|
|
323
|
+
convos conversation stream <id> --timeout 60
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Attachments
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
# Send a photo (small files ≤1MB sent inline)
|
|
330
|
+
convos conversation send-attachment <id> ./photo.jpg
|
|
331
|
+
|
|
332
|
+
# Large files are automatically encrypted and uploaded via configured provider
|
|
333
|
+
convos conversation send-attachment <id> ./video.mp4
|
|
334
|
+
|
|
335
|
+
# Force remote upload even for small files
|
|
336
|
+
convos conversation send-attachment <id> ./photo.jpg --remote
|
|
337
|
+
|
|
338
|
+
# Override MIME type
|
|
339
|
+
convos conversation send-attachment <id> ./file.bin --mime-type image/png
|
|
340
|
+
|
|
341
|
+
# Per-command upload provider (no .env needed)
|
|
342
|
+
convos conversation send-attachment <id> ./photo.jpg \
|
|
343
|
+
--upload-provider pinata --upload-provider-token <jwt>
|
|
344
|
+
|
|
345
|
+
# Encrypt only (for manual upload workflows)
|
|
346
|
+
convos conversation send-attachment <id> ./photo.jpg --encrypt
|
|
347
|
+
|
|
348
|
+
# Send a pre-uploaded encrypted file
|
|
349
|
+
convos conversation send-remote-attachment <id> <url> \
|
|
350
|
+
--content-digest <hex> --secret <base64> --salt <base64> \
|
|
351
|
+
--nonce <base64> --content-length <bytes>
|
|
352
|
+
|
|
353
|
+
# Download an attachment (handles both inline and remote transparently)
|
|
354
|
+
convos conversation download-attachment <id> <message-id>
|
|
355
|
+
|
|
356
|
+
# Download to a specific path
|
|
357
|
+
convos conversation download-attachment <id> <message-id> --output ./photo.jpg
|
|
358
|
+
|
|
359
|
+
# Reply with a photo
|
|
360
|
+
convos conversation send-reply <id> <message-id> --file ./photo.jpg
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
To configure an upload provider for large files, add to your `~/.convos/.env`:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
CONVOS_UPLOAD_PROVIDER=pinata
|
|
367
|
+
CONVOS_UPLOAD_PROVIDER_TOKEN=<your-pinata-jwt>
|
|
368
|
+
# Optional: custom gateway URL
|
|
369
|
+
CONVOS_UPLOAD_PROVIDER_GATEWAY=https://your-gateway.mypinata.cloud
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Supported upload providers: `pinata`
|
|
373
|
+
|
|
374
|
+
### Profiles
|
|
375
|
+
|
|
376
|
+
Each conversation has independent profiles — you can be a different person in each conversation. Profiles are stored in the group's metadata and visible to all members.
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
# Set your display name in a conversation
|
|
380
|
+
convos conversation update-profile <id> --name "Alice"
|
|
381
|
+
|
|
382
|
+
# Set name and avatar
|
|
383
|
+
convos conversation update-profile <id> --name "Alice" --image "https://example.com/avatar.jpg"
|
|
384
|
+
|
|
385
|
+
# Go anonymous (clear profile)
|
|
386
|
+
convos conversation update-profile <id> --name "" --image ""
|
|
387
|
+
|
|
388
|
+
# View all member profiles
|
|
389
|
+
convos conversation profiles <id>
|
|
390
|
+
convos conversation profiles <id> --json
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Group Management
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
# View members
|
|
397
|
+
convos conversation members <id>
|
|
398
|
+
|
|
399
|
+
# Add/remove members
|
|
400
|
+
convos conversation add-members <id> <inbox-id>
|
|
401
|
+
convos conversation remove-members <id> <inbox-id>
|
|
402
|
+
|
|
403
|
+
# Update metadata
|
|
404
|
+
convos conversation update-name <id> "New Name"
|
|
405
|
+
convos conversation update-description <id> "New description"
|
|
406
|
+
|
|
407
|
+
# View permissions
|
|
408
|
+
convos conversation permissions <id>
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Lock a Conversation
|
|
412
|
+
|
|
413
|
+
Prevent new members from being added:
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
convos conversation lock <id>
|
|
417
|
+
convos conversation lock <id> --unlock
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Explode a Conversation
|
|
421
|
+
|
|
422
|
+
Permanently destroy a conversation and all its cryptographic keys:
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
# Explode immediately
|
|
426
|
+
convos conversation explode <id> --force
|
|
427
|
+
|
|
428
|
+
# Schedule explosion for a future date
|
|
429
|
+
convos conversation explode <id> --scheduled "2025-03-01T00:00:00Z"
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Exploding sends an `ExplodeSettings` notification to all members (so iOS and other clients trigger their cleanup flow), updates group metadata with the expiration timestamp, removes all members, then destroys the local identity. The conversation becomes unreadable.
|
|
433
|
+
|
|
434
|
+
When using `--scheduled`, members are notified but not removed — clients handle cleanup when the time arrives.
|
|
435
|
+
|
|
436
|
+
### JSON Output
|
|
437
|
+
|
|
438
|
+
All commands support `--json` for machine-readable output:
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# Create a conversation and capture the ID
|
|
442
|
+
CONV_ID=$(convos conversations create --name "Test" --json | jq -r '.conversationId')
|
|
443
|
+
|
|
444
|
+
# Send a message
|
|
445
|
+
convos conversation send-text "$CONV_ID" "Hello!"
|
|
446
|
+
|
|
447
|
+
# Read messages as JSON
|
|
448
|
+
convos conversation messages "$CONV_ID" --sync --json
|
|
449
|
+
|
|
450
|
+
# Generate invite and capture the URL
|
|
451
|
+
INVITE_URL=$(convos conversation invite "$CONV_ID" --json | jq -r '.url')
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Verbose Output
|
|
455
|
+
|
|
456
|
+
Use `--verbose` to see detailed client initialization info. When combined with `--json`, verbose logs go to stderr:
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
convos identity info <id> --verbose
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
## Data Directory
|
|
463
|
+
|
|
464
|
+
```
|
|
465
|
+
~/.convos/
|
|
466
|
+
├── .env # Global config (env only)
|
|
467
|
+
├── identities/
|
|
468
|
+
│ ├── <id-1>.json # Identity: wallet key, db key, conversation link
|
|
469
|
+
│ └── <id-2>.json
|
|
470
|
+
└── db/
|
|
471
|
+
└── dev/ # XMTP databases by environment
|
|
472
|
+
├── <id-1>.db3
|
|
473
|
+
└── <id-2>.db3
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
## Architecture
|
|
477
|
+
|
|
478
|
+
```
|
|
479
|
+
┌──────────────────────────────────────────┐
|
|
480
|
+
│ @xmtp/convos-cli │
|
|
481
|
+
│ │
|
|
482
|
+
│ Commands: │
|
|
483
|
+
│ agent serve (long-running bot mode) │
|
|
484
|
+
│ identity create/list/info/remove │
|
|
485
|
+
│ conversations create/join/list/sync │
|
|
486
|
+
│ conversation invite/explode/lock │
|
|
487
|
+
│ conversation send-text/stream/... │
|
|
488
|
+
│ conversation send-attachment/download │
|
|
489
|
+
│ conversation update-profile/profiles │
|
|
490
|
+
│ │
|
|
491
|
+
│ ┌────────────────────────────────────┐ │
|
|
492
|
+
│ │ @xmtp/node-sdk │ │
|
|
493
|
+
│ │ │ │
|
|
494
|
+
│ │ Per-conversation XMTP clients │ │
|
|
495
|
+
│ │ Group/DM management │ │
|
|
496
|
+
│ │ Message encryption & delivery │ │
|
|
497
|
+
│ └────────────────────────────────────┘ │
|
|
498
|
+
└──────────────────────────────────────────┘
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## Library Usage
|
|
502
|
+
|
|
503
|
+
`@xmtp/convos-cli` exports its core functionality for use in other applications:
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
import {
|
|
507
|
+
createIdentityStore,
|
|
508
|
+
createClientForIdentity,
|
|
509
|
+
createInviteSlug,
|
|
510
|
+
parseInvite,
|
|
511
|
+
verifyInvite,
|
|
512
|
+
parseAppData,
|
|
513
|
+
serializeAppData,
|
|
514
|
+
upsertProfile,
|
|
515
|
+
ConvosBaseCommand,
|
|
516
|
+
} from "@xmtp/convos-cli";
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
See the [exports](./src/index.ts) for the full API.
|
|
520
|
+
|
|
521
|
+
## AI Coding Agent Skill
|
|
522
|
+
|
|
523
|
+
This package includes an [agent skill](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) (`skills/convos-cli/SKILL.md`) that teaches AI coding agents how to use the Convos CLI.
|
|
524
|
+
|
|
525
|
+
**Claude Code**
|
|
526
|
+
|
|
527
|
+
Add the skill directory to your project's `.claude/settings.json`:
|
|
528
|
+
|
|
529
|
+
```json
|
|
530
|
+
{
|
|
531
|
+
"skills": ["./node_modules/@xmtp/convos-cli/skills"]
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**Other agents** (Cursor, Windsurf, Codex, etc.)
|
|
536
|
+
|
|
537
|
+
Use [openskills](https://github.com/numman-ali/openskills) to install the skill:
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
npx openskills install ./node_modules/@xmtp/convos-cli/skills
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
Or point your agent to `node_modules/@xmtp/convos-cli/skills/convos-cli/SKILL.md` directly.
|
|
544
|
+
|
|
545
|
+
## Testing
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
# Run all tests (fast, no network required)
|
|
549
|
+
npm test
|
|
550
|
+
|
|
551
|
+
# Watch mode
|
|
552
|
+
npm run test:watch
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
## Development
|
|
556
|
+
|
|
557
|
+
```bash
|
|
558
|
+
# Install dependencies
|
|
559
|
+
npm install
|
|
560
|
+
|
|
561
|
+
# Build TypeScript
|
|
562
|
+
npm run build
|
|
563
|
+
|
|
564
|
+
# Dev mode (tsx, no build needed)
|
|
565
|
+
npm run dev -- conversations list
|
|
566
|
+
|
|
567
|
+
# Run built version
|
|
568
|
+
npm start -- conversations list
|
|
569
|
+
|
|
570
|
+
# Type check without emitting
|
|
571
|
+
npm run typecheck
|
|
572
|
+
```
|
package/bin/dev.js
ADDED
package/bin/run.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base command for Convos CLI.
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - Common flags (--env, --json, --log-level, etc.)
|
|
6
|
+
* - output() and streamOutput() helpers
|
|
7
|
+
* - Config loading from .env files
|
|
8
|
+
*
|
|
9
|
+
* Convos adds: per-conversation identity resolution. Instead of a
|
|
10
|
+
* single wallet key, each conversation has its own identity with
|
|
11
|
+
* its own keys. Commands use getConvosConfig() + the identity store.
|
|
12
|
+
*/
|
|
13
|
+
import { Command } from "@oclif/core";
|
|
14
|
+
import type { ConvosConfig } from "./utils/config.js";
|
|
15
|
+
export declare class ConvosBaseCommand extends Command {
|
|
16
|
+
#private;
|
|
17
|
+
/** Flags shared by all commands. */
|
|
18
|
+
static commonFlags: {
|
|
19
|
+
"env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
"gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
23
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
24
|
+
};
|
|
25
|
+
/** Full flag set for commands that create a client. */
|
|
26
|
+
static baseFlags: {
|
|
27
|
+
"log-level": import("@oclif/core/interfaces").OptionFlag<"off" | "error" | "warn" | "info" | "debug" | "trace" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
28
|
+
"structured-logging": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
29
|
+
"app-version": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
30
|
+
"env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
31
|
+
env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
32
|
+
"gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
33
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
34
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
35
|
+
};
|
|
36
|
+
jsonOutput: boolean;
|
|
37
|
+
verbose: boolean;
|
|
38
|
+
init(): Promise<void>;
|
|
39
|
+
output(data: unknown): void;
|
|
40
|
+
streamOutput(data: unknown): void;
|
|
41
|
+
parseBigInt(value: string | undefined, flagName: string): bigint | undefined;
|
|
42
|
+
confirmAction(message: string, force?: boolean): Promise<void>;
|
|
43
|
+
getConvosConfig(): ConvosConfig;
|
|
44
|
+
run(): Promise<void>;
|
|
45
|
+
catch(error: Error): never;
|
|
46
|
+
}
|