@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
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
2
|
+
export default class ConversationRemoveMembers extends ConvosBaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static strict: boolean;
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
"log-level": import("@oclif/core/interfaces").OptionFlag<"off" | "error" | "warn" | "info" | "debug" | "trace" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
"structured-logging": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
"app-version": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
"env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
"gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Args } from "@oclif/core";
|
|
2
|
+
import { requireGroup } from "../../utils/xmtp.js";
|
|
3
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
4
|
+
import { createClientForIdentity } from "../../utils/client.js";
|
|
5
|
+
import { createIdentityStore } from "../../utils/identities.js";
|
|
6
|
+
export default class ConversationRemoveMembers extends ConvosBaseCommand {
|
|
7
|
+
static description = `Remove members from a conversation. Requires super admin permissions.`;
|
|
8
|
+
static strict = false;
|
|
9
|
+
static args = {
|
|
10
|
+
id: Args.string({ description: "The conversation ID", required: true }),
|
|
11
|
+
};
|
|
12
|
+
static flags = { ...ConvosBaseCommand.baseFlags };
|
|
13
|
+
async run() {
|
|
14
|
+
const { args, argv } = await this.parse(ConversationRemoveMembers);
|
|
15
|
+
const inboxIds = argv.slice(1);
|
|
16
|
+
if (inboxIds.length === 0)
|
|
17
|
+
this.error("At least one inbox ID is required");
|
|
18
|
+
const config = this.getConvosConfig();
|
|
19
|
+
const store = createIdentityStore();
|
|
20
|
+
const identity = store.getByConversationId(args.id);
|
|
21
|
+
if (!identity)
|
|
22
|
+
this.error(`No identity found for conversation: ${args.id}`);
|
|
23
|
+
const client = await createClientForIdentity(identity, config);
|
|
24
|
+
const conversation = await client.conversations.getConversationById(args.id);
|
|
25
|
+
if (!conversation)
|
|
26
|
+
this.error(`Conversation not found: ${args.id}`);
|
|
27
|
+
const group = requireGroup(conversation);
|
|
28
|
+
await group.removeMembers(inboxIds);
|
|
29
|
+
this.output({
|
|
30
|
+
success: true,
|
|
31
|
+
conversationId: args.id,
|
|
32
|
+
removedInboxIds: inboxIds,
|
|
33
|
+
count: inboxIds.length,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
2
|
+
export default class ConversationSendAttachment extends ConvosBaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}[];
|
|
8
|
+
static args: {
|
|
9
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
10
|
+
file: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
static flags: {
|
|
13
|
+
"mime-type": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
encrypt: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
"encrypted-output": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
"upload-provider": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
"upload-provider-token": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
"upload-provider-gateway": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
remote: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
"log-level": import("@oclif/core/interfaces").OptionFlag<"off" | "error" | "warn" | "info" | "debug" | "trace" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
"structured-logging": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
"app-version": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
"env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
"gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
};
|
|
29
|
+
run(): Promise<void>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { Args, Flags } from "@oclif/core";
|
|
4
|
+
import { encryptAttachment } from "@xmtp/node-sdk";
|
|
5
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
6
|
+
import { createClientForIdentity } from "../../utils/client.js";
|
|
7
|
+
import { createIdentityStore } from "../../utils/identities.js";
|
|
8
|
+
import { getMimeType } from "../../utils/mime.js";
|
|
9
|
+
import { getUploadProvider, INLINE_ATTACHMENT_MAX_BYTES, } from "../../utils/upload.js";
|
|
10
|
+
export default class ConversationSendAttachment extends ConvosBaseCommand {
|
|
11
|
+
static description = `Send a file attachment to a conversation.
|
|
12
|
+
|
|
13
|
+
Reads a file from disk and sends it as an attachment message. Small
|
|
14
|
+
files (≤1MB) are sent inline; large files are automatically encrypted
|
|
15
|
+
and uploaded via the configured upload provider, then sent as a remote
|
|
16
|
+
attachment.
|
|
17
|
+
|
|
18
|
+
To configure an upload provider for large files, add to your .env:
|
|
19
|
+
|
|
20
|
+
CONVOS_UPLOAD_PROVIDER=pinata
|
|
21
|
+
CONVOS_UPLOAD_PROVIDER_TOKEN=<your-pinata-jwt>
|
|
22
|
+
CONVOS_UPLOAD_PROVIDER_GATEWAY=https://your-gateway.mypinata.cloud
|
|
23
|
+
|
|
24
|
+
Or pass --upload-provider and --upload-provider-token flags.
|
|
25
|
+
|
|
26
|
+
The MIME type is auto-detected from the file extension, or can be
|
|
27
|
+
specified manually with --mime-type.
|
|
28
|
+
|
|
29
|
+
Use --encrypt to only encrypt the file and output decryption keys
|
|
30
|
+
without sending (for manual upload workflows).`;
|
|
31
|
+
static examples = [
|
|
32
|
+
{
|
|
33
|
+
command: "<%= config.bin %> <%= command.id %> <conversation-id> ./photo.jpg",
|
|
34
|
+
description: "Send a photo (auto-detects inline vs remote)",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
command: "<%= config.bin %> <%= command.id %> <conversation-id> ./photo.jpg --remote",
|
|
38
|
+
description: "Force remote upload even for small files",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
command: "<%= config.bin %> <%= command.id %> <conversation-id> ./photo.jpg --encrypt",
|
|
42
|
+
description: "Encrypt and output decryption keys (for manual upload)",
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
static args = {
|
|
46
|
+
id: Args.string({
|
|
47
|
+
description: "The conversation ID",
|
|
48
|
+
required: true,
|
|
49
|
+
}),
|
|
50
|
+
file: Args.string({
|
|
51
|
+
description: "Path to the file to send",
|
|
52
|
+
required: true,
|
|
53
|
+
}),
|
|
54
|
+
};
|
|
55
|
+
static flags = {
|
|
56
|
+
...ConvosBaseCommand.baseFlags,
|
|
57
|
+
"mime-type": Flags.string({
|
|
58
|
+
description: "Override the auto-detected MIME type",
|
|
59
|
+
helpValue: "<type>",
|
|
60
|
+
}),
|
|
61
|
+
encrypt: Flags.boolean({
|
|
62
|
+
description: "Encrypt the attachment and output decryption keys instead of sending. Upload the payload yourself, then use 'send-remote-attachment' to send.",
|
|
63
|
+
default: false,
|
|
64
|
+
}),
|
|
65
|
+
"encrypted-output": Flags.string({
|
|
66
|
+
description: "When using --encrypt, write encrypted payload to this path (default: <file>.encrypted)",
|
|
67
|
+
helpValue: "<path>",
|
|
68
|
+
dependsOn: ["encrypt"],
|
|
69
|
+
}),
|
|
70
|
+
"upload-provider": Flags.string({
|
|
71
|
+
description: "Upload provider for remote attachments",
|
|
72
|
+
helpValue: "<provider>",
|
|
73
|
+
}),
|
|
74
|
+
"upload-provider-token": Flags.string({
|
|
75
|
+
description: "Authentication token for the upload provider",
|
|
76
|
+
helpValue: "<token>",
|
|
77
|
+
}),
|
|
78
|
+
"upload-provider-gateway": Flags.string({
|
|
79
|
+
description: "Custom gateway URL for the upload provider",
|
|
80
|
+
helpValue: "<url>",
|
|
81
|
+
}),
|
|
82
|
+
remote: Flags.boolean({
|
|
83
|
+
description: "Force sending as a remote attachment (encrypt + upload), even for small files",
|
|
84
|
+
default: false,
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
async run() {
|
|
88
|
+
const { args, flags } = await this.parse(ConversationSendAttachment);
|
|
89
|
+
const config = {
|
|
90
|
+
...this.getConvosConfig(),
|
|
91
|
+
...(flags["upload-provider"] && {
|
|
92
|
+
uploadProvider: flags["upload-provider"],
|
|
93
|
+
}),
|
|
94
|
+
...(flags["upload-provider-token"] && {
|
|
95
|
+
uploadProviderToken: flags["upload-provider-token"],
|
|
96
|
+
}),
|
|
97
|
+
...(flags["upload-provider-gateway"] && {
|
|
98
|
+
uploadProviderGateway: flags["upload-provider-gateway"],
|
|
99
|
+
}),
|
|
100
|
+
};
|
|
101
|
+
const content = await readFile(args.file);
|
|
102
|
+
const filename = basename(args.file);
|
|
103
|
+
const mimeType = flags["mime-type"] ?? getMimeType(args.file);
|
|
104
|
+
const attachment = {
|
|
105
|
+
mimeType,
|
|
106
|
+
content,
|
|
107
|
+
filename,
|
|
108
|
+
};
|
|
109
|
+
// --encrypt: just encrypt and output keys, don't send
|
|
110
|
+
if (flags.encrypt) {
|
|
111
|
+
const encrypted = encryptAttachment(attachment);
|
|
112
|
+
const outputPath = flags["encrypted-output"] ?? `${args.file}.encrypted`;
|
|
113
|
+
await writeFile(outputPath, encrypted.payload);
|
|
114
|
+
this.output({
|
|
115
|
+
encryptedFile: outputPath,
|
|
116
|
+
filename,
|
|
117
|
+
mimeType,
|
|
118
|
+
contentDigest: encrypted.contentDigest,
|
|
119
|
+
secret: Buffer.from(encrypted.secret).toString("base64"),
|
|
120
|
+
salt: Buffer.from(encrypted.salt).toString("base64"),
|
|
121
|
+
nonce: Buffer.from(encrypted.nonce).toString("base64"),
|
|
122
|
+
contentLength: encrypted.payload.length,
|
|
123
|
+
note: "Upload the encrypted file to a URL, then use 'conversation send-remote-attachment' to send it.",
|
|
124
|
+
});
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const store = createIdentityStore();
|
|
128
|
+
const identity = store.getByConversationId(args.id);
|
|
129
|
+
if (!identity) {
|
|
130
|
+
this.error(`No identity found for conversation: ${args.id}\nUse 'convos conversations list' to see available conversations.`);
|
|
131
|
+
}
|
|
132
|
+
const client = await createClientForIdentity(identity, config);
|
|
133
|
+
const conversation = await client.conversations.getConversationById(args.id);
|
|
134
|
+
if (!conversation) {
|
|
135
|
+
this.error(`Conversation not found: ${args.id}`);
|
|
136
|
+
}
|
|
137
|
+
const needsRemote = flags.remote || content.length > INLINE_ATTACHMENT_MAX_BYTES;
|
|
138
|
+
if (needsRemote) {
|
|
139
|
+
const provider = getUploadProvider(config);
|
|
140
|
+
if (!provider) {
|
|
141
|
+
this.error(`File is ${content.length} bytes (>${INLINE_ATTACHMENT_MAX_BYTES}). ` +
|
|
142
|
+
`Configure an upload provider to send large files.\n\n` +
|
|
143
|
+
`Set in your .env:\n` +
|
|
144
|
+
` CONVOS_UPLOAD_PROVIDER=pinata\n` +
|
|
145
|
+
` CONVOS_UPLOAD_PROVIDER_TOKEN=<your-jwt>\n\n` +
|
|
146
|
+
`Or use flags:\n` +
|
|
147
|
+
` --upload-provider pinata --upload-provider-token <jwt>\n\n` +
|
|
148
|
+
`Or use --encrypt to manually encrypt and upload.`);
|
|
149
|
+
}
|
|
150
|
+
const encrypted = encryptAttachment(attachment);
|
|
151
|
+
const url = await provider.upload(encrypted.payload, filename, mimeType);
|
|
152
|
+
const messageId = await conversation.sendRemoteAttachment({
|
|
153
|
+
url,
|
|
154
|
+
contentDigest: encrypted.contentDigest,
|
|
155
|
+
secret: encrypted.secret,
|
|
156
|
+
salt: encrypted.salt,
|
|
157
|
+
nonce: encrypted.nonce,
|
|
158
|
+
scheme: "https",
|
|
159
|
+
contentLength: encrypted.payload.length,
|
|
160
|
+
filename,
|
|
161
|
+
}, false);
|
|
162
|
+
this.output({
|
|
163
|
+
success: true,
|
|
164
|
+
messageId,
|
|
165
|
+
conversationId: args.id,
|
|
166
|
+
filename,
|
|
167
|
+
mimeType,
|
|
168
|
+
size: content.length,
|
|
169
|
+
type: "remote",
|
|
170
|
+
provider: provider.name,
|
|
171
|
+
url,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const messageId = await conversation.sendAttachment(attachment, false);
|
|
176
|
+
this.output({
|
|
177
|
+
success: true,
|
|
178
|
+
messageId,
|
|
179
|
+
conversationId: args.id,
|
|
180
|
+
filename,
|
|
181
|
+
mimeType,
|
|
182
|
+
size: content.length,
|
|
183
|
+
type: "inline",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
2
|
+
export default class ConversationSendReaction extends ConvosBaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
"message-id": import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
action: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
8
|
+
emoji: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
9
|
+
};
|
|
10
|
+
static flags: {
|
|
11
|
+
"log-level": import("@oclif/core/interfaces").OptionFlag<"off" | "error" | "warn" | "info" | "debug" | "trace" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
"structured-logging": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
"app-version": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
"env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
"gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
19
|
+
};
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Args } from "@oclif/core";
|
|
2
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
3
|
+
import { createClientForIdentity } from "../../utils/client.js";
|
|
4
|
+
import { createIdentityStore } from "../../utils/identities.js";
|
|
5
|
+
export default class ConversationSendReaction extends ConvosBaseCommand {
|
|
6
|
+
static description = `Send a reaction to a message.`;
|
|
7
|
+
static args = {
|
|
8
|
+
id: Args.string({ description: "The conversation ID", required: true }),
|
|
9
|
+
"message-id": Args.string({ description: "The message ID", required: true }),
|
|
10
|
+
action: Args.string({ description: "add or remove", required: true, options: ["add", "remove"] }),
|
|
11
|
+
emoji: Args.string({ description: "The reaction emoji", required: true }),
|
|
12
|
+
};
|
|
13
|
+
static flags = { ...ConvosBaseCommand.baseFlags };
|
|
14
|
+
async run() {
|
|
15
|
+
const { args } = await this.parse(ConversationSendReaction);
|
|
16
|
+
const config = this.getConvosConfig();
|
|
17
|
+
const store = createIdentityStore();
|
|
18
|
+
const identity = store.getByConversationId(args.id);
|
|
19
|
+
if (!identity)
|
|
20
|
+
this.error(`No identity found for conversation: ${args.id}`);
|
|
21
|
+
const client = await createClientForIdentity(identity, config);
|
|
22
|
+
const conversation = await client.conversations.getConversationById(args.id);
|
|
23
|
+
if (!conversation)
|
|
24
|
+
this.error(`Conversation not found: ${args.id}`);
|
|
25
|
+
const reaction = {
|
|
26
|
+
reference: args["message-id"],
|
|
27
|
+
referenceInboxId: "",
|
|
28
|
+
action: args.action === "add" ? 1 /* ReactionAction.Added */ : 2 /* ReactionAction.Removed */,
|
|
29
|
+
content: args.emoji,
|
|
30
|
+
schema: 1 /* ReactionSchema.Unicode */,
|
|
31
|
+
};
|
|
32
|
+
const messageId = await conversation.sendReaction(reaction);
|
|
33
|
+
this.output({
|
|
34
|
+
success: true, messageId, conversationId: args.id,
|
|
35
|
+
referenceMessageId: args["message-id"], action: args.action, emoji: args.emoji,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
2
|
+
export default class ConversationSendRemoteAttachment extends ConvosBaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}[];
|
|
8
|
+
static args: {
|
|
9
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
10
|
+
url: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
|
+
};
|
|
12
|
+
static flags: {
|
|
13
|
+
"content-digest": import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
secret: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
salt: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
nonce: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
scheme: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
"content-length": import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
filename: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
"log-level": import("@oclif/core/interfaces").OptionFlag<"off" | "error" | "warn" | "info" | "debug" | "trace" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
"structured-logging": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
"app-version": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
"env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
"gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
};
|
|
29
|
+
run(): Promise<void>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { Args, Flags } from "@oclif/core";
|
|
2
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
3
|
+
import { createClientForIdentity } from "../../utils/client.js";
|
|
4
|
+
import { createIdentityStore } from "../../utils/identities.js";
|
|
5
|
+
export default class ConversationSendRemoteAttachment extends ConvosBaseCommand {
|
|
6
|
+
static description = `Send a remote attachment message to a conversation.
|
|
7
|
+
|
|
8
|
+
Sends a reference to an encrypted file that has been uploaded to a URL.
|
|
9
|
+
The recipient downloads and decrypts the file using the provided keys.
|
|
10
|
+
|
|
11
|
+
Use 'conversation send-attachment --encrypt' to encrypt a file and get
|
|
12
|
+
the required keys, then upload the encrypted payload and use this
|
|
13
|
+
command to send the message.`;
|
|
14
|
+
static examples = [
|
|
15
|
+
{
|
|
16
|
+
command: "<%= config.bin %> <%= command.id %> <conversation-id> https://example.com/file.enc --content-digest abc123 --secret <base64> --salt <base64> --nonce <base64> --content-length 12345",
|
|
17
|
+
description: "Send a remote attachment",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
command: "<%= config.bin %> <%= command.id %> <conversation-id> https://example.com/photo.enc --content-digest abc123 --secret <base64> --salt <base64> --nonce <base64> --content-length 12345 --filename photo.jpg",
|
|
21
|
+
description: "Send with original filename",
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
static args = {
|
|
25
|
+
id: Args.string({
|
|
26
|
+
description: "The conversation ID",
|
|
27
|
+
required: true,
|
|
28
|
+
}),
|
|
29
|
+
url: Args.string({
|
|
30
|
+
description: "URL where the encrypted file is hosted",
|
|
31
|
+
required: true,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
static flags = {
|
|
35
|
+
...ConvosBaseCommand.baseFlags,
|
|
36
|
+
"content-digest": Flags.string({
|
|
37
|
+
description: "SHA-256 digest of the encrypted payload (hex)",
|
|
38
|
+
required: true,
|
|
39
|
+
}),
|
|
40
|
+
secret: Flags.string({
|
|
41
|
+
description: "Decryption secret key (base64)",
|
|
42
|
+
required: true,
|
|
43
|
+
}),
|
|
44
|
+
salt: Flags.string({
|
|
45
|
+
description: "Encryption salt (base64)",
|
|
46
|
+
required: true,
|
|
47
|
+
}),
|
|
48
|
+
nonce: Flags.string({
|
|
49
|
+
description: "Encryption nonce (base64)",
|
|
50
|
+
required: true,
|
|
51
|
+
}),
|
|
52
|
+
scheme: Flags.string({
|
|
53
|
+
description: "URL scheme",
|
|
54
|
+
default: "https",
|
|
55
|
+
}),
|
|
56
|
+
"content-length": Flags.integer({
|
|
57
|
+
description: "Size of the encrypted payload in bytes",
|
|
58
|
+
required: true,
|
|
59
|
+
}),
|
|
60
|
+
filename: Flags.string({
|
|
61
|
+
description: "Original filename",
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
64
|
+
async run() {
|
|
65
|
+
const { args, flags } = await this.parse(ConversationSendRemoteAttachment);
|
|
66
|
+
const config = this.getConvosConfig();
|
|
67
|
+
const store = createIdentityStore();
|
|
68
|
+
const identity = store.getByConversationId(args.id);
|
|
69
|
+
if (!identity) {
|
|
70
|
+
this.error(`No identity found for conversation: ${args.id}\nUse 'convos conversations list' to see available conversations.`);
|
|
71
|
+
}
|
|
72
|
+
const client = await createClientForIdentity(identity, config);
|
|
73
|
+
const conversation = await client.conversations.getConversationById(args.id);
|
|
74
|
+
if (!conversation) {
|
|
75
|
+
this.error(`Conversation not found: ${args.id}`);
|
|
76
|
+
}
|
|
77
|
+
const remoteAttachment = {
|
|
78
|
+
url: args.url,
|
|
79
|
+
contentDigest: flags["content-digest"],
|
|
80
|
+
secret: new Uint8Array(Buffer.from(flags.secret, "base64")),
|
|
81
|
+
salt: new Uint8Array(Buffer.from(flags.salt, "base64")),
|
|
82
|
+
nonce: new Uint8Array(Buffer.from(flags.nonce, "base64")),
|
|
83
|
+
scheme: flags.scheme,
|
|
84
|
+
contentLength: flags["content-length"],
|
|
85
|
+
filename: flags.filename,
|
|
86
|
+
};
|
|
87
|
+
const messageId = await conversation.sendRemoteAttachment(remoteAttachment, false);
|
|
88
|
+
this.output({
|
|
89
|
+
success: true,
|
|
90
|
+
messageId,
|
|
91
|
+
conversationId: args.id,
|
|
92
|
+
url: args.url,
|
|
93
|
+
filename: flags.filename,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ConvosBaseCommand } from "../../baseCommand.js";
|
|
2
|
+
export default class ConversationSendReply extends ConvosBaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}[];
|
|
8
|
+
static args: {
|
|
9
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
10
|
+
"message-id": import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
11
|
+
text: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
static flags: {
|
|
14
|
+
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
"mime-type": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
remote: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
"upload-provider": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
"upload-provider-token": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
"upload-provider-gateway": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
"log-level": import("@oclif/core/interfaces").OptionFlag<"off" | "error" | "warn" | "info" | "debug" | "trace" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
"structured-logging": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
"app-version": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
"env-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
env: import("@oclif/core/interfaces").OptionFlag<"local" | "dev" | "production" | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
"gateway-host": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
};
|
|
29
|
+
run(): Promise<void>;
|
|
30
|
+
private sendTextReply;
|
|
31
|
+
private sendFileReply;
|
|
32
|
+
}
|