@hasna/connectors 1.3.45 → 1.3.46
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/README.md +25 -0
- package/bin/index.js +792 -130
- package/bin/mcp.js +438 -52
- package/bin/serve.js +438 -52
- package/connectors/cloudflare-workers/.env.example +5 -0
- package/connectors/cloudflare-workers/AGENTS.md +11 -0
- package/connectors/cloudflare-workers/CLAUDE.md +11 -0
- package/connectors/cloudflare-workers/README.md +45 -0
- package/connectors/cloudflare-workers/package.json +47 -0
- package/connectors/cloudflare-workers/src/api/client.test.ts +144 -0
- package/connectors/cloudflare-workers/src/api/client.ts +386 -0
- package/connectors/cloudflare-workers/src/api/index.ts +1 -0
- package/connectors/cloudflare-workers/src/cli/index.ts +206 -0
- package/connectors/cloudflare-workers/src/index.ts +16 -0
- package/connectors/cloudflare-workers/src/types/index.ts +53 -0
- package/connectors/cloudflare-workers/src/utils/config.ts +61 -0
- package/connectors/cloudflare-workers/src/utils/output.ts +26 -0
- package/connectors/cloudflare-workers/tsconfig.build.json +4 -0
- package/connectors/cloudflare-workers/tsconfig.json +14 -0
- package/connectors/tidio/.env.example +3 -2
- package/connectors/tidio/CLAUDE.md +21 -96
- package/connectors/tidio/README.md +22 -18
- package/connectors/tidio/package.json +4 -2
- package/connectors/tidio/src/api/client.ts +26 -15
- package/connectors/tidio/src/api/index.ts +185 -128
- package/connectors/tidio/src/api/tidio.test.ts +175 -44
- package/connectors/tidio/src/cli/index.ts +154 -388
- package/connectors/tidio/src/index.ts +5 -3
- package/connectors/tidio/src/types/index.ts +135 -82
- package/connectors/tidio/src/utils/config.ts +90 -44
- package/connectors/wandb/.env.example +7 -0
- package/connectors/wandb/AGENTS.md +43 -0
- package/connectors/wandb/CLAUDE.md +67 -0
- package/connectors/wandb/README.md +65 -0
- package/connectors/wandb/package.json +52 -0
- package/connectors/wandb/src/api/client.test.ts +116 -0
- package/connectors/wandb/src/api/client.ts +83 -0
- package/connectors/wandb/src/api/graphql.ts +9 -0
- package/connectors/wandb/src/api/index.ts +36 -0
- package/connectors/wandb/src/api/projects.ts +36 -0
- package/connectors/wandb/src/api/viewer.ts +20 -0
- package/connectors/wandb/src/cli/index.ts +265 -0
- package/connectors/wandb/src/index.ts +22 -0
- package/connectors/wandb/src/types/index.ts +75 -0
- package/connectors/wandb/src/utils/config.ts +164 -0
- package/connectors/wandb/src/utils/output.ts +119 -0
- package/connectors/wandb/tsconfig.json +16 -0
- package/connectors/weights-biases/.env.example +7 -0
- package/connectors/weights-biases/CLAUDE.md +65 -0
- package/connectors/weights-biases/README.md +62 -0
- package/connectors/weights-biases/package.json +53 -0
- package/connectors/weights-biases/src/api/client.test.ts +46 -0
- package/connectors/weights-biases/src/api/client.ts +119 -0
- package/connectors/weights-biases/src/api/events.ts +18 -0
- package/connectors/weights-biases/src/api/index.ts +56 -0
- package/connectors/weights-biases/src/api/runs.ts +28 -0
- package/connectors/weights-biases/src/api/search.ts +10 -0
- package/connectors/weights-biases/src/cli/index.ts +289 -0
- package/connectors/weights-biases/src/index.ts +19 -0
- package/connectors/weights-biases/src/types/index.ts +92 -0
- package/connectors/weights-biases/src/utils/config.ts +168 -0
- package/connectors/weights-biases/src/utils/output.ts +116 -0
- package/connectors/weights-biases/tsconfig.json +16 -0
- package/connectors/zoominfo/.env.example +4 -0
- package/connectors/zoominfo/AGENTS.md +26 -0
- package/connectors/zoominfo/CLAUDE.md +20 -0
- package/connectors/zoominfo/README.md +69 -0
- package/connectors/zoominfo/package.json +52 -0
- package/connectors/zoominfo/src/api/client.test.ts +140 -0
- package/connectors/zoominfo/src/api/client.ts +228 -0
- package/connectors/zoominfo/src/api/index.ts +1 -0
- package/connectors/zoominfo/src/cli/index.ts +179 -0
- package/connectors/zoominfo/src/index.ts +3 -0
- package/connectors/zoominfo/src/types/index.ts +39 -0
- package/connectors/zoominfo/src/utils/config.ts +61 -0
- package/connectors/zoominfo/src/utils/output.ts +27 -0
- package/connectors/zoominfo/tsconfig.json +20 -0
- package/connectors/zotero/.env.example +7 -0
- package/connectors/zotero/.npmrc.example +2 -0
- package/connectors/zotero/AGENTS.md +40 -0
- package/connectors/zotero/CLAUDE.md +69 -0
- package/connectors/zotero/README.md +91 -0
- package/connectors/zotero/package.json +43 -0
- package/connectors/zotero/src/api/attachments.ts +130 -0
- package/connectors/zotero/src/api/client.test.ts +166 -0
- package/connectors/zotero/src/api/client.ts +169 -0
- package/connectors/zotero/src/api/collections.ts +26 -0
- package/connectors/zotero/src/api/index.ts +45 -0
- package/connectors/zotero/src/api/items.ts +64 -0
- package/connectors/zotero/src/cli/index.ts +386 -0
- package/connectors/zotero/src/index.ts +28 -0
- package/connectors/zotero/src/types/index.ts +129 -0
- package/connectors/zotero/src/utils/config.ts +245 -0
- package/connectors/zotero/src/utils/output.ts +119 -0
- package/connectors/zotero/tsconfig.json +16 -0
- package/connectors/zymbly/.env.example +2 -0
- package/connectors/zymbly/AGENTS.md +11 -0
- package/connectors/zymbly/CLAUDE.md +5 -0
- package/connectors/zymbly/README.md +35 -0
- package/connectors/zymbly/package.json +52 -0
- package/connectors/zymbly/src/api/client.test.ts +110 -0
- package/connectors/zymbly/src/api/client.ts +166 -0
- package/connectors/zymbly/src/api/index.ts +1 -0
- package/connectors/zymbly/src/cli/index.ts +156 -0
- package/connectors/zymbly/src/index.ts +12 -0
- package/connectors/zymbly/src/types/index.ts +34 -0
- package/connectors/zymbly/src/utils/config.ts +52 -0
- package/connectors/zymbly/src/utils/output.ts +17 -0
- package/connectors/zymbly/tsconfig.json +13 -0
- package/dist/index.js +45 -2
- package/dist/lib/compact-output.d.ts +40 -0
- package/dist/mcp/tools/jobs.d.ts +32 -0
- package/dist/mcp/tools/jobs.test.d.ts +1 -0
- package/package.json +3 -2
|
@@ -2,23 +2,22 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { Tidio } from '../api';
|
|
5
|
-
import type {
|
|
5
|
+
import type { OutputFormat } from '../types';
|
|
6
6
|
import {
|
|
7
|
-
getApiKey,
|
|
8
|
-
setApiKey,
|
|
9
7
|
clearConfig,
|
|
8
|
+
createProfile,
|
|
9
|
+
deleteProfile,
|
|
10
|
+
getClientCredentials,
|
|
10
11
|
getConfigDir,
|
|
11
|
-
setProfileOverride,
|
|
12
12
|
getCurrentProfile,
|
|
13
|
-
setCurrentProfile,
|
|
14
13
|
listProfiles,
|
|
15
|
-
createProfile,
|
|
16
|
-
deleteProfile,
|
|
17
|
-
profileExists,
|
|
18
14
|
loadProfile,
|
|
15
|
+
profileExists,
|
|
16
|
+
setClientCredentials,
|
|
17
|
+
setCurrentProfile,
|
|
18
|
+
setProfileOverride,
|
|
19
19
|
} from '../utils/config';
|
|
20
|
-
import
|
|
21
|
-
import { success, error, info, print } from '../utils/output';
|
|
20
|
+
import { error, info, print, success } from '../utils/output';
|
|
22
21
|
|
|
23
22
|
const CONNECTOR_NAME = 'connect-tidio';
|
|
24
23
|
const VERSION = '0.0.1';
|
|
@@ -27,12 +26,13 @@ const program = new Command();
|
|
|
27
26
|
|
|
28
27
|
program
|
|
29
28
|
.name(CONNECTOR_NAME)
|
|
30
|
-
.description('Tidio connector -
|
|
29
|
+
.description('Tidio connector - contacts, contact messages, departments, operators, project, tickets, products, and Lyro')
|
|
31
30
|
.version(VERSION)
|
|
32
|
-
.option('
|
|
31
|
+
.option('--client-id <id>', 'OpenAPI client id (overrides config)')
|
|
32
|
+
.option('--client-secret <secret>', 'OpenAPI client secret (overrides config)')
|
|
33
33
|
.option('-f, --format <format>', 'Output format (json, pretty)', 'pretty')
|
|
34
34
|
.option('-p, --profile <profile>', 'Use a specific profile')
|
|
35
|
-
.hook('preAction',
|
|
35
|
+
.hook('preAction', thisCommand => {
|
|
36
36
|
const opts = thisCommand.opts();
|
|
37
37
|
if (opts.profile) {
|
|
38
38
|
if (!profileExists(opts.profile)) {
|
|
@@ -41,26 +41,25 @@ program
|
|
|
41
41
|
}
|
|
42
42
|
setProfileOverride(opts.profile);
|
|
43
43
|
}
|
|
44
|
-
if (opts.
|
|
45
|
-
|
|
46
|
-
}
|
|
44
|
+
if (opts.clientId) process.env.TIDIO_CLIENT_ID = opts.clientId;
|
|
45
|
+
if (opts.clientSecret) process.env.TIDIO_CLIENT_SECRET = opts.clientSecret;
|
|
47
46
|
});
|
|
48
47
|
|
|
49
48
|
function getFormat(cmd: Command): OutputFormat {
|
|
50
|
-
|
|
51
|
-
return (parent?.opts().format || 'pretty') as OutputFormat;
|
|
49
|
+
return (cmd.opts().format || cmd.parent?.opts().format || 'pretty') as OutputFormat;
|
|
52
50
|
}
|
|
53
51
|
|
|
54
52
|
function getClient(): Tidio {
|
|
55
|
-
const
|
|
56
|
-
if (!
|
|
57
|
-
error(
|
|
53
|
+
const { clientId, clientSecret } = getClientCredentials();
|
|
54
|
+
if (!clientId || !clientSecret) {
|
|
55
|
+
error(
|
|
56
|
+
`No Tidio credentials configured. Run "${CONNECTOR_NAME} config set-credentials <client-id> <client-secret>" or set TIDIO_CLIENT_ID and TIDIO_CLIENT_SECRET.`,
|
|
57
|
+
);
|
|
58
58
|
process.exit(1);
|
|
59
59
|
}
|
|
60
|
-
return new Tidio({
|
|
60
|
+
return new Tidio({ clientId, clientSecret });
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
// Profile Commands
|
|
64
63
|
const profileCmd = program.command('profile').description('Manage configuration profiles');
|
|
65
64
|
|
|
66
65
|
profileCmd.command('list').description('List all profiles').action(() => {
|
|
@@ -71,17 +70,13 @@ profileCmd.command('list').description('List all profiles').action(() => {
|
|
|
71
70
|
return;
|
|
72
71
|
}
|
|
73
72
|
success('Profiles:');
|
|
74
|
-
profiles.forEach(
|
|
75
|
-
const
|
|
76
|
-
console.log(` ${
|
|
73
|
+
profiles.forEach(profile => {
|
|
74
|
+
const active = profile === current ? chalk.green(' (active)') : '';
|
|
75
|
+
console.log(` ${profile}${active}`);
|
|
77
76
|
});
|
|
78
77
|
});
|
|
79
78
|
|
|
80
79
|
profileCmd.command('use <name>').description('Switch to a profile').action((name: string) => {
|
|
81
|
-
if (!profileExists(name)) {
|
|
82
|
-
error(`Profile "${name}" does not exist. Create it with "profile create ${name}"`);
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
80
|
setCurrentProfile(name);
|
|
86
81
|
success(`Switched to profile: ${name}`);
|
|
87
82
|
});
|
|
@@ -89,14 +84,14 @@ profileCmd.command('use <name>').description('Switch to a profile').action((name
|
|
|
89
84
|
profileCmd
|
|
90
85
|
.command('create <name>')
|
|
91
86
|
.description('Create a new profile')
|
|
92
|
-
.option('--
|
|
87
|
+
.option('--client-id <id>', 'OpenAPI client id')
|
|
88
|
+
.option('--client-secret <secret>', 'OpenAPI client secret')
|
|
93
89
|
.option('--use', 'Switch to this profile after creation')
|
|
94
90
|
.action((name: string, opts) => {
|
|
95
|
-
if (
|
|
91
|
+
if (!createProfile(name, { clientId: opts.clientId, clientSecret: opts.clientSecret })) {
|
|
96
92
|
error(`Profile "${name}" already exists`);
|
|
97
93
|
process.exit(1);
|
|
98
94
|
}
|
|
99
|
-
createProfile(name, { apiKey: opts.key });
|
|
100
95
|
success(`Profile "${name}" created`);
|
|
101
96
|
if (opts.use) {
|
|
102
97
|
setCurrentProfile(name);
|
|
@@ -105,16 +100,12 @@ profileCmd
|
|
|
105
100
|
});
|
|
106
101
|
|
|
107
102
|
profileCmd.command('delete <name>').description('Delete a profile').action((name: string) => {
|
|
108
|
-
if (name === 'default') {
|
|
109
|
-
error('Cannot delete the default profile');
|
|
110
|
-
process.exit(1);
|
|
111
|
-
}
|
|
112
103
|
if (deleteProfile(name)) {
|
|
113
104
|
success(`Profile "${name}" deleted`);
|
|
114
|
-
|
|
115
|
-
error(`Profile "${name}" not found`);
|
|
116
|
-
process.exit(1);
|
|
105
|
+
return;
|
|
117
106
|
}
|
|
107
|
+
error(`Profile "${name}" was not deleted`);
|
|
108
|
+
process.exit(1);
|
|
118
109
|
});
|
|
119
110
|
|
|
120
111
|
profileCmd.command('show [name]').description('Show profile configuration').action((name?: string) => {
|
|
@@ -122,23 +113,24 @@ profileCmd.command('show [name]').description('Show profile configuration').acti
|
|
|
122
113
|
const config = loadProfile(profileName);
|
|
123
114
|
const active = getCurrentProfile();
|
|
124
115
|
console.log(chalk.bold(`Profile: ${profileName}${profileName === active ? chalk.green(' (active)') : ''}`));
|
|
125
|
-
info(`
|
|
116
|
+
info(`Client ID: ${config.clientId ? `${config.clientId.substring(0, 8)}...` : chalk.gray('not set')}`);
|
|
117
|
+
info(`Client Secret: ${config.clientSecret ? chalk.gray('set') : chalk.gray('not set')}`);
|
|
126
118
|
});
|
|
127
119
|
|
|
128
|
-
// Config Commands
|
|
129
120
|
const configCmd = program.command('config').description('Manage CLI configuration');
|
|
130
121
|
|
|
131
|
-
configCmd.command('set-
|
|
132
|
-
|
|
133
|
-
success(`
|
|
122
|
+
configCmd.command('set-credentials <client-id> <client-secret>').description('Set OpenAPI credentials').action((clientId: string, clientSecret: string) => {
|
|
123
|
+
setClientCredentials(clientId, clientSecret);
|
|
124
|
+
success(`Credentials saved to profile: ${getCurrentProfile()}`);
|
|
134
125
|
});
|
|
135
126
|
|
|
136
127
|
configCmd.command('show').description('Show current configuration').action(() => {
|
|
137
128
|
const profileName = getCurrentProfile();
|
|
138
|
-
const
|
|
129
|
+
const { clientId, clientSecret } = getClientCredentials();
|
|
139
130
|
console.log(chalk.bold(`Active Profile: ${profileName}`));
|
|
140
131
|
info(`Config directory: ${getConfigDir()}`);
|
|
141
|
-
info(`
|
|
132
|
+
info(`Client ID: ${clientId ? `${clientId.substring(0, 8)}...` : chalk.gray('not set')}`);
|
|
133
|
+
info(`Client Secret: ${clientSecret ? chalk.gray('set') : chalk.gray('not set')}`);
|
|
142
134
|
});
|
|
143
135
|
|
|
144
136
|
configCmd.command('clear').description('Clear configuration').action(() => {
|
|
@@ -146,391 +138,165 @@ configCmd.command('clear').description('Clear configuration').action(() => {
|
|
|
146
138
|
success(`Configuration cleared for profile: ${getCurrentProfile()}`);
|
|
147
139
|
});
|
|
148
140
|
|
|
149
|
-
|
|
150
|
-
const contactCmd = program.command('contact').description('Manage contacts');
|
|
141
|
+
const contactCmd = program.command('contact').description('Manage contacts and contact messages');
|
|
151
142
|
|
|
152
|
-
contactCmd
|
|
153
|
-
.
|
|
154
|
-
|
|
155
|
-
.option('-n, --limit <number>', 'Results limit')
|
|
156
|
-
.option('--cursor <cursor>', 'Pagination cursor')
|
|
157
|
-
.option('--updated-after <iso>', 'Filter by updated after')
|
|
158
|
-
.option('--updated-before <iso>', 'Filter by updated before')
|
|
159
|
-
.action(async (opts) => {
|
|
160
|
-
try {
|
|
161
|
-
const client = getClient();
|
|
162
|
-
const result = await client.listContacts({
|
|
163
|
-
limit: opts.limit ? parseInt(opts.limit, 10) : undefined,
|
|
164
|
-
cursor: opts.cursor,
|
|
165
|
-
updatedAfter: opts.updatedAfter,
|
|
166
|
-
updatedBefore: opts.updatedBefore,
|
|
167
|
-
});
|
|
168
|
-
print(result, getFormat(contactCmd));
|
|
169
|
-
} catch (err) {
|
|
170
|
-
error(String(err));
|
|
171
|
-
process.exit(1);
|
|
172
|
-
}
|
|
173
|
-
});
|
|
143
|
+
contactCmd.command('list').description('List contacts').option('-n, --limit <number>').option('--cursor <cursor>').action(async opts => {
|
|
144
|
+
print(await getClient().listContacts({ limit: opts.limit ? Number(opts.limit) : undefined, cursor: opts.cursor }), getFormat(contactCmd));
|
|
145
|
+
});
|
|
174
146
|
|
|
175
|
-
contactCmd.command('get <id>').description('Get a contact
|
|
176
|
-
|
|
177
|
-
print(await getClient().getContact(id), getFormat(contactCmd));
|
|
178
|
-
} catch (err) {
|
|
179
|
-
error(String(err));
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
147
|
+
contactCmd.command('get <id>').description('Get a contact').action(async (id: string) => {
|
|
148
|
+
print(await getClient().getContact(id), getFormat(contactCmd));
|
|
182
149
|
});
|
|
183
150
|
|
|
184
151
|
contactCmd
|
|
185
152
|
.command('create')
|
|
186
153
|
.description('Create a contact')
|
|
187
|
-
.option('--email <email>'
|
|
188
|
-
.option('--phone <phone>'
|
|
189
|
-
.option('--name <name>'
|
|
190
|
-
.option('--
|
|
191
|
-
.option('--
|
|
192
|
-
.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
const result = await getClient().createContact({
|
|
154
|
+
.option('--email <email>')
|
|
155
|
+
.option('--phone <phone>')
|
|
156
|
+
.option('--first-name <name>')
|
|
157
|
+
.option('--last-name <name>')
|
|
158
|
+
.option('--distinct-id <id>')
|
|
159
|
+
.action(async opts => {
|
|
160
|
+
print(
|
|
161
|
+
await getClient().createContact({
|
|
197
162
|
email: opts.email,
|
|
198
163
|
phone: opts.phone,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
success('Contact created!');
|
|
206
|
-
print(result, getFormat(contactCmd));
|
|
207
|
-
} catch (err) {
|
|
208
|
-
error(String(err));
|
|
209
|
-
process.exit(1);
|
|
210
|
-
}
|
|
164
|
+
firstName: opts.firstName,
|
|
165
|
+
lastName: opts.lastName,
|
|
166
|
+
distinctId: opts.distinctId,
|
|
167
|
+
}),
|
|
168
|
+
getFormat(contactCmd),
|
|
169
|
+
);
|
|
211
170
|
});
|
|
212
171
|
|
|
213
172
|
contactCmd
|
|
214
173
|
.command('update <id>')
|
|
215
174
|
.description('Update a contact')
|
|
216
|
-
.option('--email <email>'
|
|
217
|
-
.option('--phone <phone>'
|
|
218
|
-
.option('--name <name>'
|
|
219
|
-
.option('--
|
|
220
|
-
.option('--
|
|
175
|
+
.option('--email <email>')
|
|
176
|
+
.option('--phone <phone>')
|
|
177
|
+
.option('--first-name <name>')
|
|
178
|
+
.option('--last-name <name>')
|
|
179
|
+
.option('--distinct-id <id>')
|
|
221
180
|
.action(async (id: string, opts) => {
|
|
222
|
-
|
|
223
|
-
|
|
181
|
+
print(
|
|
182
|
+
await getClient().updateContact(id, {
|
|
224
183
|
email: opts.email,
|
|
225
184
|
phone: opts.phone,
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
} catch (err) {
|
|
233
|
-
error(String(err));
|
|
234
|
-
process.exit(1);
|
|
235
|
-
}
|
|
185
|
+
firstName: opts.firstName,
|
|
186
|
+
lastName: opts.lastName,
|
|
187
|
+
distinctId: opts.distinctId,
|
|
188
|
+
}),
|
|
189
|
+
getFormat(contactCmd),
|
|
190
|
+
);
|
|
236
191
|
});
|
|
237
192
|
|
|
238
193
|
contactCmd.command('delete <id>').description('Delete a contact').action(async (id: string) => {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
success('Contact deleted!');
|
|
242
|
-
} catch (err) {
|
|
243
|
-
error(String(err));
|
|
244
|
-
process.exit(1);
|
|
245
|
-
}
|
|
194
|
+
await getClient().deleteContact(id);
|
|
195
|
+
success('Contact deleted');
|
|
246
196
|
});
|
|
247
197
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
conversationCmd
|
|
252
|
-
.command('list')
|
|
253
|
-
.description('List conversations')
|
|
254
|
-
.option('-n, --limit <number>', 'Results limit')
|
|
255
|
-
.option('--cursor <cursor>', 'Pagination cursor')
|
|
256
|
-
.option('--status <status>', 'Filter by status (open, closed, snoozed)')
|
|
257
|
-
.option('--channel <channel>', 'Filter by channel')
|
|
258
|
-
.option('--updated-after <iso>', 'Filter by updated after')
|
|
259
|
-
.action(async (opts) => {
|
|
260
|
-
try {
|
|
261
|
-
const result = await getClient().listConversations({
|
|
262
|
-
limit: opts.limit ? parseInt(opts.limit, 10) : undefined,
|
|
263
|
-
cursor: opts.cursor,
|
|
264
|
-
status: opts.status as ConversationStatus | undefined,
|
|
265
|
-
channel: opts.channel,
|
|
266
|
-
updatedAfter: opts.updatedAfter,
|
|
267
|
-
});
|
|
268
|
-
print(result, getFormat(conversationCmd));
|
|
269
|
-
} catch (err) {
|
|
270
|
-
error(String(err));
|
|
271
|
-
process.exit(1);
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
conversationCmd.command('get <id>').description('Get a conversation by ID').action(async (id: string) => {
|
|
276
|
-
try {
|
|
277
|
-
print(await getClient().getConversation(id), getFormat(conversationCmd));
|
|
278
|
-
} catch (err) {
|
|
279
|
-
error(String(err));
|
|
280
|
-
process.exit(1);
|
|
281
|
-
}
|
|
198
|
+
contactCmd.command('properties').description('Get contact property definitions').action(async () => {
|
|
199
|
+
print(await getClient().getContactProperties(), getFormat(contactCmd));
|
|
282
200
|
});
|
|
283
201
|
|
|
284
|
-
|
|
285
|
-
.
|
|
286
|
-
.description('List messages in a conversation')
|
|
287
|
-
.option('-n, --limit <number>', 'Results limit')
|
|
288
|
-
.option('--cursor <cursor>', 'Pagination cursor')
|
|
289
|
-
.action(async (id: string, opts) => {
|
|
290
|
-
try {
|
|
291
|
-
const result = await getClient().listConversationMessages(id, {
|
|
292
|
-
limit: opts.limit ? parseInt(opts.limit, 10) : undefined,
|
|
293
|
-
cursor: opts.cursor,
|
|
294
|
-
});
|
|
295
|
-
print(result, getFormat(conversationCmd));
|
|
296
|
-
} catch (err) {
|
|
297
|
-
error(String(err));
|
|
298
|
-
process.exit(1);
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
conversationCmd
|
|
303
|
-
.command('send <id>')
|
|
304
|
-
.description('Send a message in a conversation')
|
|
305
|
-
.requiredOption('--type <type>', 'Message type (text, image, file, note)')
|
|
306
|
-
.requiredOption('--content <content>', 'Message content')
|
|
307
|
-
.option('--media-url <url>', 'Media URL for image/file')
|
|
308
|
-
.option('--private', 'Send as private note')
|
|
309
|
-
.option('--operator-id <id>', 'Operator ID')
|
|
310
|
-
.action(async (id: string, opts) => {
|
|
311
|
-
try {
|
|
312
|
-
const result = await getClient().sendConversationMessage(id, {
|
|
313
|
-
type: opts.type as MessageType,
|
|
314
|
-
content: opts.content,
|
|
315
|
-
mediaUrl: opts.mediaUrl,
|
|
316
|
-
private: opts.private,
|
|
317
|
-
operatorId: opts.operatorId,
|
|
318
|
-
});
|
|
319
|
-
success('Message sent!');
|
|
320
|
-
print(result, getFormat(conversationCmd));
|
|
321
|
-
} catch (err) {
|
|
322
|
-
error(String(err));
|
|
323
|
-
process.exit(1);
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
conversationCmd
|
|
328
|
-
.command('status <id>')
|
|
329
|
-
.description('Set conversation status')
|
|
330
|
-
.requiredOption('--status <status>', 'Status (open, closed, snoozed)')
|
|
331
|
-
.option('--snoozed-until <iso>', 'Snooze until (ISO datetime)')
|
|
332
|
-
.action(async (id: string, opts) => {
|
|
333
|
-
try {
|
|
334
|
-
const result = await getClient().setConversationStatus(id, {
|
|
335
|
-
status: opts.status as ConversationStatus,
|
|
336
|
-
snoozedUntil: opts.snoozedUntil,
|
|
337
|
-
});
|
|
338
|
-
success('Conversation status updated!');
|
|
339
|
-
print(result, getFormat(conversationCmd));
|
|
340
|
-
} catch (err) {
|
|
341
|
-
error(String(err));
|
|
342
|
-
process.exit(1);
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
conversationCmd
|
|
347
|
-
.command('assign <id>')
|
|
348
|
-
.description('Assign a conversation')
|
|
349
|
-
.option('--operator-id <id>', 'Operator ID (omit with --unassign to clear)')
|
|
350
|
-
.option('--unassign', 'Unassign operator')
|
|
351
|
-
.option('--department-id <id>', 'Department ID')
|
|
352
|
-
.action(async (id: string, opts) => {
|
|
353
|
-
try {
|
|
354
|
-
const result = await getClient().assignConversation(id, {
|
|
355
|
-
operatorId: opts.unassign ? null : opts.operatorId ?? null,
|
|
356
|
-
departmentId: opts.departmentId,
|
|
357
|
-
});
|
|
358
|
-
success('Conversation assigned!');
|
|
359
|
-
print(result, getFormat(conversationCmd));
|
|
360
|
-
} catch (err) {
|
|
361
|
-
error(String(err));
|
|
362
|
-
process.exit(1);
|
|
363
|
-
}
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
// Operator Commands
|
|
367
|
-
const operatorCmd = program.command('operator').description('Manage operators');
|
|
368
|
-
|
|
369
|
-
operatorCmd.command('list').description('List operators').action(async () => {
|
|
370
|
-
try {
|
|
371
|
-
print(await getClient().listOperators(), getFormat(operatorCmd));
|
|
372
|
-
} catch (err) {
|
|
373
|
-
error(String(err));
|
|
374
|
-
process.exit(1);
|
|
375
|
-
}
|
|
202
|
+
contactCmd.command('viewed-pages <id>').description('Get viewed pages history').action(async (id: string) => {
|
|
203
|
+
print(await getClient().getContactViewedPages(id), getFormat(contactCmd));
|
|
376
204
|
});
|
|
377
205
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
print(await getClient().getOperator(id), getFormat(operatorCmd));
|
|
381
|
-
} catch (err) {
|
|
382
|
-
error(String(err));
|
|
383
|
-
process.exit(1);
|
|
384
|
-
}
|
|
206
|
+
contactCmd.command('messages <id>').description('List contact messages').option('--cursor <cursor>').action(async (id: string, opts) => {
|
|
207
|
+
print(await getClient().listContactMessages(id, { cursor: opts.cursor }), getFormat(contactCmd));
|
|
385
208
|
});
|
|
386
209
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
departmentCmd.command('list').description('List departments').action(async () => {
|
|
391
|
-
try {
|
|
392
|
-
print(await getClient().listDepartments(), getFormat(departmentCmd));
|
|
393
|
-
} catch (err) {
|
|
394
|
-
error(String(err));
|
|
395
|
-
process.exit(1);
|
|
396
|
-
}
|
|
210
|
+
contactCmd.command('send-message <id>').description('Send a message on behalf of a contact').requiredOption('-m, --message <message>').action(async (id: string, opts) => {
|
|
211
|
+
print(await getClient().sendContactMessage(id, { message: opts.message }), getFormat(contactCmd));
|
|
397
212
|
});
|
|
398
213
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
tagCmd.command('list').description('List tags').action(async () => {
|
|
403
|
-
try {
|
|
404
|
-
print(await getClient().listTags(), getFormat(tagCmd));
|
|
405
|
-
} catch (err) {
|
|
406
|
-
error(String(err));
|
|
407
|
-
process.exit(1);
|
|
408
|
-
}
|
|
214
|
+
program.command('operator').description('List operators').action(async () => {
|
|
215
|
+
print(await getClient().listOperators(), getFormat(program));
|
|
409
216
|
});
|
|
410
217
|
|
|
411
|
-
|
|
412
|
-
.
|
|
413
|
-
.description('Create a tag')
|
|
414
|
-
.option('--color <color>', 'Tag color')
|
|
415
|
-
.action(async (name: string, opts) => {
|
|
416
|
-
try {
|
|
417
|
-
const result = await getClient().createTag({ name, color: opts.color });
|
|
418
|
-
success('Tag created!');
|
|
419
|
-
print(result, getFormat(tagCmd));
|
|
420
|
-
} catch (err) {
|
|
421
|
-
error(String(err));
|
|
422
|
-
process.exit(1);
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
tagCmd.command('delete <id>').description('Delete a tag').action(async (id: string) => {
|
|
427
|
-
try {
|
|
428
|
-
await getClient().deleteTag(id);
|
|
429
|
-
success('Tag deleted!');
|
|
430
|
-
} catch (err) {
|
|
431
|
-
error(String(err));
|
|
432
|
-
process.exit(1);
|
|
433
|
-
}
|
|
218
|
+
program.command('department').description('List departments').action(async () => {
|
|
219
|
+
print(await getClient().listDepartments(), getFormat(program));
|
|
434
220
|
});
|
|
435
221
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
automationCmd.command('list').description('List automations').action(async () => {
|
|
440
|
-
try {
|
|
441
|
-
print(await getClient().listAutomations(), getFormat(automationCmd));
|
|
442
|
-
} catch (err) {
|
|
443
|
-
error(String(err));
|
|
444
|
-
process.exit(1);
|
|
445
|
-
}
|
|
222
|
+
program.command('project').description('Get project info').action(async () => {
|
|
223
|
+
print(await getClient().getProject(), getFormat(program));
|
|
446
224
|
});
|
|
447
225
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
226
|
+
const ticketCmd = program.command('ticket').description('Manage tickets');
|
|
227
|
+
|
|
228
|
+
ticketCmd.command('list').option('-n, --limit <number>').option('--cursor <cursor>').option('--status <status>').option('--priority <priority>').action(async opts => {
|
|
229
|
+
print(
|
|
230
|
+
await getClient().listTickets({
|
|
231
|
+
limit: opts.limit ? Number(opts.limit) : undefined,
|
|
232
|
+
cursor: opts.cursor,
|
|
233
|
+
status: opts.status,
|
|
234
|
+
priority: opts.priority,
|
|
235
|
+
}),
|
|
236
|
+
getFormat(ticketCmd),
|
|
237
|
+
);
|
|
458
238
|
});
|
|
459
239
|
|
|
460
|
-
|
|
461
|
-
.
|
|
462
|
-
.description('Create a canned response')
|
|
463
|
-
.requiredOption('--shortcut <shortcut>', 'Shortcut keyword')
|
|
464
|
-
.requiredOption('--content <content>', 'Response content')
|
|
465
|
-
.option('--department-id <id>', 'Department ID')
|
|
466
|
-
.action(async (opts) => {
|
|
467
|
-
try {
|
|
468
|
-
const result = await getClient().createCannedResponse({
|
|
469
|
-
shortcut: opts.shortcut,
|
|
470
|
-
content: opts.content,
|
|
471
|
-
departmentId: opts.departmentId,
|
|
472
|
-
});
|
|
473
|
-
success('Canned response created!');
|
|
474
|
-
print(result, getFormat(cannedCmd));
|
|
475
|
-
} catch (err) {
|
|
476
|
-
error(String(err));
|
|
477
|
-
process.exit(1);
|
|
478
|
-
}
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
// Webhook Commands
|
|
482
|
-
const webhookCmd = program.command('webhook').description('Manage webhooks');
|
|
483
|
-
|
|
484
|
-
webhookCmd.command('list').description('List webhooks').action(async () => {
|
|
485
|
-
try {
|
|
486
|
-
print(await getClient().listWebhooks(), getFormat(webhookCmd));
|
|
487
|
-
} catch (err) {
|
|
488
|
-
error(String(err));
|
|
489
|
-
process.exit(1);
|
|
490
|
-
}
|
|
240
|
+
ticketCmd.command('get <id>').action(async (id: string) => {
|
|
241
|
+
print(await getClient().getTicket(id), getFormat(ticketCmd));
|
|
491
242
|
});
|
|
492
243
|
|
|
493
|
-
|
|
494
|
-
.
|
|
495
|
-
|
|
496
|
-
.requiredOption('--url <url>', 'Webhook URL')
|
|
497
|
-
.requiredOption('--events <events>', 'Comma-separated events')
|
|
498
|
-
.option('--secret <secret>', 'Webhook secret')
|
|
499
|
-
.action(async (opts) => {
|
|
500
|
-
try {
|
|
501
|
-
const result = await getClient().createWebhook({
|
|
502
|
-
url: opts.url,
|
|
503
|
-
events: opts.events.split(',').map((e: string) => e.trim()) as WebhookEvent[],
|
|
504
|
-
secret: opts.secret,
|
|
505
|
-
});
|
|
506
|
-
success('Webhook created!');
|
|
507
|
-
print(result, getFormat(webhookCmd));
|
|
508
|
-
} catch (err) {
|
|
509
|
-
error(String(err));
|
|
510
|
-
process.exit(1);
|
|
511
|
-
}
|
|
512
|
-
});
|
|
244
|
+
ticketCmd.command('reply <id>').requiredOption('-m, --message <message>').option('--author-type <type>').action(async (id: string, opts) => {
|
|
245
|
+
print(await getClient().replyToTicket(id, { message: opts.message, authorType: opts.authorType }), getFormat(ticketCmd));
|
|
246
|
+
});
|
|
513
247
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
await getClient().deleteWebhook(id);
|
|
517
|
-
success('Webhook deleted!');
|
|
518
|
-
} catch (err) {
|
|
519
|
-
error(String(err));
|
|
520
|
-
process.exit(1);
|
|
521
|
-
}
|
|
248
|
+
ticketCmd.command('tags').description('Get ticket tags').action(async () => {
|
|
249
|
+
print(await getClient().getTicketTags(), getFormat(ticketCmd));
|
|
522
250
|
});
|
|
523
251
|
|
|
524
|
-
|
|
525
|
-
|
|
252
|
+
ticketCmd.command('custom-fields').description('Get ticket custom fields').action(async () => {
|
|
253
|
+
print(await getClient().getTicketCustomFields(), getFormat(ticketCmd));
|
|
254
|
+
});
|
|
526
255
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
256
|
+
const lyroCmd = program.command('lyro').description('Manage Lyro data sources');
|
|
257
|
+
|
|
258
|
+
lyroCmd.command('sources').option('-n, --limit <number>').option('--cursor <cursor>').option('--kind <kind>').action(async opts => {
|
|
259
|
+
print(
|
|
260
|
+
await getClient().listLyroDataSources({
|
|
261
|
+
limit: opts.limit ? Number(opts.limit) : undefined,
|
|
262
|
+
cursor: opts.cursor,
|
|
263
|
+
kind: opts.kind,
|
|
264
|
+
}),
|
|
265
|
+
getFormat(lyroCmd),
|
|
266
|
+
);
|
|
534
267
|
});
|
|
535
268
|
|
|
269
|
+
lyroCmd
|
|
270
|
+
.command('ask-ticket')
|
|
271
|
+
.description('Ask Lyro to answer a ticket from a single contact message')
|
|
272
|
+
.requiredOption('--ticket-id <id>')
|
|
273
|
+
.requiredOption('--subject <subject>')
|
|
274
|
+
.requiredOption('--contact-email <email>')
|
|
275
|
+
.requiredOption('--contact-name <name>')
|
|
276
|
+
.requiredOption('--recipient-email <email>')
|
|
277
|
+
.requiredOption('--message-id <id>')
|
|
278
|
+
.requiredOption('--message <message>')
|
|
279
|
+
.option('--created-at <iso>', 'Message creation timestamp', new Date().toISOString())
|
|
280
|
+
.action(async opts => {
|
|
281
|
+
print(
|
|
282
|
+
await getClient().askLyroToAnswerTicket({
|
|
283
|
+
ticketId: opts.ticketId,
|
|
284
|
+
subject: opts.subject,
|
|
285
|
+
contactEmail: opts.contactEmail,
|
|
286
|
+
contactName: opts.contactName,
|
|
287
|
+
recipientEmail: opts.recipientEmail,
|
|
288
|
+
messages: [
|
|
289
|
+
{
|
|
290
|
+
created_at: opts.createdAt,
|
|
291
|
+
message_id: opts.messageId,
|
|
292
|
+
author_type: 'contact',
|
|
293
|
+
message_type: 'public',
|
|
294
|
+
message_content: opts.message,
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
}),
|
|
298
|
+
getFormat(lyroCmd),
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
|
|
536
302
|
program.parse();
|