trello-cli-unofficial 0.11.5 → 0.12.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/CHANGELOG.md +16 -0
- package/README.md +7 -0
- package/dist/main.js +119 -13
- package/dist/trello-cli-unofficial-0.12.0.tgz +0 -0
- package/package.json +1 -1
- package/src/application/use-cases/GetCardUseCase.ts +10 -0
- package/src/application/use-cases/index.ts +1 -0
- package/src/domain/entities/Card.ts +23 -1
- package/src/domain/repositories/TrelloRepository.ts +1 -0
- package/src/i18n/locales/en.json +9 -0
- package/src/i18n/locales/pt-BR.json +9 -0
- package/src/infrastructure/repositories/TrelloApiRepository.ts +10 -1
- package/src/presentation/cli/CardController.ts +53 -0
- package/src/presentation/cli/CommandController.ts +52 -17
- package/dist/trello-cli-unofficial-0.11.5.tgz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
# [0.12.0](https://github.com/JaegerCaiser/trello-cli-unofficial/compare/v0.11.6...v0.12.0) (2025-11-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **cards:** add cards show command ([a98fa9f](https://github.com/JaegerCaiser/trello-cli-unofficial/commit/a98fa9fe2244bbd8ba754e725b867ee22cfd4c33))
|
|
7
|
+
|
|
8
|
+
## [0.11.6](https://github.com/JaegerCaiser/trello-cli-unofficial/compare/v0.11.5...v0.11.6) (2025-11-14)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* Add debug logs to CommandController for Windows troubleshooting ([5c146a9](https://github.com/JaegerCaiser/trello-cli-unofficial/commit/5c146a9801502747c9eb1dee3f6db38fa9ad20ab))
|
|
14
|
+
* Implement lazy Commander initialization for Windows compatibility ([e08ca9f](https://github.com/JaegerCaiser/trello-cli-unofficial/commit/e08ca9f298fb15d9b29e4e3daa98584c5d6321ad))
|
|
15
|
+
* Improve Windows compatibility test script ([2b230d9](https://github.com/JaegerCaiser/trello-cli-unofficial/commit/2b230d9b36e0b0b4f2fec52bbd9200fd424b4de9))
|
|
16
|
+
|
|
1
17
|
## [0.11.5](https://github.com/JaegerCaiser/trello-cli-unofficial/compare/v0.11.4...v0.11.5) (2025-11-14)
|
|
2
18
|
|
|
3
19
|
|
package/README.md
CHANGED
|
@@ -252,6 +252,13 @@ tcu
|
|
|
252
252
|
- **Delete**: Confirm before removing
|
|
253
253
|
- **Move**: Select destination list
|
|
254
254
|
|
|
255
|
+
### Show Card Details
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Show detailed information about a card, including checklists, members, labels and attachments
|
|
259
|
+
tcu cards show <cardId>
|
|
260
|
+
```
|
|
261
|
+
|
|
255
262
|
## 🤖 CI/CD & Automation
|
|
256
263
|
|
|
257
264
|
This project uses automated CI/CD with semantic versioning based on **commit messages**:
|
package/dist/main.js
CHANGED
|
@@ -2588,6 +2588,12 @@ var require_en = __commonJS((exports, module) => {
|
|
|
2588
2588
|
delete: "\uD83D\uDDD1\uFE0F Delete Card",
|
|
2589
2589
|
back: "\u2B05\uFE0F Back",
|
|
2590
2590
|
moveCard: "\uD83D\uDCE6 Move card"
|
|
2591
|
+
},
|
|
2592
|
+
show: {
|
|
2593
|
+
labels: "\uD83C\uDFF7\uFE0F Labels:",
|
|
2594
|
+
members: "\uD83D\uDC65 Members:",
|
|
2595
|
+
checklists: "\u2705 Checklists:",
|
|
2596
|
+
attachments: "\uD83D\uDCCE Attachments:"
|
|
2591
2597
|
}
|
|
2592
2598
|
},
|
|
2593
2599
|
errors: {
|
|
@@ -2724,6 +2730,9 @@ var require_en = __commonJS((exports, module) => {
|
|
|
2724
2730
|
update: {
|
|
2725
2731
|
description: "Update an existing card"
|
|
2726
2732
|
},
|
|
2733
|
+
show: {
|
|
2734
|
+
description: "Show detailed information about a specific card"
|
|
2735
|
+
},
|
|
2727
2736
|
delete: {
|
|
2728
2737
|
description: "Delete a card"
|
|
2729
2738
|
}
|
|
@@ -2863,6 +2872,12 @@ var require_pt_BR = __commonJS((exports, module) => {
|
|
|
2863
2872
|
delete: "\uD83D\uDDD1\uFE0F Deletar Card",
|
|
2864
2873
|
back: "\u2B05\uFE0F Voltar",
|
|
2865
2874
|
moveCard: "\uD83D\uDCE6 Mover cart\xE3o"
|
|
2875
|
+
},
|
|
2876
|
+
show: {
|
|
2877
|
+
labels: "\uD83C\uDFF7\uFE0F Labels:",
|
|
2878
|
+
members: "\uD83D\uDC65 Membros:",
|
|
2879
|
+
checklists: "\u2705 Checklists:",
|
|
2880
|
+
attachments: "\uD83D\uDCCE Anexos:"
|
|
2866
2881
|
}
|
|
2867
2882
|
},
|
|
2868
2883
|
errors: {
|
|
@@ -2999,6 +3014,9 @@ var require_pt_BR = __commonJS((exports, module) => {
|
|
|
2999
3014
|
update: {
|
|
3000
3015
|
description: "Atualiza um card existente"
|
|
3001
3016
|
},
|
|
3017
|
+
show: {
|
|
3018
|
+
description: "Mostra informa\xE7\xF5es detalhadas sobre um card espec\xEDfico"
|
|
3019
|
+
},
|
|
3002
3020
|
delete: {
|
|
3003
3021
|
description: "Deleta um card"
|
|
3004
3022
|
}
|
|
@@ -3251,6 +3269,17 @@ class GetCardsUseCase {
|
|
|
3251
3269
|
}
|
|
3252
3270
|
}
|
|
3253
3271
|
|
|
3272
|
+
// src/application/use-cases/GetCardUseCase.ts
|
|
3273
|
+
class GetCardUseCase {
|
|
3274
|
+
trelloRepository;
|
|
3275
|
+
constructor(trelloRepository) {
|
|
3276
|
+
this.trelloRepository = trelloRepository;
|
|
3277
|
+
}
|
|
3278
|
+
async execute(cardId) {
|
|
3279
|
+
return await this.trelloRepository.getCard(cardId);
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3254
3283
|
// src/application/use-cases/GetListsUseCase.ts
|
|
3255
3284
|
class GetListsUseCase {
|
|
3256
3285
|
trelloRepository;
|
|
@@ -26134,6 +26163,7 @@ class CardController {
|
|
|
26134
26163
|
updateCardUseCase;
|
|
26135
26164
|
deleteCardUseCase;
|
|
26136
26165
|
moveCardUseCase;
|
|
26166
|
+
getCardUseCase;
|
|
26137
26167
|
constructor(trelloRepository, boardController, outputFormatter) {
|
|
26138
26168
|
this.trelloRepository = trelloRepository;
|
|
26139
26169
|
this.boardController = boardController;
|
|
@@ -26142,6 +26172,7 @@ class CardController {
|
|
|
26142
26172
|
this.updateCardUseCase = new UpdateCardUseCase(trelloRepository);
|
|
26143
26173
|
this.deleteCardUseCase = new DeleteCardUseCase(trelloRepository);
|
|
26144
26174
|
this.moveCardUseCase = new MoveCardUseCase(trelloRepository);
|
|
26175
|
+
this.getCardUseCase = new GetCardUseCase(trelloRepository);
|
|
26145
26176
|
}
|
|
26146
26177
|
async createCardInteractive() {
|
|
26147
26178
|
const boards = await this.boardController.getBoards();
|
|
@@ -26425,6 +26456,46 @@ class CardController {
|
|
|
26425
26456
|
console.log(t2("card.updated"));
|
|
26426
26457
|
console.log(t2("card.cardName", { name: updatedCard.name }));
|
|
26427
26458
|
}
|
|
26459
|
+
async showCard(cardId) {
|
|
26460
|
+
const card = await this.getCardUseCase.execute(cardId);
|
|
26461
|
+
const boards = await this.boardController.getBoards();
|
|
26462
|
+
let boardName;
|
|
26463
|
+
let listName;
|
|
26464
|
+
for (const board of boards) {
|
|
26465
|
+
const lists = await this.boardController.getLists(board.id);
|
|
26466
|
+
const list = lists.find((l) => l.id === card.idList);
|
|
26467
|
+
if (list) {
|
|
26468
|
+
boardName = board.name;
|
|
26469
|
+
listName = list.name;
|
|
26470
|
+
break;
|
|
26471
|
+
}
|
|
26472
|
+
}
|
|
26473
|
+
this.outputFormatter.message(t2("card.cardName", { name: card.name }));
|
|
26474
|
+
if (card.desc) {
|
|
26475
|
+
this.outputFormatter.message(t2("card.cardDescription", { description: card.desc }));
|
|
26476
|
+
}
|
|
26477
|
+
this.outputFormatter.message(t2("card.cardUrl", { url: card.url }));
|
|
26478
|
+
this.outputFormatter.message(t2("card.cardId", { id: card.id }));
|
|
26479
|
+
if (boardName && listName) {
|
|
26480
|
+
this.outputFormatter.message(`${t2("board.boardName", { name: boardName })} / ${t2("list.boardLists", { boardName: listName })}`);
|
|
26481
|
+
}
|
|
26482
|
+
if (card.labels && card.labels.length > 0) {
|
|
26483
|
+
this.outputFormatter.message(t2("card.show.labels"));
|
|
26484
|
+
this.outputFormatter.output(card.labels);
|
|
26485
|
+
}
|
|
26486
|
+
if (card.members && card.members.length > 0) {
|
|
26487
|
+
this.outputFormatter.message(t2("card.show.members"));
|
|
26488
|
+
this.outputFormatter.output(card.members);
|
|
26489
|
+
}
|
|
26490
|
+
if (card.checklists && card.checklists.length > 0) {
|
|
26491
|
+
this.outputFormatter.message(t2("card.show.checklists"));
|
|
26492
|
+
this.outputFormatter.output(card.checklists);
|
|
26493
|
+
}
|
|
26494
|
+
if (card.attachments && card.attachments.length > 0) {
|
|
26495
|
+
this.outputFormatter.message(t2("card.show.attachments"));
|
|
26496
|
+
this.outputFormatter.output(card.attachments);
|
|
26497
|
+
}
|
|
26498
|
+
}
|
|
26428
26499
|
async moveCardToList(cardId, targetListId) {
|
|
26429
26500
|
const boards = await this.trelloRepository.getBoards();
|
|
26430
26501
|
let card;
|
|
@@ -26494,15 +26565,23 @@ class CardEntity {
|
|
|
26494
26565
|
idList;
|
|
26495
26566
|
desc;
|
|
26496
26567
|
url;
|
|
26497
|
-
|
|
26568
|
+
labels;
|
|
26569
|
+
members;
|
|
26570
|
+
checklists;
|
|
26571
|
+
attachments;
|
|
26572
|
+
constructor(id, name, idList, desc, url, labels, members, checklists, attachments) {
|
|
26498
26573
|
this.id = id;
|
|
26499
26574
|
this.name = name;
|
|
26500
26575
|
this.idList = idList;
|
|
26501
26576
|
this.desc = desc;
|
|
26502
26577
|
this.url = url;
|
|
26578
|
+
this.labels = labels;
|
|
26579
|
+
this.members = members;
|
|
26580
|
+
this.checklists = checklists;
|
|
26581
|
+
this.attachments = attachments;
|
|
26503
26582
|
}
|
|
26504
26583
|
static fromApiResponse(data) {
|
|
26505
|
-
return new CardEntity(data.id, data.name, data.idList, data.desc, data.url);
|
|
26584
|
+
return new CardEntity(data.id, data.name, data.idList, data.desc, data.url, data.labels, data.members, data.checklists, data.attachments);
|
|
26506
26585
|
}
|
|
26507
26586
|
static create(data) {
|
|
26508
26587
|
return {
|
|
@@ -28688,7 +28767,8 @@ class TrelloApiRepository {
|
|
|
28688
28767
|
this.token = token;
|
|
28689
28768
|
}
|
|
28690
28769
|
async request(endpoint, options) {
|
|
28691
|
-
const
|
|
28770
|
+
const separator = endpoint.includes("?") ? "&" : "?";
|
|
28771
|
+
const url = `${this.baseUrl}${endpoint}${separator}key=${this.apiKey}&token=${this.token}`;
|
|
28692
28772
|
const response = await fetch(url, options);
|
|
28693
28773
|
if (!response.ok) {
|
|
28694
28774
|
const errorText = await response.text();
|
|
@@ -28829,6 +28909,11 @@ ${errorText}`);
|
|
|
28829
28909
|
async moveCard(cardId, targetListId) {
|
|
28830
28910
|
return this.updateCard(cardId, { idList: targetListId });
|
|
28831
28911
|
}
|
|
28912
|
+
async getCard(cardId) {
|
|
28913
|
+
const endpoint = `/cards/${cardId}?checklists=all&members=true&attachments=true`;
|
|
28914
|
+
const data = await this.request(endpoint);
|
|
28915
|
+
return CardEntity.fromApiResponse(data);
|
|
28916
|
+
}
|
|
28832
28917
|
}
|
|
28833
28918
|
var init_TrelloApiRepository = __esm(() => {
|
|
28834
28919
|
init_entities();
|
|
@@ -31143,8 +31228,15 @@ class CommandController {
|
|
|
31143
31228
|
constructor() {
|
|
31144
31229
|
const configRepository = new FileConfigRepository;
|
|
31145
31230
|
this.authController = new AuthController(configRepository);
|
|
31146
|
-
this.outputFormatter = new OutputFormatter;
|
|
31147
31231
|
this.program = new Command;
|
|
31232
|
+
this.outputFormatter = new OutputFormatter;
|
|
31233
|
+
this.initializeProgram();
|
|
31234
|
+
this.setupCommands();
|
|
31235
|
+
}
|
|
31236
|
+
initializeProgram() {
|
|
31237
|
+
if (!this.program) {
|
|
31238
|
+
this.program = new Command;
|
|
31239
|
+
}
|
|
31148
31240
|
}
|
|
31149
31241
|
getVersion() {
|
|
31150
31242
|
const cwdPackageJson = join(process.cwd(), "package.json");
|
|
@@ -31157,13 +31249,13 @@ class CommandController {
|
|
|
31157
31249
|
try {
|
|
31158
31250
|
const currentFilePath = fileURLToPath2(import.meta.url);
|
|
31159
31251
|
const currentDir = dirname(currentFilePath);
|
|
31160
|
-
const installedPackageJson = join(currentDir, "..", "..", "package.json");
|
|
31252
|
+
const installedPackageJson = join(currentDir, "..", "..", "..", "..", "package.json");
|
|
31161
31253
|
if (existsSync(installedPackageJson)) {
|
|
31162
31254
|
const packageJson = JSON.parse(readFileSync2(installedPackageJson, "utf-8"));
|
|
31163
31255
|
return packageJson.version;
|
|
31164
31256
|
}
|
|
31165
31257
|
} catch {}
|
|
31166
|
-
return "0.11.
|
|
31258
|
+
return "0.11.10";
|
|
31167
31259
|
}
|
|
31168
31260
|
async initializeTrelloControllers() {
|
|
31169
31261
|
await this.authController.ensureAuthenticated();
|
|
@@ -31173,7 +31265,7 @@ class CommandController {
|
|
|
31173
31265
|
this.boardController = new BoardController(trelloRepository, this.outputFormatter);
|
|
31174
31266
|
this.cardController = new CardController(trelloRepository, this.boardController, this.outputFormatter);
|
|
31175
31267
|
}
|
|
31176
|
-
|
|
31268
|
+
setupCommands() {
|
|
31177
31269
|
if (!this.program) {
|
|
31178
31270
|
throw new Error(t2("errors.programNotInitialized"));
|
|
31179
31271
|
}
|
|
@@ -31203,7 +31295,7 @@ class CommandController {
|
|
|
31203
31295
|
}
|
|
31204
31296
|
await this.boardController.showBoards();
|
|
31205
31297
|
} catch (error) {
|
|
31206
|
-
console.error(t2("commands.
|
|
31298
|
+
console.error(t2("commands.commandErrors.genericError"), error.message);
|
|
31207
31299
|
}
|
|
31208
31300
|
});
|
|
31209
31301
|
boardsCmd.command("show <boardId>").description(t2("commands.boards.show.description")).option("-f, --format <format>", t2("commands.formatOption"), "table").action(async (boardId, options) => {
|
|
@@ -31214,7 +31306,7 @@ class CommandController {
|
|
|
31214
31306
|
}
|
|
31215
31307
|
await this.boardController.showBoardDetails(boardId);
|
|
31216
31308
|
} catch (error) {
|
|
31217
|
-
console.error(t2("commands.
|
|
31309
|
+
console.error(t2("commands.commandErrors.genericError"), error.message);
|
|
31218
31310
|
}
|
|
31219
31311
|
});
|
|
31220
31312
|
boardsCmd.command("create <name>").description(t2("commands.boards.create.description")).option("-d, --desc <description>", t2("commands.boards.create.descOption")).action(async (name, options) => {
|
|
@@ -31243,7 +31335,7 @@ class CommandController {
|
|
|
31243
31335
|
}
|
|
31244
31336
|
await this.boardController.showListsById(boardId);
|
|
31245
31337
|
} catch (error) {
|
|
31246
|
-
console.error(t2("commands.
|
|
31338
|
+
console.error(t2("commands.commandErrors.genericError"), error.message);
|
|
31247
31339
|
}
|
|
31248
31340
|
});
|
|
31249
31341
|
listsCmd.command("create <boardId> <name>").description(t2("commands.lists.create.description")).action(async (boardId, name) => {
|
|
@@ -31288,7 +31380,7 @@ class CommandController {
|
|
|
31288
31380
|
}
|
|
31289
31381
|
await this.boardController.showCardsByListId(listId);
|
|
31290
31382
|
} catch (error) {
|
|
31291
|
-
console.error(t2("commands.
|
|
31383
|
+
console.error(t2("commands.commandErrors.genericError"), error.message);
|
|
31292
31384
|
}
|
|
31293
31385
|
});
|
|
31294
31386
|
cardsCmd.command("create <listId> <name>").description(t2("commands.cards.create.description")).option("-d, --desc <description>", t2("commands.options.cardDescription")).action(async (listId, name, options) => {
|
|
@@ -31323,6 +31415,17 @@ class CommandController {
|
|
|
31323
31415
|
console.error(t2("commands.commandErrors.genericError"), error.message);
|
|
31324
31416
|
}
|
|
31325
31417
|
});
|
|
31418
|
+
cardsCmd.command("show <cardId>").description(t2("commands.cards.show.description")).option("-f, --format <format>", t2("commands.formatOption"), "table").action(async (cardId, options) => {
|
|
31419
|
+
try {
|
|
31420
|
+
await this.initializeTrelloControllers();
|
|
31421
|
+
if (options.format) {
|
|
31422
|
+
this.outputFormatter.setFormat(options.format);
|
|
31423
|
+
}
|
|
31424
|
+
await this.cardController.showCard(cardId);
|
|
31425
|
+
} catch (error) {
|
|
31426
|
+
console.error(t2("commands.commandErrors.genericError"), error.message);
|
|
31427
|
+
}
|
|
31428
|
+
});
|
|
31326
31429
|
this.program.command("cards-legacy <boardName> <listName>").description(t2("commands.deprecated.cardsLegacyDescription")).action(async (boardName, listName) => {
|
|
31327
31430
|
console.warn(t2("commands.deprecated.cardsLegacyWarning"));
|
|
31328
31431
|
try {
|
|
@@ -31361,13 +31464,16 @@ class CommandController {
|
|
|
31361
31464
|
});
|
|
31362
31465
|
}
|
|
31363
31466
|
async run() {
|
|
31364
|
-
|
|
31467
|
+
if (!this.program) {
|
|
31468
|
+
this.initializeProgram();
|
|
31469
|
+
this.setupCommands();
|
|
31470
|
+
}
|
|
31365
31471
|
if (process.argv.length === 2) {
|
|
31366
31472
|
const configRepository = new FileConfigRepository;
|
|
31367
31473
|
const cli = new (await Promise.resolve().then(() => (init_TrelloCliController(), exports_TrelloCliController))).TrelloCliController(configRepository, this.outputFormatter);
|
|
31368
31474
|
await cli.run();
|
|
31369
31475
|
} else {
|
|
31370
|
-
|
|
31476
|
+
this.program.parse();
|
|
31371
31477
|
}
|
|
31372
31478
|
}
|
|
31373
31479
|
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trello-cli-unofficial",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Unofficial Trello CLI using Power-Up authentication, built with Bun for maximum performance",
|
|
7
7
|
"author": "Matheus Caiser <matheus.kaiser@gmail.com> (https://www.mrdeveloper.com.br/)",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CardEntity } from '@domain/entities';
|
|
2
|
+
import type { TrelloRepository } from '@domain/repositories';
|
|
3
|
+
|
|
4
|
+
export class GetCardUseCase {
|
|
5
|
+
constructor(private trelloRepository: TrelloRepository) {}
|
|
6
|
+
|
|
7
|
+
async execute(cardId: string): Promise<CardEntity> {
|
|
8
|
+
return await this.trelloRepository.getCard(cardId);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -6,6 +6,7 @@ export * from './DeleteCardUseCase';
|
|
|
6
6
|
export * from './GetBoardDetailsUseCase';
|
|
7
7
|
export * from './GetBoardsUseCase';
|
|
8
8
|
export * from './GetCardsUseCase';
|
|
9
|
+
export * from './GetCardUseCase';
|
|
9
10
|
export * from './GetListsUseCase';
|
|
10
11
|
export * from './MoveCardUseCase';
|
|
11
12
|
export * from './UpdateCardUseCase';
|
|
@@ -4,6 +4,10 @@ export interface Card {
|
|
|
4
4
|
desc?: string;
|
|
5
5
|
idList: string;
|
|
6
6
|
url?: string;
|
|
7
|
+
labels?: Array<{ id: string; name?: string; color?: string }>;
|
|
8
|
+
members?: Array<{ id: string; username?: string; fullName?: string }>;
|
|
9
|
+
checklists?: Array<Record<string, unknown>>;
|
|
10
|
+
attachments?: Array<Record<string, unknown>>;
|
|
7
11
|
}
|
|
8
12
|
|
|
9
13
|
export interface CreateCardData {
|
|
@@ -26,6 +30,10 @@ interface TrelloCardResponse {
|
|
|
26
30
|
idList: string;
|
|
27
31
|
pos: number;
|
|
28
32
|
url?: string;
|
|
33
|
+
labels?: Array<{ id: string; name?: string; color?: string }>;
|
|
34
|
+
members?: Array<{ id: string; username?: string; fullName?: string }>;
|
|
35
|
+
checklists?: Array<Record<string, unknown>>;
|
|
36
|
+
attachments?: Array<Record<string, unknown>>;
|
|
29
37
|
[key: string]: unknown;
|
|
30
38
|
}
|
|
31
39
|
|
|
@@ -36,10 +44,24 @@ export class CardEntity implements Card {
|
|
|
36
44
|
public readonly idList: string,
|
|
37
45
|
public readonly desc?: string,
|
|
38
46
|
public readonly url?: string,
|
|
47
|
+
public readonly labels?: Array<{ id: string; name?: string; color?: string }>,
|
|
48
|
+
public readonly members?: Array<{ id: string; username?: string; fullName?: string }>,
|
|
49
|
+
public readonly checklists?: Array<Record<string, unknown>>,
|
|
50
|
+
public readonly attachments?: Array<Record<string, unknown>>,
|
|
39
51
|
) {}
|
|
40
52
|
|
|
41
53
|
static fromApiResponse(data: TrelloCardResponse): CardEntity {
|
|
42
|
-
return new CardEntity(
|
|
54
|
+
return new CardEntity(
|
|
55
|
+
data.id,
|
|
56
|
+
data.name,
|
|
57
|
+
data.idList,
|
|
58
|
+
data.desc,
|
|
59
|
+
data.url,
|
|
60
|
+
data.labels,
|
|
61
|
+
data.members,
|
|
62
|
+
data.checklists,
|
|
63
|
+
data.attachments,
|
|
64
|
+
);
|
|
43
65
|
}
|
|
44
66
|
|
|
45
67
|
static create(
|
|
@@ -14,6 +14,7 @@ export interface TrelloRepository {
|
|
|
14
14
|
deleteList: (listId: string) => Promise<void>;
|
|
15
15
|
moveList: (listId: string, position: number) => Promise<ListEntity>;
|
|
16
16
|
getCards: (listId: string) => Promise<CardEntity[]>;
|
|
17
|
+
getCard: (cardId: string) => Promise<CardEntity>;
|
|
17
18
|
createCard: (data: CreateCardData) => Promise<CardEntity>;
|
|
18
19
|
updateCard: (cardId: string, data: UpdateCardData) => Promise<CardEntity>;
|
|
19
20
|
deleteCard: (cardId: string) => Promise<void>;
|
package/src/i18n/locales/en.json
CHANGED
|
@@ -127,6 +127,12 @@
|
|
|
127
127
|
"delete": "🗑️ Delete Card",
|
|
128
128
|
"back": "⬅️ Back",
|
|
129
129
|
"moveCard": "📦 Move card"
|
|
130
|
+
},
|
|
131
|
+
"show": {
|
|
132
|
+
"labels": "🏷️ Labels:",
|
|
133
|
+
"members": "👥 Members:",
|
|
134
|
+
"checklists": "✅ Checklists:",
|
|
135
|
+
"attachments": "📎 Attachments:"
|
|
130
136
|
}
|
|
131
137
|
},
|
|
132
138
|
"errors": {
|
|
@@ -263,6 +269,9 @@
|
|
|
263
269
|
"update": {
|
|
264
270
|
"description": "Update an existing card"
|
|
265
271
|
},
|
|
272
|
+
"show": {
|
|
273
|
+
"description": "Show detailed information about a specific card"
|
|
274
|
+
},
|
|
266
275
|
"delete": {
|
|
267
276
|
"description": "Delete a card"
|
|
268
277
|
}
|
|
@@ -127,6 +127,12 @@
|
|
|
127
127
|
"delete": "🗑️ Deletar Card",
|
|
128
128
|
"back": "⬅️ Voltar",
|
|
129
129
|
"moveCard": "📦 Mover cartão"
|
|
130
|
+
},
|
|
131
|
+
"show": {
|
|
132
|
+
"labels": "🏷️ Labels:",
|
|
133
|
+
"members": "👥 Membros:",
|
|
134
|
+
"checklists": "✅ Checklists:",
|
|
135
|
+
"attachments": "📎 Anexos:"
|
|
130
136
|
}
|
|
131
137
|
},
|
|
132
138
|
"errors": {
|
|
@@ -263,6 +269,9 @@
|
|
|
263
269
|
"update": {
|
|
264
270
|
"description": "Atualiza um card existente"
|
|
265
271
|
},
|
|
272
|
+
"show": {
|
|
273
|
+
"description": "Mostra informações detalhadas sobre um card específico"
|
|
274
|
+
},
|
|
266
275
|
"delete": {
|
|
267
276
|
"description": "Deleta um card"
|
|
268
277
|
}
|
|
@@ -40,7 +40,9 @@ export class TrelloApiRepository implements TrelloRepository {
|
|
|
40
40
|
endpoint: string,
|
|
41
41
|
options?: RequestInit,
|
|
42
42
|
): Promise<unknown> {
|
|
43
|
-
|
|
43
|
+
// If the endpoint already contains query params, add key/token with & otherwise use ?
|
|
44
|
+
const separator = endpoint.includes('?') ? '&' : '?';
|
|
45
|
+
const url = `${this.baseUrl}${endpoint}${separator}key=${this.apiKey}&token=${this.token}`;
|
|
44
46
|
|
|
45
47
|
const response = await fetch(url, options);
|
|
46
48
|
|
|
@@ -235,4 +237,11 @@ export class TrelloApiRepository implements TrelloRepository {
|
|
|
235
237
|
async moveCard(cardId: string, targetListId: string): Promise<CardEntity> {
|
|
236
238
|
return this.updateCard(cardId, { idList: targetListId });
|
|
237
239
|
}
|
|
240
|
+
|
|
241
|
+
async getCard(cardId: string): Promise<CardEntity> {
|
|
242
|
+
// Request the card with details: members, checklists and attachments
|
|
243
|
+
const endpoint = `/cards/${cardId}?checklists=all&members=true&attachments=true`;
|
|
244
|
+
const data = await this.request(endpoint);
|
|
245
|
+
return CardEntity.fromApiResponse(data as TrelloCardResponse);
|
|
246
|
+
}
|
|
238
247
|
}
|
|
@@ -6,6 +6,7 @@ import type { OutputFormatter } from '@/shared';
|
|
|
6
6
|
import {
|
|
7
7
|
CreateCardUseCase,
|
|
8
8
|
DeleteCardUseCase,
|
|
9
|
+
GetCardUseCase,
|
|
9
10
|
MoveCardUseCase,
|
|
10
11
|
UpdateCardUseCase,
|
|
11
12
|
} from '@application/use-cases';
|
|
@@ -19,6 +20,7 @@ export class CardController {
|
|
|
19
20
|
private updateCardUseCase: UpdateCardUseCase;
|
|
20
21
|
private deleteCardUseCase: DeleteCardUseCase;
|
|
21
22
|
private moveCardUseCase: MoveCardUseCase;
|
|
23
|
+
private getCardUseCase: GetCardUseCase;
|
|
22
24
|
|
|
23
25
|
constructor(
|
|
24
26
|
private trelloRepository: TrelloRepository,
|
|
@@ -29,6 +31,7 @@ export class CardController {
|
|
|
29
31
|
this.updateCardUseCase = new UpdateCardUseCase(trelloRepository);
|
|
30
32
|
this.deleteCardUseCase = new DeleteCardUseCase(trelloRepository);
|
|
31
33
|
this.moveCardUseCase = new MoveCardUseCase(trelloRepository);
|
|
34
|
+
this.getCardUseCase = new GetCardUseCase(trelloRepository);
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
async createCardInteractive(): Promise<void> {
|
|
@@ -405,6 +408,56 @@ export class CardController {
|
|
|
405
408
|
console.log(t('card.cardName', { name: updatedCard.name }));
|
|
406
409
|
}
|
|
407
410
|
|
|
411
|
+
async showCard(cardId: string): Promise<void> {
|
|
412
|
+
// Get detailed card from the repository
|
|
413
|
+
const card = await this.getCardUseCase.execute(cardId);
|
|
414
|
+
|
|
415
|
+
// Try to find board and list names
|
|
416
|
+
const boards = await this.boardController.getBoards();
|
|
417
|
+
let boardName: string | undefined;
|
|
418
|
+
let listName: string | undefined;
|
|
419
|
+
for (const board of boards) {
|
|
420
|
+
const lists = await this.boardController.getLists(board.id);
|
|
421
|
+
const list = lists.find(l => l.id === card.idList);
|
|
422
|
+
if (list) {
|
|
423
|
+
boardName = board.name;
|
|
424
|
+
listName = list.name;
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
this.outputFormatter.message(t('card.cardName', { name: card.name }));
|
|
430
|
+
if (card.desc) {
|
|
431
|
+
this.outputFormatter.message(t('card.cardDescription', { description: card.desc }));
|
|
432
|
+
}
|
|
433
|
+
this.outputFormatter.message(t('card.cardUrl', { url: card.url }));
|
|
434
|
+
this.outputFormatter.message(t('card.cardId', { id: card.id }));
|
|
435
|
+
if (boardName && listName) {
|
|
436
|
+
this.outputFormatter.message(`${t('board.boardName', { name: boardName })} / ${t('list.boardLists', { boardName: listName })}`);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Show labels, members and checklists if present
|
|
440
|
+
if (card.labels && card.labels.length > 0) {
|
|
441
|
+
this.outputFormatter.message(t('card.show.labels'));
|
|
442
|
+
this.outputFormatter.output(card.labels);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (card.members && card.members.length > 0) {
|
|
446
|
+
this.outputFormatter.message(t('card.show.members'));
|
|
447
|
+
this.outputFormatter.output(card.members);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (card.checklists && card.checklists.length > 0) {
|
|
451
|
+
this.outputFormatter.message(t('card.show.checklists'));
|
|
452
|
+
this.outputFormatter.output(card.checklists);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (card.attachments && card.attachments.length > 0) {
|
|
456
|
+
this.outputFormatter.message(t('card.show.attachments'));
|
|
457
|
+
this.outputFormatter.output(card.attachments);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
408
461
|
async moveCardToList(cardId: string, targetListId: string): Promise<void> {
|
|
409
462
|
// Primeiro precisamos encontrar o cartão para mostrar informações
|
|
410
463
|
const boards = await this.trelloRepository.getBoards();
|
|
@@ -8,11 +8,10 @@ import {
|
|
|
8
8
|
FileConfigRepository,
|
|
9
9
|
TrelloApiRepository,
|
|
10
10
|
} from '@infrastructure/repositories';
|
|
11
|
-
|
|
12
11
|
import { Command } from 'commander';
|
|
12
|
+
|
|
13
13
|
import { t } from '@/i18n';
|
|
14
14
|
import { OutputFormatter } from '@/shared';
|
|
15
|
-
|
|
16
15
|
import { AuthController, BoardController, CardController } from './index';
|
|
17
16
|
|
|
18
17
|
export class CommandController {
|
|
@@ -25,9 +24,17 @@ export class CommandController {
|
|
|
25
24
|
constructor() {
|
|
26
25
|
const configRepository = new FileConfigRepository();
|
|
27
26
|
this.authController = new AuthController(configRepository);
|
|
28
|
-
this.outputFormatter = new OutputFormatter();
|
|
29
|
-
// Initialize Commander immediately in constructor
|
|
30
27
|
this.program = new Command();
|
|
28
|
+
this.outputFormatter = new OutputFormatter();
|
|
29
|
+
this.initializeProgram();
|
|
30
|
+
this.setupCommands();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private initializeProgram(): void {
|
|
34
|
+
// Ensure program is properly initialized
|
|
35
|
+
if (!this.program) {
|
|
36
|
+
this.program = new Command();
|
|
37
|
+
}
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
private getVersion(): string {
|
|
@@ -39,7 +46,8 @@ export class CommandController {
|
|
|
39
46
|
try {
|
|
40
47
|
const packageJson = JSON.parse(readFileSync(cwdPackageJson, 'utf-8'));
|
|
41
48
|
return packageJson.version;
|
|
42
|
-
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
43
51
|
// Continue to next approach
|
|
44
52
|
}
|
|
45
53
|
}
|
|
@@ -48,18 +56,19 @@ export class CommandController {
|
|
|
48
56
|
try {
|
|
49
57
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
50
58
|
const currentDir = dirname(currentFilePath);
|
|
51
|
-
const installedPackageJson = join(currentDir, '..', '..', 'package.json');
|
|
59
|
+
const installedPackageJson = join(currentDir, '..', '..', '..', '..', 'package.json');
|
|
52
60
|
|
|
53
61
|
if (existsSync(installedPackageJson)) {
|
|
54
62
|
const packageJson = JSON.parse(readFileSync(installedPackageJson, 'utf-8'));
|
|
55
63
|
return packageJson.version;
|
|
56
64
|
}
|
|
57
|
-
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
58
67
|
// Continue to fallback
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
// 3. Fallback to hardcoded version
|
|
62
|
-
return '0.11.
|
|
70
|
+
// 3. Fallback to hardcoded version
|
|
71
|
+
return '0.11.10';
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
private async initializeTrelloControllers(): Promise<void> {
|
|
@@ -83,8 +92,8 @@ export class CommandController {
|
|
|
83
92
|
);
|
|
84
93
|
}
|
|
85
94
|
|
|
86
|
-
private
|
|
87
|
-
//
|
|
95
|
+
private setupCommands(): void {
|
|
96
|
+
// Ensure program is initialized
|
|
88
97
|
if (!this.program) {
|
|
89
98
|
throw new Error(t('errors.programNotInitialized'));
|
|
90
99
|
}
|
|
@@ -149,7 +158,10 @@ export class CommandController {
|
|
|
149
158
|
}
|
|
150
159
|
await this.boardController.showBoards();
|
|
151
160
|
} catch (error) {
|
|
152
|
-
console.error(
|
|
161
|
+
console.error(
|
|
162
|
+
t('commands.commandErrors.genericError'),
|
|
163
|
+
(error as Error).message,
|
|
164
|
+
);
|
|
153
165
|
}
|
|
154
166
|
});
|
|
155
167
|
|
|
@@ -165,7 +177,7 @@ export class CommandController {
|
|
|
165
177
|
}
|
|
166
178
|
await this.boardController.showBoardDetails(boardId);
|
|
167
179
|
} catch (error) {
|
|
168
|
-
console.error(t('commands.
|
|
180
|
+
console.error(t('commands.commandErrors.genericError'), (error as Error).message);
|
|
169
181
|
}
|
|
170
182
|
});
|
|
171
183
|
|
|
@@ -219,7 +231,7 @@ export class CommandController {
|
|
|
219
231
|
}
|
|
220
232
|
await this.boardController.showListsById(boardId);
|
|
221
233
|
} catch (error) {
|
|
222
|
-
console.error(t('commands.
|
|
234
|
+
console.error(t('commands.commandErrors.genericError'), (error as Error).message);
|
|
223
235
|
}
|
|
224
236
|
});
|
|
225
237
|
|
|
@@ -305,7 +317,7 @@ export class CommandController {
|
|
|
305
317
|
}
|
|
306
318
|
await this.boardController.showCardsByListId(listId);
|
|
307
319
|
} catch (error) {
|
|
308
|
-
console.error(t('commands.
|
|
320
|
+
console.error(t('commands.commandErrors.genericError'), (error as Error).message);
|
|
309
321
|
}
|
|
310
322
|
});
|
|
311
323
|
|
|
@@ -388,6 +400,25 @@ export class CommandController {
|
|
|
388
400
|
},
|
|
389
401
|
);
|
|
390
402
|
|
|
403
|
+
cardsCmd
|
|
404
|
+
.command('show <cardId>')
|
|
405
|
+
.description(t('commands.cards.show.description'))
|
|
406
|
+
.option('-f, --format <format>', t('commands.formatOption'), 'table')
|
|
407
|
+
.action(async (cardId: string, options: { format?: string }) => {
|
|
408
|
+
try {
|
|
409
|
+
await this.initializeTrelloControllers();
|
|
410
|
+
if (options.format) {
|
|
411
|
+
this.outputFormatter.setFormat(options.format as OutputFormat);
|
|
412
|
+
}
|
|
413
|
+
await this.cardController.showCard(cardId);
|
|
414
|
+
} catch (error) {
|
|
415
|
+
console.error(
|
|
416
|
+
t('commands.commandErrors.genericError'),
|
|
417
|
+
(error as Error).message,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
|
|
391
422
|
// Legacy commands with deprecation warnings
|
|
392
423
|
this.program
|
|
393
424
|
.command('cards-legacy <boardName> <listName>')
|
|
@@ -468,7 +499,11 @@ export class CommandController {
|
|
|
468
499
|
}
|
|
469
500
|
|
|
470
501
|
async run(): Promise<void> {
|
|
471
|
-
|
|
502
|
+
// Ensure program is initialized before parsing
|
|
503
|
+
if (!this.program) {
|
|
504
|
+
this.initializeProgram();
|
|
505
|
+
this.setupCommands();
|
|
506
|
+
}
|
|
472
507
|
|
|
473
508
|
// Fallback to interactive mode if no command specified
|
|
474
509
|
if (process.argv.length === 2) {
|
|
@@ -478,7 +513,7 @@ export class CommandController {
|
|
|
478
513
|
).TrelloCliController(configRepository, this.outputFormatter);
|
|
479
514
|
await cli.run();
|
|
480
515
|
} else {
|
|
481
|
-
|
|
516
|
+
this.program.parse();
|
|
482
517
|
}
|
|
483
518
|
}
|
|
484
519
|
}
|
|
Binary file
|