rook-cli 1.0.2 → 1.0.3
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/package.json +1 -1
- package/src/commands/AddCommand.js +73 -7
- package/src/services/GitHubService.js +54 -7
- package/src/ui/PromptUI.js +8 -6
- package/src/utils/logger.js +4 -4
package/package.json
CHANGED
|
@@ -59,18 +59,75 @@ export class AddCommand {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
|
-
* Fluxo de instalação de um kit completo.
|
|
62
|
+
* Fluxo de instalação de um kit completo (nova arquitetura de composição).
|
|
63
|
+
*
|
|
64
|
+
* Segue o padrão descrito no PRD (Seção 5.3):
|
|
65
|
+
* 1. Lista kits disponíveis (com dados do kit.json)
|
|
66
|
+
* 2. Usuário seleciona o kit
|
|
67
|
+
* 3. Instala cada componente referenciado no manifesto
|
|
68
|
+
* 4. Instala os arquivos locais exclusivos do kit
|
|
69
|
+
*
|
|
63
70
|
* @private
|
|
64
71
|
*/
|
|
65
72
|
async _instalarKit() {
|
|
66
|
-
// Lista kits disponíveis
|
|
73
|
+
// 1. Lista kits disponíveis (já enriquecidos com dados do kit.json)
|
|
67
74
|
const kits = await this.githubService.listarKits();
|
|
75
|
+
|
|
76
|
+
if (kits.length === 0) {
|
|
77
|
+
this.logger.aviso('Nenhum kit disponível no repositório.');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 2. Usuário seleciona o kit
|
|
68
82
|
const kitSelecionado = await this.promptUI.selecionarKit(kits);
|
|
69
83
|
|
|
70
84
|
this.logger.destaque(`\n📥 Instalando kit: ${kitSelecionado.nome}\n`);
|
|
71
85
|
|
|
72
|
-
|
|
73
|
-
|
|
86
|
+
if (kitSelecionado.descricao) {
|
|
87
|
+
this.logger.sutil(kitSelecionado.descricao);
|
|
88
|
+
console.log('');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let totalComponentesInstalados = 0;
|
|
92
|
+
let totalArquivosCopiados = 0;
|
|
93
|
+
|
|
94
|
+
// 3. Instala cada componente referenciado no manifesto (kit.json)
|
|
95
|
+
if (kitSelecionado.componentes.length > 0) {
|
|
96
|
+
this.logger.destaque(`🧩 Instalando ${kitSelecionado.componentes.length} componente(s) do manifesto...\n`);
|
|
97
|
+
|
|
98
|
+
for (const nomeComponente of kitSelecionado.componentes) {
|
|
99
|
+
const caminhoComponente = `components/${nomeComponente}`;
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
this.logger.info(`[${totalComponentesInstalados + 1}/${kitSelecionado.componentes.length}] ${nomeComponente}`);
|
|
103
|
+
const copiados = await this._baixarEDistribuir(caminhoComponente, nomeComponente);
|
|
104
|
+
totalArquivosCopiados += copiados;
|
|
105
|
+
totalComponentesInstalados++;
|
|
106
|
+
} catch (erro) {
|
|
107
|
+
this.logger.erro(`Falha ao instalar componente "${nomeComponente}": ${erro.message}`);
|
|
108
|
+
this.logger.aviso('Continuando com os próximos componentes...');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 4. Instala os arquivos locais exclusivos do kit (ex: layout/theme.liquid, config/)
|
|
114
|
+
this.logger.destaque(`\n📁 Instalando arquivos base do kit "${kitSelecionado.slug}"...\n`);
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const copiadosKit = await this._baixarEDistribuir(kitSelecionado.caminho, `kit:${kitSelecionado.slug}`);
|
|
118
|
+
totalArquivosCopiados += copiadosKit;
|
|
119
|
+
} catch (erro) {
|
|
120
|
+
this.logger.erro(`Falha ao instalar arquivos base do kit: ${erro.message}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 5. Resumo final
|
|
124
|
+
console.log('');
|
|
125
|
+
this.logger.destaque('═══════════════════════════════════════════');
|
|
126
|
+
this.logger.sucesso(`🎉 Kit "${kitSelecionado.nome}" instalado com sucesso!`);
|
|
127
|
+
this.logger.sutil(` Componentes: ${totalComponentesInstalados}/${kitSelecionado.componentes.length}`);
|
|
128
|
+
this.logger.sutil(` Arquivos copiados: ${totalArquivosCopiados}`);
|
|
129
|
+
this.logger.destaque('═══════════════════════════════════════════');
|
|
130
|
+
console.log('');
|
|
74
131
|
}
|
|
75
132
|
|
|
76
133
|
/**
|
|
@@ -84,10 +141,16 @@ export class AddCommand {
|
|
|
84
141
|
|
|
85
142
|
this.logger.destaque(`\n📥 Instalando ${selecionados.length} componente(s)...\n`);
|
|
86
143
|
|
|
144
|
+
let totalArquivosCopiados = 0;
|
|
145
|
+
|
|
87
146
|
// Baixa e distribui cada componente
|
|
88
147
|
for (const componente of selecionados) {
|
|
89
|
-
await this._baixarEDistribuir(componente.caminho, componente.nome);
|
|
148
|
+
const copiados = await this._baixarEDistribuir(componente.caminho, componente.nome);
|
|
149
|
+
totalArquivosCopiados += copiados;
|
|
90
150
|
}
|
|
151
|
+
|
|
152
|
+
console.log('');
|
|
153
|
+
this.logger.sucesso(`🎉 ${selecionados.length} componente(s) instalado(s)! (${totalArquivosCopiados} arquivo(s) copiados)\n`);
|
|
91
154
|
}
|
|
92
155
|
|
|
93
156
|
/**
|
|
@@ -95,6 +158,7 @@ export class AddCommand {
|
|
|
95
158
|
*
|
|
96
159
|
* @param {string} caminhoRemoto - Caminho no repositório (ex: "components/whatsapp-btn")
|
|
97
160
|
* @param {string} nomePacote - Nome do pacote para exibição nos logs
|
|
161
|
+
* @returns {Promise<number>} Número de arquivos copiados
|
|
98
162
|
* @private
|
|
99
163
|
*/
|
|
100
164
|
async _baixarEDistribuir(caminhoRemoto, nomePacote) {
|
|
@@ -104,14 +168,16 @@ export class AddCommand {
|
|
|
104
168
|
try {
|
|
105
169
|
await fs.ensureDir(pastaTmp);
|
|
106
170
|
|
|
107
|
-
// Download via tiged
|
|
171
|
+
// Download via tiged ou GitHub API
|
|
108
172
|
await this.downloadService.baixar(caminhoRemoto, pastaTmp);
|
|
109
173
|
|
|
110
174
|
// Distribui nas pastas Shopify locais
|
|
111
175
|
const diretorioAtual = process.cwd();
|
|
112
176
|
const totalCopiados = await this.fileMapper.distribuir(pastaTmp, diretorioAtual);
|
|
113
177
|
|
|
114
|
-
this.logger.sucesso(
|
|
178
|
+
this.logger.sucesso(` ✔ "${nomePacote}" — ${totalCopiados} arquivo(s)`);
|
|
179
|
+
|
|
180
|
+
return totalCopiados;
|
|
115
181
|
|
|
116
182
|
} finally {
|
|
117
183
|
// Limpa pasta temporária
|
|
@@ -65,19 +65,66 @@ export class GitHubService {
|
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* Lista os kits disponíveis no repositório.
|
|
68
|
-
*
|
|
68
|
+
* Busca o kit.json de cada kit para obter nome e descrição.
|
|
69
|
+
*
|
|
70
|
+
* @returns {Promise<Array<{nome: string, slug: string, descricao: string, componentes: string[], caminho: string}>>} Lista de kits
|
|
69
71
|
*/
|
|
70
72
|
async listarKits() {
|
|
71
73
|
this.logger.info('Buscando kits disponíveis...');
|
|
72
74
|
|
|
73
75
|
const itens = await this.listarDiretorio(REMOTE_PATHS.KITS);
|
|
76
|
+
const pastasKit = itens.filter(item => item.type === 'dir');
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
const kits = [];
|
|
79
|
+
|
|
80
|
+
for (const pasta of pastasKit) {
|
|
81
|
+
try {
|
|
82
|
+
const manifesto = await this.buscarKitManifesto(pasta.name);
|
|
83
|
+
kits.push({
|
|
84
|
+
nome: manifesto.name || pasta.name,
|
|
85
|
+
slug: pasta.name,
|
|
86
|
+
descricao: manifesto.description || '',
|
|
87
|
+
componentes: manifesto.components || [],
|
|
88
|
+
caminho: `${REMOTE_PATHS.KITS}/${pasta.name}`,
|
|
89
|
+
});
|
|
90
|
+
} catch {
|
|
91
|
+
// Se o kit não tem kit.json válido, lista com dados básicos
|
|
92
|
+
this.logger.aviso(`Kit "${pasta.name}" sem kit.json válido. Ignorando.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return kits;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Busca e parseia o manifesto (kit.json) de um kit específico.
|
|
101
|
+
*
|
|
102
|
+
* @param {string} nomeKit - Nome/slug da pasta do kit (ex: "starter-base")
|
|
103
|
+
* @returns {Promise<{name: string, version: string, description: string, components: string[]}>} Manifesto do kit
|
|
104
|
+
*/
|
|
105
|
+
async buscarKitManifesto(nomeKit) {
|
|
106
|
+
const caminho = `${REMOTE_PATHS.KITS}/${nomeKit}/kit.json`;
|
|
107
|
+
const url = `${GITHUB_API_BASE}/${caminho}`;
|
|
108
|
+
const headers = await this.tokenManager.obterHeaders();
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const resposta = await fetch(url, { headers });
|
|
112
|
+
|
|
113
|
+
if (!resposta.ok) {
|
|
114
|
+
throw new Error(`kit.json não encontrado para "${nomeKit}" (HTTP ${resposta.status})`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const dados = await resposta.json();
|
|
118
|
+
|
|
119
|
+
// A API do GitHub retorna o conteúdo em base64
|
|
120
|
+
const conteudo = Buffer.from(dados.content, 'base64').toString('utf-8');
|
|
121
|
+
const manifesto = JSON.parse(conteudo);
|
|
122
|
+
|
|
123
|
+
return manifesto;
|
|
124
|
+
} catch (erro) {
|
|
125
|
+
this.logger.erro(`Falha ao ler kit.json de "${nomeKit}": ${erro.message}`);
|
|
126
|
+
throw erro;
|
|
127
|
+
}
|
|
81
128
|
}
|
|
82
129
|
|
|
83
130
|
/**
|
package/src/ui/PromptUI.js
CHANGED
|
@@ -39,24 +39,26 @@ export class PromptUI {
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Exibe a lista de kits disponíveis para seleção.
|
|
42
|
+
* Mostra nome e descrição vindos do kit.json (manifesto).
|
|
42
43
|
*
|
|
43
|
-
* @param {Array<{nome: string, caminho: string}>} kits - Kits disponíveis
|
|
44
|
-
* @returns {Promise<{nome: string, caminho: string}>} Kit selecionado
|
|
44
|
+
* @param {Array<{nome: string, slug: string, descricao: string, componentes: string[], caminho: string}>} kits - Kits disponíveis
|
|
45
|
+
* @returns {Promise<{nome: string, slug: string, descricao: string, componentes: string[], caminho: string}>} Kit selecionado
|
|
45
46
|
*/
|
|
46
47
|
async selecionarKit(kits) {
|
|
47
48
|
if (kits.length === 0) {
|
|
48
49
|
throw new Error('Nenhum kit disponível no repositório.');
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
const
|
|
52
|
+
const slug = await select({
|
|
52
53
|
message: '🎯 Selecione o kit para instalar:',
|
|
53
54
|
choices: kits.map(kit => ({
|
|
54
|
-
name: `📁 ${kit.nome}`,
|
|
55
|
-
value: kit.
|
|
55
|
+
name: `📁 ${kit.nome} (${kit.componentes.length} componentes)`,
|
|
56
|
+
value: kit.slug,
|
|
57
|
+
description: kit.descricao || undefined,
|
|
56
58
|
})),
|
|
57
59
|
});
|
|
58
60
|
|
|
59
|
-
return kits.find(k => k.
|
|
61
|
+
return kits.find(k => k.slug === slug);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
/**
|
package/src/utils/logger.js
CHANGED
|
@@ -48,10 +48,10 @@ export class Logger {
|
|
|
48
48
|
*/
|
|
49
49
|
banner() {
|
|
50
50
|
console.log('');
|
|
51
|
-
console.log(pc.bold(pc.
|
|
52
|
-
console.log(pc.bold(pc.
|
|
53
|
-
console.log(pc.bold(pc.
|
|
54
|
-
console.log(pc.bold(pc.
|
|
51
|
+
console.log(pc.bold(pc.white(' ╔══════════════════════════════╗')));
|
|
52
|
+
console.log(pc.bold(pc.white(' ║ ♟️ ROOK CLI v1.0.3 ║')));
|
|
53
|
+
console.log(pc.bold(pc.white(' ║ Shopify Component Tool ║')));
|
|
54
|
+
console.log(pc.bold(pc.white(' ╚══════════════════════════════╝')));
|
|
55
55
|
console.log('');
|
|
56
56
|
}
|
|
57
57
|
|