@brunoluizdesiqueira/bbuilder-cli 1.0.1 → 1.0.2

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 CHANGED
@@ -23,6 +23,90 @@ npm install -g @brunoluizdesiqueira/bbuilder-cli
23
23
  npm publish --access public
24
24
  ```
25
25
 
26
+ ## Publicação
27
+
28
+ ### Publicação manual inicial
29
+
30
+ Use esse fluxo para a primeira publicação ou para publicar manualmente uma versão:
31
+
32
+ 1. Faça login no npm:
33
+
34
+ ```bash
35
+ npm login
36
+ ```
37
+
38
+ 2. Valide o pacote localmente:
39
+
40
+ ```bash
41
+ npm run build
42
+ npm pack --dry-run
43
+ ```
44
+
45
+ 3. Publique:
46
+
47
+ ```bash
48
+ npm publish --access public
49
+ ```
50
+
51
+ Se a versão atual do `package.json` já tiver sido publicada, gere uma nova versão antes:
52
+
53
+ ```bash
54
+ npm version patch --no-git-tag-version
55
+ npm publish --access public
56
+ ```
57
+
58
+ ### Configurar publicação automática
59
+
60
+ Depois da primeira publicação manual, configure o npm para confiar no workflow do GitHub Actions.
61
+
62
+ No npm:
63
+
64
+ 1. abra a página do pacote `@brunoluizdesiqueira/bbuilder-cli`
65
+ 2. vá em `Settings`
66
+ 3. abra `Trusted publishing`
67
+ 4. adicione um publisher do tipo `GitHub Actions`
68
+ 5. configure:
69
+ - repositório: `brunoluizdesiqueira/b-cli`
70
+ - workflow: `release.yml`
71
+
72
+ Na opção **Publishing access**, use:
73
+
74
+ - `Require two-factor authentication or a granular access token with bypass 2fa enabled`
75
+
76
+ Evite para esse fluxo:
77
+
78
+ - `Require two-factor authentication and disallow tokens`
79
+
80
+ ### Publicação automática com Changesets
81
+
82
+ Depois do Trusted Publisher configurado, o fluxo recomendado fica assim:
83
+
84
+ 1. criar uma changeset para cada mudança publicada:
85
+
86
+ ```bash
87
+ npm run changeset
88
+ ```
89
+
90
+ 2. fazer commit da changeset junto com o código
91
+ 3. abrir PR e fazer merge na `main`
92
+ 4. o workflow `Release` abre ou atualiza uma PR de release
93
+ 5. ao mergear a PR de release, o npm é publicado automaticamente
94
+
95
+ Comandos locais úteis:
96
+
97
+ ```bash
98
+ npm run changeset
99
+ npm run version-packages
100
+ npm run release
101
+ ```
102
+
103
+ ## CI/CD
104
+
105
+ O repositório agora está preparado com GitHub Actions:
106
+
107
+ - `CI`: roda em `push` e `pull_request`, executando `npm ci`, `tsc`, `build` e `npm pack --dry-run`
108
+ - `Release`: usa `changesets` para abrir uma PR de release com bump de versão e changelog; quando essa PR entra na `main`, o pacote é publicado no npm
109
+
26
110
  Ou use direto sem instalar globalmente:
27
111
  ```bash
28
112
  npx ts-node src/index.ts build
@@ -57,12 +141,15 @@ bbuilder release --project Bimer --version 11.3.1
57
141
  ```bash
58
142
  bbuilder project list # lista projetos configurados
59
143
  bbuilder project add # adiciona novo projeto (interativo)
144
+ bbuilder project remove # remove projeto (interativo ou por --name)
60
145
  ```
61
146
 
62
147
  ### Configuração do ambiente
63
148
  ```bash
64
149
  bbuilder config init # assistente para criar bbuilder.config.json
65
150
  bbuilder config show # exibe configuração atual
151
+ bbuilder config validate # valida a estrutura do arquivo de configuração
152
+ bbuilder doctor # diagnostica ambiente, config e paths
66
153
  ```
67
154
 
68
155
  ---
@@ -110,6 +197,46 @@ Crie com `bbuilder config init`, ou manualmente:
110
197
 
111
198
  Se o arquivo não existir, os valores padrão acima são usados automaticamente. Ao rodar `bbuilder config init`, a CLI gera um `dependencyPaths` inicial com base nos diretórios informados.
112
199
 
200
+ ### Como usar configs locais
201
+
202
+ O pacote é instalado normalmente, e a configuração é informada na execução, não na instalação.
203
+
204
+ Instalação global:
205
+
206
+ ```bash
207
+ npm install -g @brunoluizdesiqueira/bbuilder-cli
208
+ ```
209
+
210
+ Usando um arquivo de config local explícito:
211
+
212
+ ```bash
213
+ bbuilder --config C:\configs\bbuilder.config.json build
214
+ ```
215
+
216
+ Usando variável de ambiente no Windows CMD:
217
+
218
+ ```bat
219
+ set BBUILDER_CONFIG=C:\configs\bbuilder.config.json
220
+ bbuilder build
221
+ ```
222
+
223
+ Usando variável de ambiente no PowerShell:
224
+
225
+ ```powershell
226
+ $env:BBUILDER_CONFIG="C:\configs\bbuilder.config.json"
227
+ bbuilder build
228
+ ```
229
+
230
+ Usando config local no diretório atual:
231
+
232
+ Se existir um `bbuilder.config.json` na pasta onde o comando é executado, a CLI usa esse arquivo automaticamente.
233
+
234
+ Para verificar qual arquivo está sendo usado:
235
+
236
+ ```bash
237
+ bbuilder config show
238
+ ```
239
+
113
240
  Exemplos:
114
241
 
115
242
  ```bash
@@ -188,15 +315,41 @@ E nos keybindings, nada muda — os atalhos continuam os mesmos.
188
315
 
189
316
  ```
190
317
  bbuilder-cli/
318
+ ├── .changeset/
319
+ │ ├── config.json
320
+ │ └── *.md
321
+ ├── .github/
322
+ │ └── workflows/
323
+ │ ├── ci.yml
324
+ │ └── release.yml
191
325
  ├── src/
192
326
  │ ├── build/
327
+ │ │ ├── compiler.ts
328
+ │ │ ├── execute.ts
329
+ │ │ ├── project.ts
330
+ │ │ └── resources.ts
193
331
  │ ├── cli/
332
+ │ │ └── program.ts
194
333
  │ ├── config/
334
+ │ │ ├── config.ts
335
+ │ │ └── validate.ts
336
+ │ ├── diagnostics/
337
+ │ │ └── doctor.ts
195
338
  │ ├── ui/
339
+ │ │ ├── output.ts
340
+ │ │ └── prompts.ts
196
341
  │ ├── index.ts
197
342
  │ └── types.ts
343
+ ├── files/
344
+ │ ├── build_local.bat
345
+ │ ├── tasks.json
346
+ │ └── ...
347
+ ├── bbuilder.config.json
198
348
  ├── package.json
349
+ ├── package-lock.json
199
350
  ├── tsconfig.json
351
+ ├── .gitignore
352
+ ├── LICENSE
200
353
  └── README.md
201
354
  ```
202
355
 
@@ -8,24 +8,97 @@ const commander_1 = require("commander");
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
9
  const execute_1 = require("../build/execute");
10
10
  const config_1 = require("../config/config");
11
+ const validate_1 = require("../config/validate");
12
+ const doctor_1 = require("../diagnostics/doctor");
11
13
  const output_1 = require("../ui/output");
12
14
  const prompts_1 = require("../ui/prompts");
15
+ const packageJson = require('../../package.json');
16
+ const HELP_EXAMPLES = {
17
+ root: [
18
+ 'Exemplos:',
19
+ ' bbuilder',
20
+ ' bbuilder build --type DEBUG --project faturamento\\BimerFaturamento',
21
+ ' bbuilder fast --project Bimer',
22
+ ' bbuilder --config C:\\configs\\bbuilder.config.json doctor',
23
+ ].join('\n'),
24
+ build: [
25
+ 'Exemplos:',
26
+ ' bbuilder build',
27
+ ' bbuilder build --type RELEASE --project Bimer --version 11.3.1',
28
+ ' bbuilder build --type FAST --project faturamento\\BimerFaturamento',
29
+ ].join('\n'),
30
+ fast: [
31
+ 'Exemplos:',
32
+ ' bbuilder fast',
33
+ ' bbuilder fast --project Bimer',
34
+ ' bbuilder fast --project faturamento\\BimerFaturamento --version 11.3.1',
35
+ ].join('\n'),
36
+ debug: [
37
+ 'Exemplos:',
38
+ ' bbuilder debug',
39
+ ' bbuilder debug --project Bimer',
40
+ ' bbuilder debug --project faturamento\\BimerFaturamento --version 11.3.1',
41
+ ].join('\n'),
42
+ release: [
43
+ 'Exemplos:',
44
+ ' bbuilder release',
45
+ ' bbuilder release --project Bimer',
46
+ ' bbuilder release --project faturamento\\BimerFaturamento --version 11.3.1',
47
+ ].join('\n'),
48
+ config: [
49
+ 'Exemplos:',
50
+ ' bbuilder config init',
51
+ ' bbuilder config show',
52
+ ' bbuilder config validate',
53
+ ' bbuilder --config C:\\configs\\bbuilder.config.json config show',
54
+ ].join('\n'),
55
+ configValidate: [
56
+ 'Exemplos:',
57
+ ' bbuilder config validate',
58
+ ' bbuilder --config C:\\configs\\bbuilder.config.json config validate',
59
+ ].join('\n'),
60
+ project: [
61
+ 'Exemplos:',
62
+ ' bbuilder project list',
63
+ ' bbuilder project add',
64
+ ' bbuilder project remove',
65
+ ' bbuilder project remove --name Bimer',
66
+ ].join('\n'),
67
+ projectRemove: [
68
+ 'Exemplos:',
69
+ ' bbuilder project remove',
70
+ ' bbuilder project remove --name Bimer',
71
+ ].join('\n'),
72
+ doctor: [
73
+ 'Exemplos:',
74
+ ' bbuilder doctor',
75
+ ' bbuilder --config C:\\configs\\bbuilder.config.json doctor',
76
+ ].join('\n'),
77
+ };
78
+ function attachHelpExamples(command, examples) {
79
+ command.on('--help', () => {
80
+ console.log('');
81
+ console.log(examples);
82
+ console.log('');
83
+ });
84
+ return command;
85
+ }
13
86
  async function runCli(argv) {
14
87
  const resolvedConfigPath = (0, config_1.resolveConfigPath)(argv);
15
88
  const writableConfigPath = (0, config_1.getWritableConfigPath)(resolvedConfigPath);
16
89
  const config = (0, config_1.loadConfig)(resolvedConfigPath);
17
90
  const program = new commander_1.Command();
18
- program
91
+ attachHelpExamples(program
19
92
  .name('bbuilder')
20
93
  .description('CLI de build local para projetos Delphi do Bimer')
21
- .version('1.0.0')
22
- .option('-c, --config <path>', `Caminho do arquivo de configuração (ou ${config_1.CONFIG_ENV_VAR})`);
23
- program
94
+ .version(packageJson.version)
95
+ .option('-c, --config <path>', `Caminho do arquivo de configuração (ou ${config_1.CONFIG_ENV_VAR})`), HELP_EXAMPLES.root);
96
+ const buildCmd = attachHelpExamples(program
24
97
  .command('build')
25
98
  .description('Compila um projeto Delphi (interativo se flags omitidas)')
26
99
  .option('-t, --type <FAST|DEBUG|RELEASE>', 'Modo de build')
27
100
  .option('-p, --project <path>', 'Caminho do projeto (ex: faturamento\\BimerFaturamento)')
28
- .option('-v, --version <version>', 'Versão a injetar (ex: 11.2.4)')
101
+ .option('-v, --version <version>', 'Versão a injetar (ex: 11.2.4)'), HELP_EXAMPLES.build)
29
102
  .action(async (opts) => {
30
103
  const buildType = opts.type?.toUpperCase();
31
104
  if (buildType && !['FAST', 'DEBUG', 'RELEASE'].includes(buildType)) {
@@ -35,7 +108,7 @@ async function runCli(argv) {
35
108
  await (0, execute_1.executeBuild)(resolved);
36
109
  });
37
110
  for (const type of ['fast', 'debug', 'release']) {
38
- program
111
+ const shortcutCmd = program
39
112
  .command(type)
40
113
  .description(`Compila no modo ${type.toUpperCase()} (interativo para projeto/versão)`)
41
114
  .option('-p, --project <path>', 'Caminho do projeto')
@@ -44,10 +117,11 @@ async function runCli(argv) {
44
117
  const resolved = await (0, prompts_1.promptBuild)(config, type.toUpperCase(), opts.project, opts.version);
45
118
  await (0, execute_1.executeBuild)(resolved);
46
119
  });
120
+ attachHelpExamples(shortcutCmd, HELP_EXAMPLES[type]);
47
121
  }
48
- const configCmd = program
122
+ const configCmd = attachHelpExamples(program
49
123
  .command('config')
50
- .description('Gerencia a configuração do ambiente');
124
+ .description('Gerencia a configuração do ambiente'), HELP_EXAMPLES.config);
51
125
  configCmd
52
126
  .command('init')
53
127
  .description('Configura o ambiente de forma interativa (cria bbuilder.config.json)')
@@ -67,9 +141,14 @@ async function runCli(argv) {
67
141
  .join('\n'));
68
142
  console.log('');
69
143
  });
70
- const projectCmd = program
144
+ const configValidateCmd = configCmd
145
+ .command('validate')
146
+ .description('Valida a estrutura do arquivo de configuração')
147
+ .action(() => (0, validate_1.runConfigValidate)(resolvedConfigPath));
148
+ attachHelpExamples(configValidateCmd, HELP_EXAMPLES.configValidate);
149
+ const projectCmd = attachHelpExamples(program
71
150
  .command('project')
72
- .description('Gerencia a lista de projetos');
151
+ .description('Gerencia a lista de projetos'), HELP_EXAMPLES.project);
73
152
  projectCmd
74
153
  .command('add')
75
154
  .description('Adiciona um novo projeto à lista')
@@ -86,6 +165,16 @@ async function runCli(argv) {
86
165
  });
87
166
  console.log('');
88
167
  });
168
+ const projectRemoveCmd = projectCmd
169
+ .command('remove')
170
+ .description('Remove um projeto da lista')
171
+ .option('-n, --name <projectName>', 'Nome do projeto cadastrado')
172
+ .action((opts) => (0, prompts_1.runProjectRemove)(config, writableConfigPath, opts.name));
173
+ attachHelpExamples(projectRemoveCmd, HELP_EXAMPLES.projectRemove);
174
+ attachHelpExamples(program
175
+ .command('doctor')
176
+ .description('Diagnostica configuração, paths e binários do ambiente')
177
+ .action(() => (0, doctor_1.runDoctor)(config, resolvedConfigPath)), HELP_EXAMPLES.doctor);
89
178
  if (argv.length <= 2) {
90
179
  (0, output_1.banner)();
91
180
  const resolved = await (0, prompts_1.promptBuild)(config);
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.validateConfigObject = validateConfigObject;
40
+ exports.runConfigValidate = runConfigValidate;
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const fs = __importStar(require("fs"));
43
+ function isNonEmptyString(value) {
44
+ return typeof value === 'string' && value.trim().length > 0;
45
+ }
46
+ function validateProjects(projects) {
47
+ if (!projects || typeof projects !== 'object' || Array.isArray(projects)) {
48
+ return [{ field: 'projects', message: 'deve ser um objeto no formato nome => caminho' }];
49
+ }
50
+ const entries = Object.entries(projects);
51
+ if (entries.length === 0) {
52
+ return [{ field: 'projects', message: 'deve conter ao menos um projeto configurado' }];
53
+ }
54
+ const issues = [];
55
+ for (const [name, projectPath] of entries) {
56
+ if (!isNonEmptyString(name)) {
57
+ issues.push({ field: 'projects', message: 'contém uma chave de projeto inválida' });
58
+ }
59
+ if (!isNonEmptyString(projectPath)) {
60
+ issues.push({ field: `projects.${name}`, message: 'deve apontar para um caminho não vazio' });
61
+ }
62
+ }
63
+ return issues;
64
+ }
65
+ function validateConfigObject(raw) {
66
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
67
+ return [{ field: 'config', message: 'o arquivo deve conter um objeto JSON válido' }];
68
+ }
69
+ const config = raw;
70
+ const issues = [];
71
+ const requiredStringFields = [
72
+ 'repoBase',
73
+ 'delphiDir',
74
+ 'envVersion',
75
+ 'libRoot',
76
+ 'libErp',
77
+ 'libAlterdata',
78
+ ];
79
+ for (const field of requiredStringFields) {
80
+ if (!isNonEmptyString(config[field])) {
81
+ issues.push({ field, message: 'deve ser uma string não vazia' });
82
+ }
83
+ }
84
+ if (!Array.isArray(config.dependencyPaths) || config.dependencyPaths.length === 0) {
85
+ issues.push({ field: 'dependencyPaths', message: 'deve ser um array com ao menos um path' });
86
+ }
87
+ else {
88
+ config.dependencyPaths.forEach((depPath, index) => {
89
+ if (!isNonEmptyString(depPath)) {
90
+ issues.push({ field: `dependencyPaths[${index}]`, message: 'deve ser uma string não vazia' });
91
+ }
92
+ });
93
+ }
94
+ issues.push(...validateProjects(config.projects));
95
+ return issues;
96
+ }
97
+ function runConfigValidate(configPath) {
98
+ console.log('');
99
+ console.log(chalk_1.default.cyan(' Validação da Configuração'));
100
+ console.log(chalk_1.default.blue(' ─────────────────────────'));
101
+ console.log(chalk_1.default.gray(` Arquivo: ${configPath}`));
102
+ console.log('');
103
+ if (!fs.existsSync(configPath)) {
104
+ console.log(chalk_1.default.red(' FAIL Arquivo de configuração não encontrado.'));
105
+ console.log('');
106
+ process.exitCode = 1;
107
+ return;
108
+ }
109
+ let rawText;
110
+ try {
111
+ rawText = fs.readFileSync(configPath, 'utf-8');
112
+ }
113
+ catch (error) {
114
+ console.log(chalk_1.default.red(` FAIL Não foi possível ler o arquivo: ${error instanceof Error ? error.message : String(error)}`));
115
+ console.log('');
116
+ process.exitCode = 1;
117
+ return;
118
+ }
119
+ let parsed;
120
+ try {
121
+ parsed = JSON.parse(rawText);
122
+ }
123
+ catch (error) {
124
+ console.log(chalk_1.default.red(` FAIL JSON inválido: ${error instanceof Error ? error.message : String(error)}`));
125
+ console.log('');
126
+ process.exitCode = 1;
127
+ return;
128
+ }
129
+ const issues = validateConfigObject(parsed);
130
+ if (issues.length === 0) {
131
+ console.log(chalk_1.default.green(' OK Estrutura da configuração está válida.'));
132
+ console.log('');
133
+ return;
134
+ }
135
+ issues.forEach(issue => {
136
+ console.log(chalk_1.default.red(` FAIL ${issue.field}: ${issue.message}`));
137
+ });
138
+ console.log('');
139
+ process.exitCode = 1;
140
+ }
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.runDoctor = runDoctor;
40
+ const chalk_1 = __importDefault(require("chalk"));
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ function checkPath(label, targetPath) {
44
+ return {
45
+ label,
46
+ ok: fs.existsSync(targetPath),
47
+ detail: targetPath,
48
+ };
49
+ }
50
+ function checkFile(label, targetPath) {
51
+ return {
52
+ label,
53
+ ok: fs.existsSync(targetPath) && fs.statSync(targetPath).isFile(),
54
+ detail: targetPath,
55
+ };
56
+ }
57
+ function printCheck(result) {
58
+ const status = result.ok ? chalk_1.default.green('OK') : chalk_1.default.red('FAIL');
59
+ console.log(` ${status.padEnd(6)} ${chalk_1.default.white(result.label)} ${chalk_1.default.gray(`→ ${result.detail}`)}`);
60
+ }
61
+ function runDoctor(config, resolvedConfigPath) {
62
+ const checks = [];
63
+ const cgrcPath = path.win32.join(config.delphiDir, 'bin', 'cgrc.exe');
64
+ const dcc64Path = path.win32.join(config.delphiDir, 'bin', 'dcc64.exe');
65
+ checks.push(checkFile('Arquivo de configuração em uso', resolvedConfigPath));
66
+ checks.push(checkPath('repoBase', config.repoBase));
67
+ checks.push(checkPath('delphiDir', config.delphiDir));
68
+ checks.push(checkPath('libRoot', config.libRoot));
69
+ checks.push(checkPath('libErp', config.libErp));
70
+ checks.push(checkPath('libAlterdata', config.libAlterdata));
71
+ checks.push(checkFile('cgrc.exe', cgrcPath));
72
+ checks.push(checkFile('dcc64.exe', dcc64Path));
73
+ const projectEntries = Object.entries(config.projects);
74
+ checks.push({
75
+ label: 'Projetos configurados',
76
+ ok: projectEntries.length > 0,
77
+ detail: `${projectEntries.length} projeto(s)`,
78
+ });
79
+ checks.push({
80
+ label: 'dependencyPaths configurados',
81
+ ok: Array.isArray(config.dependencyPaths) && config.dependencyPaths.length > 0,
82
+ detail: `${config.dependencyPaths.length} path(s)`,
83
+ });
84
+ console.log('');
85
+ console.log(chalk_1.default.cyan(' Diagnóstico do Ambiente'));
86
+ console.log(chalk_1.default.blue(' ───────────────────────'));
87
+ console.log(chalk_1.default.gray(` Config: ${resolvedConfigPath}`));
88
+ console.log('');
89
+ checks.forEach(printCheck);
90
+ if (projectEntries.length > 0) {
91
+ console.log('');
92
+ console.log(chalk_1.default.cyan(' Projetos'));
93
+ console.log(chalk_1.default.blue(' ────────'));
94
+ projectEntries.forEach(([name, projectPath]) => {
95
+ const fullPath = path.win32.join(config.repoBase, projectPath);
96
+ const dprojPath = `${fullPath}.dproj`;
97
+ const exists = fs.existsSync(dprojPath);
98
+ const status = exists ? chalk_1.default.green('OK') : chalk_1.default.red('FAIL');
99
+ console.log(` ${status.padEnd(6)} ${chalk_1.default.white(name)} ${chalk_1.default.gray(`→ ${dprojPath}`)}`);
100
+ });
101
+ }
102
+ if (config.dependencyPaths.length > 0) {
103
+ console.log('');
104
+ console.log(chalk_1.default.cyan(' Dependências'));
105
+ console.log(chalk_1.default.blue(' ────────────'));
106
+ config.dependencyPaths.forEach(depPath => {
107
+ const exists = fs.existsSync(depPath);
108
+ const status = exists ? chalk_1.default.green('OK') : chalk_1.default.yellow('WARN');
109
+ console.log(` ${status.padEnd(6)} ${chalk_1.default.gray(depPath)}`);
110
+ });
111
+ }
112
+ const failed = checks.filter(check => !check.ok).length;
113
+ console.log('');
114
+ if (failed === 0) {
115
+ console.log(chalk_1.default.green(' Ambiente básico validado com sucesso.'));
116
+ }
117
+ else {
118
+ console.log(chalk_1.default.yellow(` Diagnóstico concluído com ${failed} problema(s) principal(is).`));
119
+ process.exitCode = 1;
120
+ }
121
+ console.log('');
122
+ }
package/dist/index.js CHANGED
File without changes
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.promptBuild = promptBuild;
7
7
  exports.runConfigInit = runConfigInit;
8
8
  exports.runProjectAdd = runProjectAdd;
9
+ exports.runProjectRemove = runProjectRemove;
9
10
  const chalk_1 = __importDefault(require("chalk"));
10
11
  const inquirer_1 = __importDefault(require("inquirer"));
11
12
  const config_1 = require("../config/config");
@@ -122,3 +123,37 @@ async function runProjectAdd(config, configPath) {
122
123
  (0, config_1.saveConfig)(nextConfig, configPath);
123
124
  console.log(chalk_1.default.green(`\n ✔ Projeto "${projectName}" adicionado!\n`));
124
125
  }
126
+ async function runProjectRemove(config, configPath, cliProjectName) {
127
+ const projectEntries = Object.entries(config.projects);
128
+ if (projectEntries.length === 0) {
129
+ console.log(chalk_1.default.yellow('\n Não há projetos cadastrados para remover.\n'));
130
+ return;
131
+ }
132
+ let projectName = cliProjectName;
133
+ if (!projectName) {
134
+ const answers = await inquirer_1.default.prompt([
135
+ {
136
+ type: 'list',
137
+ name: 'projectName',
138
+ message: 'Qual projeto deseja remover?',
139
+ choices: projectEntries.map(([name, projectPath]) => ({
140
+ name: `${name} (${projectPath})`,
141
+ value: name,
142
+ })),
143
+ },
144
+ ]);
145
+ projectName = answers.projectName;
146
+ }
147
+ if (!projectName || !config.projects[projectName]) {
148
+ console.log(chalk_1.default.yellow(`\n Projeto "${projectName || ''}" não encontrado.\n`));
149
+ return;
150
+ }
151
+ const nextProjects = { ...config.projects };
152
+ delete nextProjects[projectName];
153
+ const nextConfig = {
154
+ ...config,
155
+ projects: nextProjects,
156
+ };
157
+ (0, config_1.saveConfig)(nextConfig, configPath);
158
+ console.log(chalk_1.default.green(`\n ✔ Projeto "${projectName}" removido!\n`));
159
+ }
package/package.json CHANGED
@@ -1,19 +1,42 @@
1
1
  {
2
2
  "name": "@brunoluizdesiqueira/bbuilder-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "CLI de build local para projetos Delphi do Bimer",
5
+ "license": "ISC",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/brunoluizdesiqueira/b-cli.git"
9
+ },
10
+ "homepage": "https://github.com/brunoluizdesiqueira/b-cli#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/brunoluizdesiqueira/b-cli/issues"
13
+ },
14
+ "keywords": [
15
+ "cli",
16
+ "delphi",
17
+ "builder",
18
+ "bimer",
19
+ "typescript"
20
+ ],
5
21
  "files": [
6
22
  "dist",
7
23
  "README.md",
8
24
  "LICENSE"
9
25
  ],
26
+ "publishConfig": {
27
+ "access": "public",
28
+ "provenance": true
29
+ },
10
30
  "bin": {
11
- "bbuilder": "dist/index.js"
31
+ "bbuilder": "./dist/index.js"
12
32
  },
13
33
  "scripts": {
14
34
  "build": "tsc",
15
35
  "dev": "ts-node src/index.ts",
16
- "prepack": "npm run build"
36
+ "prepack": "npm run build",
37
+ "changeset": "changeset",
38
+ "version-packages": "changeset version",
39
+ "release": "changeset publish"
17
40
  },
18
41
  "engines": {
19
42
  "node": ">=18"
@@ -25,6 +48,7 @@
25
48
  "inquirer": "^8.2.6"
26
49
  },
27
50
  "devDependencies": {
51
+ "@changesets/cli": "^2.30.0",
28
52
  "@types/inquirer": "^8.2.10",
29
53
  "@types/node": "^20.0.0",
30
54
  "ts-node": "^10.9.2",