@hasna/connectors 0.3.16 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/bin/index.js +71 -1
  2. package/bin/mcp.js +71 -1
  3. package/bin/serve.js +70 -0
  4. package/connectors/connect-asana/.env.example +11 -0
  5. package/connectors/connect-asana/CLAUDE.md +128 -0
  6. package/connectors/connect-asana/README.md +193 -0
  7. package/connectors/connect-asana/package.json +52 -0
  8. package/connectors/connect-asana/src/api/client.ts +119 -0
  9. package/connectors/connect-asana/src/api/index.ts +319 -0
  10. package/connectors/connect-asana/src/cli/index.ts +731 -0
  11. package/connectors/connect-asana/src/index.ts +19 -0
  12. package/connectors/connect-asana/src/types/index.ts +270 -0
  13. package/connectors/connect-asana/src/utils/config.ts +171 -0
  14. package/connectors/connect-asana/src/utils/output.ts +119 -0
  15. package/connectors/connect-asana/tsconfig.json +16 -0
  16. package/connectors/connect-clickup/.env.example +11 -0
  17. package/connectors/connect-clickup/CLAUDE.md +128 -0
  18. package/connectors/connect-clickup/README.md +193 -0
  19. package/connectors/connect-clickup/package.json +52 -0
  20. package/connectors/connect-clickup/src/api/client.ts +116 -0
  21. package/connectors/connect-clickup/src/api/index.ts +400 -0
  22. package/connectors/connect-clickup/src/cli/index.ts +625 -0
  23. package/connectors/connect-clickup/src/index.ts +19 -0
  24. package/connectors/connect-clickup/src/types/index.ts +591 -0
  25. package/connectors/connect-clickup/src/utils/config.ts +157 -0
  26. package/connectors/connect-clickup/src/utils/output.ts +119 -0
  27. package/connectors/connect-clickup/tsconfig.json +16 -0
  28. package/connectors/connect-confluence/.env.example +11 -0
  29. package/connectors/connect-confluence/CLAUDE.md +272 -0
  30. package/connectors/connect-confluence/README.md +193 -0
  31. package/connectors/connect-confluence/package.json +53 -0
  32. package/connectors/connect-confluence/scripts/release.ts +179 -0
  33. package/connectors/connect-confluence/src/api/client.ts +213 -0
  34. package/connectors/connect-confluence/src/api/example.ts +48 -0
  35. package/connectors/connect-confluence/src/api/index.ts +51 -0
  36. package/connectors/connect-confluence/src/cli/index.ts +254 -0
  37. package/connectors/connect-confluence/src/index.ts +103 -0
  38. package/connectors/connect-confluence/src/types/index.ts +237 -0
  39. package/connectors/connect-confluence/src/utils/auth.ts +274 -0
  40. package/connectors/connect-confluence/src/utils/bulk.ts +212 -0
  41. package/connectors/connect-confluence/src/utils/config.ts +326 -0
  42. package/connectors/connect-confluence/src/utils/output.ts +175 -0
  43. package/connectors/connect-confluence/src/utils/settings.ts +114 -0
  44. package/connectors/connect-confluence/src/utils/storage.ts +198 -0
  45. package/connectors/connect-confluence/tsconfig.json +16 -0
  46. package/connectors/connect-jira/.env.example +11 -0
  47. package/connectors/connect-jira/CLAUDE.md +128 -0
  48. package/connectors/connect-jira/README.md +193 -0
  49. package/connectors/connect-jira/package.json +53 -0
  50. package/connectors/connect-jira/src/api/client.ts +131 -0
  51. package/connectors/connect-jira/src/api/index.ts +266 -0
  52. package/connectors/connect-jira/src/cli/index.ts +653 -0
  53. package/connectors/connect-jira/src/index.ts +23 -0
  54. package/connectors/connect-jira/src/types/index.ts +448 -0
  55. package/connectors/connect-jira/src/utils/config.ts +179 -0
  56. package/connectors/connect-jira/src/utils/output.ts +119 -0
  57. package/connectors/connect-jira/tsconfig.json +16 -0
  58. package/connectors/connect-linear/CLAUDE.md +88 -0
  59. package/connectors/connect-linear/README.md +201 -0
  60. package/connectors/connect-linear/package.json +45 -0
  61. package/connectors/connect-linear/src/api/client.ts +62 -0
  62. package/connectors/connect-linear/src/api/index.ts +46 -0
  63. package/connectors/connect-linear/src/api/issues.ts +247 -0
  64. package/connectors/connect-linear/src/api/projects.ts +179 -0
  65. package/connectors/connect-linear/src/api/teams.ts +125 -0
  66. package/connectors/connect-linear/src/api/users.ts +112 -0
  67. package/connectors/connect-linear/src/cli/index.ts +560 -0
  68. package/connectors/connect-linear/src/index.ts +27 -0
  69. package/connectors/connect-linear/src/types/index.ts +275 -0
  70. package/connectors/connect-linear/src/utils/config.ts +249 -0
  71. package/connectors/connect-linear/src/utils/output.ts +119 -0
  72. package/connectors/connect-linear/tsconfig.json +16 -0
  73. package/connectors/connect-slack/.env.example +7 -0
  74. package/connectors/connect-slack/CLAUDE.md +69 -0
  75. package/connectors/connect-slack/README.md +150 -0
  76. package/connectors/connect-slack/package.json +44 -0
  77. package/connectors/connect-slack/src/api/channels.ts +112 -0
  78. package/connectors/connect-slack/src/api/client.ts +97 -0
  79. package/connectors/connect-slack/src/api/index.ts +42 -0
  80. package/connectors/connect-slack/src/api/messages.ts +127 -0
  81. package/connectors/connect-slack/src/api/users.ts +110 -0
  82. package/connectors/connect-slack/src/cli/index.ts +494 -0
  83. package/connectors/connect-slack/src/index.ts +21 -0
  84. package/connectors/connect-slack/src/types/index.ts +263 -0
  85. package/connectors/connect-slack/src/utils/config.ts +297 -0
  86. package/connectors/connect-slack/src/utils/output.ts +119 -0
  87. package/connectors/connect-slack/tsconfig.json +16 -0
  88. package/connectors/connect-telegram/.env.example +2 -0
  89. package/connectors/connect-telegram/package.json +49 -0
  90. package/connectors/connect-todoist/.env.example +11 -0
  91. package/connectors/connect-todoist/CLAUDE.md +104 -0
  92. package/connectors/connect-todoist/README.md +193 -0
  93. package/connectors/connect-todoist/package.json +52 -0
  94. package/connectors/connect-todoist/src/api/client.ts +117 -0
  95. package/connectors/connect-todoist/src/api/index.ts +188 -0
  96. package/connectors/connect-todoist/src/cli/index.ts +990 -0
  97. package/connectors/connect-todoist/src/index.ts +21 -0
  98. package/connectors/connect-todoist/src/types/index.ts +240 -0
  99. package/connectors/connect-todoist/src/utils/config.ts +157 -0
  100. package/connectors/connect-todoist/src/utils/output.ts +119 -0
  101. package/connectors/connect-todoist/tsconfig.json +16 -0
  102. package/connectors/connect-trello/.env.example +11 -0
  103. package/connectors/connect-trello/CLAUDE.md +128 -0
  104. package/connectors/connect-trello/README.md +193 -0
  105. package/connectors/connect-trello/package.json +53 -0
  106. package/connectors/connect-trello/src/api/client.ts +128 -0
  107. package/connectors/connect-trello/src/api/index.ts +278 -0
  108. package/connectors/connect-trello/src/cli/index.ts +737 -0
  109. package/connectors/connect-trello/src/index.ts +21 -0
  110. package/connectors/connect-trello/src/types/index.ts +314 -0
  111. package/connectors/connect-trello/src/utils/config.ts +182 -0
  112. package/connectors/connect-trello/src/utils/output.ts +119 -0
  113. package/connectors/connect-trello/tsconfig.json +16 -0
  114. package/connectors/connect-whatsapp/.env.example +11 -0
  115. package/connectors/connect-whatsapp/CLAUDE.md +113 -0
  116. package/connectors/connect-whatsapp/README.md +193 -0
  117. package/connectors/connect-whatsapp/package.json +53 -0
  118. package/connectors/connect-whatsapp/src/api/client.ts +133 -0
  119. package/connectors/connect-whatsapp/src/api/index.ts +365 -0
  120. package/connectors/connect-whatsapp/src/cli/index.ts +686 -0
  121. package/connectors/connect-whatsapp/src/index.ts +25 -0
  122. package/connectors/connect-whatsapp/src/types/index.ts +502 -0
  123. package/connectors/connect-whatsapp/src/utils/config.ts +179 -0
  124. package/connectors/connect-whatsapp/src/utils/output.ts +119 -0
  125. package/connectors/connect-whatsapp/tsconfig.json +16 -0
  126. package/dist/index.js +70 -0
  127. package/package.json +1 -1
@@ -0,0 +1,737 @@
1
+ #!/usr/bin/env bun
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import { Trello } from '../api';
5
+ import {
6
+ getApiKey,
7
+ setApiKey,
8
+ getToken,
9
+ setToken,
10
+ clearConfig,
11
+ getConfigDir,
12
+ setProfileOverride,
13
+ getCurrentProfile,
14
+ setCurrentProfile,
15
+ listProfiles,
16
+ createProfile,
17
+ deleteProfile,
18
+ profileExists,
19
+ loadProfile,
20
+ } from '../utils/config';
21
+ import type { OutputFormat } from '../utils/output';
22
+ import { success, error, info, print, warn } from '../utils/output';
23
+
24
+ const CONNECTOR_NAME = 'connect-trello';
25
+ const VERSION = '0.0.1';
26
+
27
+ const program = new Command();
28
+
29
+ program
30
+ .name(CONNECTOR_NAME)
31
+ .description('Trello connector - Boards, lists, cards, and checklists management')
32
+ .version(VERSION)
33
+ .option('-k, --api-key <key>', 'API key (overrides config)')
34
+ .option('-t, --token <token>', 'Token (overrides config)')
35
+ .option('-f, --format <format>', 'Output format (json, pretty)', 'pretty')
36
+ .option('-p, --profile <profile>', 'Use a specific profile')
37
+ .hook('preAction', (thisCommand) => {
38
+ const opts = thisCommand.opts();
39
+ if (opts.profile) {
40
+ if (!profileExists(opts.profile)) {
41
+ error(`Profile "${opts.profile}" does not exist. Create it with "${CONNECTOR_NAME} profile create ${opts.profile}"`);
42
+ process.exit(1);
43
+ }
44
+ setProfileOverride(opts.profile);
45
+ }
46
+ if (opts.apiKey) {
47
+ process.env.TRELLO_API_KEY = opts.apiKey;
48
+ }
49
+ if (opts.token) {
50
+ process.env.TRELLO_TOKEN = opts.token;
51
+ }
52
+ });
53
+
54
+ function getFormat(cmd: Command): OutputFormat {
55
+ const parent = cmd.parent;
56
+ return (parent?.opts().format || 'pretty') as OutputFormat;
57
+ }
58
+
59
+ function getClient(): Trello {
60
+ const apiKey = getApiKey();
61
+ const token = getToken();
62
+ if (!apiKey) {
63
+ error(`No API key configured. Run "${CONNECTOR_NAME} config set-key <key>" or set TRELLO_API_KEY environment variable.`);
64
+ process.exit(1);
65
+ }
66
+ if (!token) {
67
+ error(`No token configured. Run "${CONNECTOR_NAME} config set-token <token>" or set TRELLO_TOKEN environment variable.`);
68
+ process.exit(1);
69
+ }
70
+ return new Trello({ apiKey, token });
71
+ }
72
+
73
+ // ============================================
74
+ // Profile Commands
75
+ // ============================================
76
+ const profileCmd = program
77
+ .command('profile')
78
+ .description('Manage configuration profiles');
79
+
80
+ profileCmd
81
+ .command('list')
82
+ .description('List all profiles')
83
+ .action(() => {
84
+ const profiles = listProfiles();
85
+ const current = getCurrentProfile();
86
+
87
+ if (profiles.length === 0) {
88
+ info('No profiles found. Use "profile create <name>" to create one.');
89
+ return;
90
+ }
91
+
92
+ success(`Profiles:`);
93
+ profiles.forEach(p => {
94
+ const isActive = p === current ? chalk.green(' (active)') : '';
95
+ console.log(` ${p}${isActive}`);
96
+ });
97
+ });
98
+
99
+ profileCmd
100
+ .command('use <name>')
101
+ .description('Switch to a profile')
102
+ .action((name: string) => {
103
+ if (!profileExists(name)) {
104
+ error(`Profile "${name}" does not exist. Create it with "profile create ${name}"`);
105
+ process.exit(1);
106
+ }
107
+ setCurrentProfile(name);
108
+ success(`Switched to profile: ${name}`);
109
+ });
110
+
111
+ profileCmd
112
+ .command('create <name>')
113
+ .description('Create a new profile')
114
+ .option('--api-key <key>', 'API key')
115
+ .option('--token <token>', 'Token')
116
+ .option('--use', 'Switch to this profile after creation')
117
+ .action((name: string, opts) => {
118
+ if (profileExists(name)) {
119
+ error(`Profile "${name}" already exists`);
120
+ process.exit(1);
121
+ }
122
+
123
+ createProfile(name, {
124
+ apiKey: opts.apiKey,
125
+ token: opts.token,
126
+ });
127
+ success(`Profile "${name}" created`);
128
+
129
+ if (opts.use) {
130
+ setCurrentProfile(name);
131
+ info(`Switched to profile: ${name}`);
132
+ }
133
+ });
134
+
135
+ profileCmd
136
+ .command('delete <name>')
137
+ .description('Delete a profile')
138
+ .action((name: string) => {
139
+ if (name === 'default') {
140
+ error('Cannot delete the default profile');
141
+ process.exit(1);
142
+ }
143
+ if (deleteProfile(name)) {
144
+ success(`Profile "${name}" deleted`);
145
+ } else {
146
+ error(`Profile "${name}" not found`);
147
+ process.exit(1);
148
+ }
149
+ });
150
+
151
+ profileCmd
152
+ .command('show [name]')
153
+ .description('Show profile configuration')
154
+ .action((name?: string) => {
155
+ const profileName = name || getCurrentProfile();
156
+ const config = loadProfile(profileName);
157
+ const active = getCurrentProfile();
158
+
159
+ console.log(chalk.bold(`Profile: ${profileName}${profileName === active ? chalk.green(' (active)') : ''}`));
160
+ info(`API Key: ${config.apiKey ? `${config.apiKey.substring(0, 8)}...` : chalk.gray('not set')}`);
161
+ info(`Token: ${config.token ? `${config.token.substring(0, 8)}...` : chalk.gray('not set')}`);
162
+ });
163
+
164
+ // ============================================
165
+ // Config Commands
166
+ // ============================================
167
+ const configCmd = program
168
+ .command('config')
169
+ .description('Manage CLI configuration (for active profile)');
170
+
171
+ configCmd
172
+ .command('set-key <apiKey>')
173
+ .description('Set API key')
174
+ .action((apiKey: string) => {
175
+ setApiKey(apiKey);
176
+ success(`API key saved to profile: ${getCurrentProfile()}`);
177
+ });
178
+
179
+ configCmd
180
+ .command('set-token <token>')
181
+ .description('Set token')
182
+ .action((token: string) => {
183
+ setToken(token);
184
+ success(`Token saved to profile: ${getCurrentProfile()}`);
185
+ });
186
+
187
+ configCmd
188
+ .command('show')
189
+ .description('Show current configuration')
190
+ .action(() => {
191
+ const profileName = getCurrentProfile();
192
+ const apiKey = getApiKey();
193
+ const token = getToken();
194
+
195
+ console.log(chalk.bold(`Active Profile: ${profileName}`));
196
+ info(`Config directory: ${getConfigDir()}`);
197
+ info(`API Key: ${apiKey ? `${apiKey.substring(0, 8)}...` : chalk.gray('not set')}`);
198
+ info(`Token: ${token ? `${token.substring(0, 8)}...` : chalk.gray('not set')}`);
199
+ });
200
+
201
+ configCmd
202
+ .command('clear')
203
+ .description('Clear configuration for active profile')
204
+ .action(() => {
205
+ clearConfig();
206
+ success(`Configuration cleared for profile: ${getCurrentProfile()}`);
207
+ });
208
+
209
+ // ============================================
210
+ // Member Commands
211
+ // ============================================
212
+ const memberCmd = program
213
+ .command('member')
214
+ .description('Member management');
215
+
216
+ memberCmd
217
+ .command('me')
218
+ .description('Get current member')
219
+ .action(async () => {
220
+ try {
221
+ const client = getClient();
222
+ const result = await client.getMe();
223
+ print(result, getFormat(memberCmd));
224
+ } catch (err) {
225
+ error(String(err));
226
+ process.exit(1);
227
+ }
228
+ });
229
+
230
+ memberCmd
231
+ .command('get <idOrUsername>')
232
+ .description('Get a member by ID or username')
233
+ .action(async (idOrUsername: string) => {
234
+ try {
235
+ const client = getClient();
236
+ const result = await client.getMember(idOrUsername);
237
+ print(result, getFormat(memberCmd));
238
+ } catch (err) {
239
+ error(String(err));
240
+ process.exit(1);
241
+ }
242
+ });
243
+
244
+ memberCmd
245
+ .command('boards')
246
+ .description('List boards for a member')
247
+ .option('--member <idOrUsername>', 'Member ID or username', 'me')
248
+ .action(async (opts) => {
249
+ try {
250
+ const client = getClient();
251
+ const result = await client.getMemberBoards(opts.member);
252
+ print(result, getFormat(memberCmd));
253
+ } catch (err) {
254
+ error(String(err));
255
+ process.exit(1);
256
+ }
257
+ });
258
+
259
+ // ============================================
260
+ // Board Commands
261
+ // ============================================
262
+ const boardCmd = program
263
+ .command('board')
264
+ .description('Board management');
265
+
266
+ boardCmd
267
+ .command('list')
268
+ .description('List all boards for current user')
269
+ .action(async () => {
270
+ try {
271
+ const client = getClient();
272
+ const result = await client.getMemberBoards('me');
273
+ print(result, getFormat(boardCmd));
274
+ } catch (err) {
275
+ error(String(err));
276
+ process.exit(1);
277
+ }
278
+ });
279
+
280
+ boardCmd
281
+ .command('get <id>')
282
+ .description('Get a board by ID')
283
+ .action(async (id: string) => {
284
+ try {
285
+ const client = getClient();
286
+ const result = await client.getBoard(id);
287
+ print(result, getFormat(boardCmd));
288
+ } catch (err) {
289
+ error(String(err));
290
+ process.exit(1);
291
+ }
292
+ });
293
+
294
+ boardCmd
295
+ .command('create')
296
+ .description('Create a new board')
297
+ .requiredOption('--name <name>', 'Board name')
298
+ .option('--desc <desc>', 'Board description')
299
+ .action(async (opts) => {
300
+ try {
301
+ const client = getClient();
302
+ const result = await client.createBoard({
303
+ name: opts.name,
304
+ desc: opts.desc,
305
+ });
306
+ success('Board created!');
307
+ print(result, getFormat(boardCmd));
308
+ } catch (err) {
309
+ error(String(err));
310
+ process.exit(1);
311
+ }
312
+ });
313
+
314
+ boardCmd
315
+ .command('delete <id>')
316
+ .description('Delete a board')
317
+ .action(async (id: string) => {
318
+ try {
319
+ const client = getClient();
320
+ await client.deleteBoard(id);
321
+ success(`Board ${id} deleted`);
322
+ } catch (err) {
323
+ error(String(err));
324
+ process.exit(1);
325
+ }
326
+ });
327
+
328
+ boardCmd
329
+ .command('lists <boardId>')
330
+ .description('Get lists on a board')
331
+ .option('--filter <filter>', 'Filter (all, open, closed)', 'open')
332
+ .action(async (boardId: string, opts) => {
333
+ try {
334
+ const client = getClient();
335
+ const result = await client.getBoardLists(boardId, opts.filter);
336
+ print(result, getFormat(boardCmd));
337
+ } catch (err) {
338
+ error(String(err));
339
+ process.exit(1);
340
+ }
341
+ });
342
+
343
+ boardCmd
344
+ .command('cards <boardId>')
345
+ .description('Get cards on a board')
346
+ .option('--filter <filter>', 'Filter (all, open, closed, visible)', 'open')
347
+ .action(async (boardId: string, opts) => {
348
+ try {
349
+ const client = getClient();
350
+ const result = await client.getBoardCards(boardId, opts.filter);
351
+ print(result, getFormat(boardCmd));
352
+ } catch (err) {
353
+ error(String(err));
354
+ process.exit(1);
355
+ }
356
+ });
357
+
358
+ boardCmd
359
+ .command('labels <boardId>')
360
+ .description('Get labels on a board')
361
+ .action(async (boardId: string) => {
362
+ try {
363
+ const client = getClient();
364
+ const result = await client.getBoardLabels(boardId);
365
+ print(result, getFormat(boardCmd));
366
+ } catch (err) {
367
+ error(String(err));
368
+ process.exit(1);
369
+ }
370
+ });
371
+
372
+ // ============================================
373
+ // List Commands
374
+ // ============================================
375
+ const listCmd = program
376
+ .command('list')
377
+ .description('List management');
378
+
379
+ listCmd
380
+ .command('get <id>')
381
+ .description('Get a list by ID')
382
+ .action(async (id: string) => {
383
+ try {
384
+ const client = getClient();
385
+ const result = await client.getList(id);
386
+ print(result, getFormat(listCmd));
387
+ } catch (err) {
388
+ error(String(err));
389
+ process.exit(1);
390
+ }
391
+ });
392
+
393
+ listCmd
394
+ .command('create')
395
+ .description('Create a new list')
396
+ .requiredOption('--name <name>', 'List name')
397
+ .requiredOption('--board <boardId>', 'Board ID')
398
+ .option('--pos <pos>', 'Position (top, bottom, or number)')
399
+ .action(async (opts) => {
400
+ try {
401
+ const client = getClient();
402
+ const result = await client.createList({
403
+ name: opts.name,
404
+ idBoard: opts.board,
405
+ pos: opts.pos,
406
+ });
407
+ success('List created!');
408
+ print(result, getFormat(listCmd));
409
+ } catch (err) {
410
+ error(String(err));
411
+ process.exit(1);
412
+ }
413
+ });
414
+
415
+ listCmd
416
+ .command('archive <id>')
417
+ .description('Archive a list')
418
+ .action(async (id: string) => {
419
+ try {
420
+ const client = getClient();
421
+ await client.archiveList(id);
422
+ success(`List ${id} archived`);
423
+ } catch (err) {
424
+ error(String(err));
425
+ process.exit(1);
426
+ }
427
+ });
428
+
429
+ listCmd
430
+ .command('cards <listId>')
431
+ .description('Get cards in a list')
432
+ .action(async (listId: string) => {
433
+ try {
434
+ const client = getClient();
435
+ const result = await client.getListCards(listId);
436
+ print(result, getFormat(listCmd));
437
+ } catch (err) {
438
+ error(String(err));
439
+ process.exit(1);
440
+ }
441
+ });
442
+
443
+ // ============================================
444
+ // Card Commands
445
+ // ============================================
446
+ const cardCmd = program
447
+ .command('card')
448
+ .description('Card management');
449
+
450
+ cardCmd
451
+ .command('get <id>')
452
+ .description('Get a card by ID')
453
+ .action(async (id: string) => {
454
+ try {
455
+ const client = getClient();
456
+ const result = await client.getCard(id);
457
+ print(result, getFormat(cardCmd));
458
+ } catch (err) {
459
+ error(String(err));
460
+ process.exit(1);
461
+ }
462
+ });
463
+
464
+ cardCmd
465
+ .command('create')
466
+ .description('Create a new card')
467
+ .requiredOption('--name <name>', 'Card name')
468
+ .requiredOption('--list <listId>', 'List ID')
469
+ .option('--desc <desc>', 'Card description')
470
+ .option('--due <date>', 'Due date')
471
+ .option('--pos <pos>', 'Position (top, bottom, or number)')
472
+ .action(async (opts) => {
473
+ try {
474
+ const client = getClient();
475
+ const result = await client.createCard({
476
+ name: opts.name,
477
+ idList: opts.list,
478
+ desc: opts.desc,
479
+ due: opts.due,
480
+ pos: opts.pos,
481
+ });
482
+ success('Card created!');
483
+ print(result, getFormat(cardCmd));
484
+ } catch (err) {
485
+ error(String(err));
486
+ process.exit(1);
487
+ }
488
+ });
489
+
490
+ cardCmd
491
+ .command('update <id>')
492
+ .description('Update a card')
493
+ .option('--name <name>', 'Card name')
494
+ .option('--desc <desc>', 'Card description')
495
+ .option('--due <date>', 'Due date')
496
+ .option('--closed', 'Archive the card')
497
+ .action(async (id: string, opts) => {
498
+ try {
499
+ const client = getClient();
500
+ const result = await client.updateCard(id, {
501
+ name: opts.name,
502
+ desc: opts.desc,
503
+ due: opts.due,
504
+ closed: opts.closed,
505
+ });
506
+ success('Card updated!');
507
+ print(result, getFormat(cardCmd));
508
+ } catch (err) {
509
+ error(String(err));
510
+ process.exit(1);
511
+ }
512
+ });
513
+
514
+ cardCmd
515
+ .command('delete <id>')
516
+ .description('Delete a card')
517
+ .action(async (id: string) => {
518
+ try {
519
+ const client = getClient();
520
+ await client.deleteCard(id);
521
+ success(`Card ${id} deleted`);
522
+ } catch (err) {
523
+ error(String(err));
524
+ process.exit(1);
525
+ }
526
+ });
527
+
528
+ cardCmd
529
+ .command('move <id>')
530
+ .description('Move a card to another list')
531
+ .requiredOption('--list <listId>', 'Destination list ID')
532
+ .option('--pos <pos>', 'Position (top, bottom, or number)')
533
+ .action(async (id: string, opts) => {
534
+ try {
535
+ const client = getClient();
536
+ const result = await client.moveCard(id, opts.list, opts.pos);
537
+ success('Card moved!');
538
+ print(result, getFormat(cardCmd));
539
+ } catch (err) {
540
+ error(String(err));
541
+ process.exit(1);
542
+ }
543
+ });
544
+
545
+ cardCmd
546
+ .command('archive <id>')
547
+ .description('Archive a card')
548
+ .action(async (id: string) => {
549
+ try {
550
+ const client = getClient();
551
+ await client.archiveCard(id);
552
+ success(`Card ${id} archived`);
553
+ } catch (err) {
554
+ error(String(err));
555
+ process.exit(1);
556
+ }
557
+ });
558
+
559
+ // ============================================
560
+ // Checklist Commands
561
+ // ============================================
562
+ const checklistCmd = program
563
+ .command('checklist')
564
+ .description('Checklist management');
565
+
566
+ checklistCmd
567
+ .command('get <id>')
568
+ .description('Get a checklist by ID')
569
+ .action(async (id: string) => {
570
+ try {
571
+ const client = getClient();
572
+ const result = await client.getChecklist(id);
573
+ print(result, getFormat(checklistCmd));
574
+ } catch (err) {
575
+ error(String(err));
576
+ process.exit(1);
577
+ }
578
+ });
579
+
580
+ checklistCmd
581
+ .command('create')
582
+ .description('Create a new checklist')
583
+ .requiredOption('--name <name>', 'Checklist name')
584
+ .requiredOption('--card <cardId>', 'Card ID')
585
+ .action(async (opts) => {
586
+ try {
587
+ const client = getClient();
588
+ const result = await client.createChecklist({
589
+ name: opts.name,
590
+ idCard: opts.card,
591
+ });
592
+ success('Checklist created!');
593
+ print(result, getFormat(checklistCmd));
594
+ } catch (err) {
595
+ error(String(err));
596
+ process.exit(1);
597
+ }
598
+ });
599
+
600
+ checklistCmd
601
+ .command('delete <id>')
602
+ .description('Delete a checklist')
603
+ .action(async (id: string) => {
604
+ try {
605
+ const client = getClient();
606
+ await client.deleteChecklist(id);
607
+ success(`Checklist ${id} deleted`);
608
+ } catch (err) {
609
+ error(String(err));
610
+ process.exit(1);
611
+ }
612
+ });
613
+
614
+ checklistCmd
615
+ .command('items <checklistId>')
616
+ .description('Get items in a checklist')
617
+ .action(async (checklistId: string) => {
618
+ try {
619
+ const client = getClient();
620
+ const result = await client.getChecklistItems(checklistId);
621
+ print(result, getFormat(checklistCmd));
622
+ } catch (err) {
623
+ error(String(err));
624
+ process.exit(1);
625
+ }
626
+ });
627
+
628
+ checklistCmd
629
+ .command('add-item')
630
+ .description('Add an item to a checklist')
631
+ .requiredOption('--checklist <checklistId>', 'Checklist ID')
632
+ .requiredOption('--name <name>', 'Item name')
633
+ .action(async (opts) => {
634
+ try {
635
+ const client = getClient();
636
+ const result = await client.createCheckItem(opts.checklist, { name: opts.name });
637
+ success('Check item added!');
638
+ print(result, getFormat(checklistCmd));
639
+ } catch (err) {
640
+ error(String(err));
641
+ process.exit(1);
642
+ }
643
+ });
644
+
645
+ // ============================================
646
+ // Comment Commands
647
+ // ============================================
648
+ const commentCmd = program
649
+ .command('comment')
650
+ .description('Comment management');
651
+
652
+ commentCmd
653
+ .command('add')
654
+ .description('Add a comment to a card')
655
+ .requiredOption('--card <cardId>', 'Card ID')
656
+ .requiredOption('--text <text>', 'Comment text')
657
+ .action(async (opts) => {
658
+ try {
659
+ const client = getClient();
660
+ const result = await client.addComment(opts.card, opts.text);
661
+ success('Comment added!');
662
+ print(result, getFormat(commentCmd));
663
+ } catch (err) {
664
+ error(String(err));
665
+ process.exit(1);
666
+ }
667
+ });
668
+
669
+ // ============================================
670
+ // Label Commands
671
+ // ============================================
672
+ const labelCmd = program
673
+ .command('label')
674
+ .description('Label management');
675
+
676
+ labelCmd
677
+ .command('create')
678
+ .description('Create a new label')
679
+ .requiredOption('--name <name>', 'Label name')
680
+ .requiredOption('--color <color>', 'Label color')
681
+ .requiredOption('--board <boardId>', 'Board ID')
682
+ .action(async (opts) => {
683
+ try {
684
+ const client = getClient();
685
+ const result = await client.createLabel({
686
+ name: opts.name,
687
+ color: opts.color,
688
+ idBoard: opts.board,
689
+ });
690
+ success('Label created!');
691
+ print(result, getFormat(labelCmd));
692
+ } catch (err) {
693
+ error(String(err));
694
+ process.exit(1);
695
+ }
696
+ });
697
+
698
+ labelCmd
699
+ .command('delete <id>')
700
+ .description('Delete a label')
701
+ .action(async (id: string) => {
702
+ try {
703
+ const client = getClient();
704
+ await client.deleteLabel(id);
705
+ success(`Label ${id} deleted`);
706
+ } catch (err) {
707
+ error(String(err));
708
+ process.exit(1);
709
+ }
710
+ });
711
+
712
+ // ============================================
713
+ // Search Commands
714
+ // ============================================
715
+ const searchCmd = program
716
+ .command('search')
717
+ .description('Search Trello');
718
+
719
+ searchCmd
720
+ .command('query <query>')
721
+ .description('Search for boards, cards, members')
722
+ .option('--boards <boardIds>', 'Limit to specific boards (comma-separated)')
723
+ .action(async (query: string, opts) => {
724
+ try {
725
+ const client = getClient();
726
+ const result = await client.search(query, {
727
+ idBoards: opts.boards,
728
+ });
729
+ print(result, getFormat(searchCmd));
730
+ } catch (err) {
731
+ error(String(err));
732
+ process.exit(1);
733
+ }
734
+ });
735
+
736
+ // Parse and execute
737
+ program.parse();