@brunoluizdesiqueira/bbuilder-cli 1.0.0 → 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
@@ -10,7 +10,7 @@ CLI em Node.js/TypeScript que substitui o `build_local.bat` com interface intera
10
10
  # Desenvolvimento local
11
11
  npm install
12
12
  npm run build
13
- npm link # disponibiliza o comando 'delphi' globalmente
13
+ npm link # disponibiliza o comando 'bbuilder' globalmente
14
14
  ```
15
15
 
16
16
  ```bash
@@ -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
@@ -34,35 +118,38 @@ npx ts-node src/index.ts build
34
118
 
35
119
  ### Modo interativo (sem argumentos)
36
120
  ```bash
37
- delphi
121
+ bbuilder
38
122
  ```
39
123
  Exibe menus para escolher: modo de build → projeto → versão.
40
124
 
41
125
  ### Comando `build` com flags opcionais
42
126
  ```bash
43
- delphi build # interativo completo
44
- delphi build --type DEBUG # escolhe projeto e versão interativamente
45
- delphi build --type FAST --project faturamento\BimerFaturamento
46
- delphi build --type RELEASE --project Bimer --version 11.3.1
127
+ bbuilder build # interativo completo
128
+ bbuilder build --type DEBUG # escolhe projeto e versão interativamente
129
+ bbuilder build --type FAST --project faturamento\BimerFaturamento
130
+ bbuilder build --type RELEASE --project Bimer --version 11.3.1
47
131
  ```
48
132
 
49
133
  ### Atalhos diretos por modo
50
134
  ```bash
51
- delphi fast # interativo para projeto/versão
52
- delphi debug --project Bimer
53
- delphi release --project Bimer --version 11.3.1
135
+ bbuilder fast # interativo para projeto/versão
136
+ bbuilder debug --project Bimer
137
+ bbuilder release --project Bimer --version 11.3.1
54
138
  ```
55
139
 
56
140
  ### Gerenciamento de projetos
57
141
  ```bash
58
- delphi project list # lista projetos configurados
59
- delphi project add # adiciona novo projeto (interativo)
142
+ bbuilder project list # lista projetos configurados
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
- delphi config init # assistente para criar bbuilder.config.json
65
- delphi config show # exibe configuração atual
149
+ bbuilder config init # assistente para criar bbuilder.config.json
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
  ---
@@ -71,7 +158,7 @@ delphi config show # exibe configuração atual
71
158
 
72
159
  Prioridade de resolução da configuração:
73
160
 
74
- 1. `delphi --config <caminho>`
161
+ 1. `bbuilder --config <caminho>`
75
162
  2. Variável de ambiente `BBUILDER_CONFIG`
76
163
  3. `bbuilder.config.json` no diretório atual
77
164
  4. `bimer.config.json` no diretório atual, por compatibilidade
@@ -79,7 +166,7 @@ Prioridade de resolução da configuração:
79
166
 
80
167
  No Windows, o arquivo global fica em `%APPDATA%\bbuilder-cli\bbuilder.config.json`.
81
168
 
82
- Crie com `delphi config init`, ou manualmente:
169
+ Crie com `bbuilder config init`, ou manualmente:
83
170
 
84
171
  ```json
85
172
  {
@@ -108,17 +195,57 @@ Crie com `delphi config init`, ou manualmente:
108
195
 
109
196
  `projects` agora usa o formato `nome amigável: caminho real do projeto`, para a CLI exibir nomes humanizados sem perder a referência correta de compilação.
110
197
 
111
- Se o arquivo não existir, os valores padrão acima são usados automaticamente. Ao rodar `delphi config init`, a CLI gera um `dependencyPaths` inicial com base nos diretórios informados.
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.
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
+ ```
112
239
 
113
240
  Exemplos:
114
241
 
115
242
  ```bash
116
- delphi --config C:\configs\bbuilder.config.json build
243
+ bbuilder --config C:\configs\bbuilder.config.json build
117
244
  ```
118
245
 
119
246
  ```bash
120
247
  set BBUILDER_CONFIG=C:\configs\bbuilder.config.json
121
- delphi config show
248
+ bbuilder config show
122
249
  ```
123
250
 
124
251
  ---
@@ -134,7 +261,7 @@ Substitua o `tasks.json` atual por este (sem mais menus do VSCode, a CLI cuida d
134
261
  {
135
262
  "label": "Bimer: FAST + Run",
136
263
  "type": "shell",
137
- "command": "delphi fast",
264
+ "command": "bbuilder fast",
138
265
  "group": "build",
139
266
  "presentation": { "reveal": "always", "focus": true, "panel": "dedicated", "clear": true },
140
267
  "problemMatcher": {
@@ -149,7 +276,7 @@ Substitua o `tasks.json` atual por este (sem mais menus do VSCode, a CLI cuida d
149
276
  {
150
277
  "label": "Bimer: DEBUG + Run",
151
278
  "type": "shell",
152
- "command": "delphi debug",
279
+ "command": "bbuilder debug",
153
280
  "group": "build",
154
281
  "presentation": { "reveal": "always", "focus": true, "panel": "dedicated", "clear": true },
155
282
  "problemMatcher": {
@@ -164,7 +291,7 @@ Substitua o `tasks.json` atual por este (sem mais menus do VSCode, a CLI cuida d
164
291
  {
165
292
  "label": "Bimer: RELEASE",
166
293
  "type": "shell",
167
- "command": "delphi release",
294
+ "command": "bbuilder release",
168
295
  "group": "build",
169
296
  "presentation": { "reveal": "always", "focus": true, "panel": "dedicated", "clear": true },
170
297
  "problemMatcher": {
@@ -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
19
- .name('delphi')
91
+ attachHelpExamples(program
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.0",
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
- "delphi": "./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",