@brunoluizdesiqueira/bbuilder-cli 1.0.1 → 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/README.md CHANGED
@@ -23,6 +23,122 @@ 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
+ ### Troubleshooting do publish automático
104
+
105
+ Se a PR de release for mergeada, a versão subir para o `package.json`, mas o publish no npm falhar com erro parecido com:
106
+
107
+ ```text
108
+ E404 Not Found - PUT https://registry.npmjs.org/@brunoluizdesiqueira%2fbbuilder-cli - Not found
109
+ ```
110
+
111
+ verifique estes pontos:
112
+
113
+ 1. o Trusted Publisher do pacote está configurado para:
114
+ - owner/user: `brunoluizdesiqueira`
115
+ - repository: `b-cli`
116
+ - workflow: `release.yml`
117
+ 2. o repositório GitHub é público
118
+ 3. o workflow `Release` tem `permissions.id-token: write`
119
+ 4. o workflow roda com Node e npm atuais
120
+
121
+ O ajuste que resolveu esse cenário neste projeto foi:
122
+
123
+ - usar `actions/setup-node@v5`
124
+ - executar o workflow com Node `24`
125
+ - atualizar o npm antes do publish
126
+ - definir no `package.json`:
127
+
128
+ ```json
129
+ "publishConfig": {
130
+ "access": "public",
131
+ "provenance": true
132
+ }
133
+ ```
134
+
135
+ ## CI/CD
136
+
137
+ O repositório agora está preparado com GitHub Actions:
138
+
139
+ - `CI`: roda em `push` e `pull_request`, executando `npm ci`, `tsc`, `build` e `npm pack --dry-run`
140
+ - `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
141
+
26
142
  Ou use direto sem instalar globalmente:
27
143
  ```bash
28
144
  npx ts-node src/index.ts build
@@ -57,12 +173,15 @@ bbuilder release --project Bimer --version 11.3.1
57
173
  ```bash
58
174
  bbuilder project list # lista projetos configurados
59
175
  bbuilder project add # adiciona novo projeto (interativo)
176
+ bbuilder project remove # remove projeto (interativo ou por --name)
60
177
  ```
61
178
 
62
179
  ### Configuração do ambiente
63
180
  ```bash
64
181
  bbuilder config init # assistente para criar bbuilder.config.json
65
182
  bbuilder config show # exibe configuração atual
183
+ bbuilder config validate # valida a estrutura do arquivo de configuração
184
+ bbuilder doctor # diagnostica ambiente, config e paths
66
185
  ```
67
186
 
68
187
  ---
@@ -110,6 +229,46 @@ Crie com `bbuilder config init`, ou manualmente:
110
229
 
111
230
  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
231
 
232
+ ### Como usar configs locais
233
+
234
+ O pacote é instalado normalmente, e a configuração é informada na execução, não na instalação.
235
+
236
+ Instalação global:
237
+
238
+ ```bash
239
+ npm install -g @brunoluizdesiqueira/bbuilder-cli
240
+ ```
241
+
242
+ Usando um arquivo de config local explícito:
243
+
244
+ ```bash
245
+ bbuilder --config C:\configs\bbuilder.config.json build
246
+ ```
247
+
248
+ Usando variável de ambiente no Windows CMD:
249
+
250
+ ```bat
251
+ set BBUILDER_CONFIG=C:\configs\bbuilder.config.json
252
+ bbuilder build
253
+ ```
254
+
255
+ Usando variável de ambiente no PowerShell:
256
+
257
+ ```powershell
258
+ $env:BBUILDER_CONFIG="C:\configs\bbuilder.config.json"
259
+ bbuilder build
260
+ ```
261
+
262
+ Usando config local no diretório atual:
263
+
264
+ Se existir um `bbuilder.config.json` na pasta onde o comando é executado, a CLI usa esse arquivo automaticamente.
265
+
266
+ Para verificar qual arquivo está sendo usado:
267
+
268
+ ```bash
269
+ bbuilder config show
270
+ ```
271
+
113
272
  Exemplos:
114
273
 
115
274
  ```bash
@@ -188,15 +347,41 @@ E nos keybindings, nada muda — os atalhos continuam os mesmos.
188
347
 
189
348
  ```
190
349
  bbuilder-cli/
350
+ ├── .changeset/
351
+ │ ├── config.json
352
+ │ └── *.md
353
+ ├── .github/
354
+ │ └── workflows/
355
+ │ ├── ci.yml
356
+ │ └── release.yml
191
357
  ├── src/
192
358
  │ ├── build/
359
+ │ │ ├── compiler.ts
360
+ │ │ ├── execute.ts
361
+ │ │ ├── project.ts
362
+ │ │ └── resources.ts
193
363
  │ ├── cli/
364
+ │ │ └── program.ts
194
365
  │ ├── config/
366
+ │ │ ├── config.ts
367
+ │ │ └── validate.ts
368
+ │ ├── diagnostics/
369
+ │ │ └── doctor.ts
195
370
  │ ├── ui/
371
+ │ │ ├── output.ts
372
+ │ │ └── prompts.ts
196
373
  │ ├── index.ts
197
374
  │ └── types.ts
375
+ ├── files/
376
+ │ ├── build_local.bat
377
+ │ ├── tasks.json
378
+ │ └── ...
379
+ ├── bbuilder.config.json
198
380
  ├── package.json
381
+ ├── package-lock.json
199
382
  ├── tsconfig.json
383
+ ├── .gitignore
384
+ ├── LICENSE
200
385
  └── README.md
201
386
  ```
202
387
 
@@ -70,7 +70,10 @@ function buildCompilerFlags(buildType) {
70
70
  }
71
71
  }
72
72
  function buildDependencies(opts) {
73
- return opts.dependencyPaths.map(p => `"${p}"`).join(';');
73
+ // execa passes each compiler switch as a single argv entry, so we should
74
+ // not embed quotes inside the semicolon-separated list. Doing that can make
75
+ // dcc64 fail to resolve paths such as the Delphi runtime library.
76
+ return opts.dependencyPaths.join(';');
74
77
  }
75
78
  async function runCgrc(opts, projectName) {
76
79
  const tempDir = path.join(os.tmpdir(), `BimerBuild_${projectName}`);
@@ -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,129 @@
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
+ const delphiRuntimePath = path.win32.join(config.delphiDir, 'lib', 'Win64', 'release');
66
+ checks.push(checkFile('Arquivo de configuração em uso', resolvedConfigPath));
67
+ checks.push(checkPath('repoBase', config.repoBase));
68
+ checks.push(checkPath('delphiDir', config.delphiDir));
69
+ checks.push(checkPath('Delphi runtime Win64', delphiRuntimePath));
70
+ checks.push(checkPath('libRoot', config.libRoot));
71
+ checks.push(checkPath('libErp', config.libErp));
72
+ checks.push(checkPath('libAlterdata', config.libAlterdata));
73
+ checks.push(checkFile('cgrc.exe', cgrcPath));
74
+ checks.push(checkFile('dcc64.exe', dcc64Path));
75
+ const projectEntries = Object.entries(config.projects);
76
+ checks.push({
77
+ label: 'Projetos configurados',
78
+ ok: projectEntries.length > 0,
79
+ detail: `${projectEntries.length} projeto(s)`,
80
+ });
81
+ checks.push({
82
+ label: 'dependencyPaths configurados',
83
+ ok: Array.isArray(config.dependencyPaths) && config.dependencyPaths.length > 0,
84
+ detail: `${config.dependencyPaths.length} path(s)`,
85
+ });
86
+ checks.push({
87
+ label: 'Delphi runtime presente em dependencyPaths',
88
+ ok: config.dependencyPaths.includes(delphiRuntimePath),
89
+ detail: delphiRuntimePath,
90
+ });
91
+ console.log('');
92
+ console.log(chalk_1.default.cyan(' Diagnóstico do Ambiente'));
93
+ console.log(chalk_1.default.blue(' ───────────────────────'));
94
+ console.log(chalk_1.default.gray(` Config: ${resolvedConfigPath}`));
95
+ console.log('');
96
+ checks.forEach(printCheck);
97
+ if (projectEntries.length > 0) {
98
+ console.log('');
99
+ console.log(chalk_1.default.cyan(' Projetos'));
100
+ console.log(chalk_1.default.blue(' ────────'));
101
+ projectEntries.forEach(([name, projectPath]) => {
102
+ const fullPath = path.win32.join(config.repoBase, projectPath);
103
+ const dprojPath = `${fullPath}.dproj`;
104
+ const exists = fs.existsSync(dprojPath);
105
+ const status = exists ? chalk_1.default.green('OK') : chalk_1.default.red('FAIL');
106
+ console.log(` ${status.padEnd(6)} ${chalk_1.default.white(name)} ${chalk_1.default.gray(`→ ${dprojPath}`)}`);
107
+ });
108
+ }
109
+ if (config.dependencyPaths.length > 0) {
110
+ console.log('');
111
+ console.log(chalk_1.default.cyan(' Dependências'));
112
+ console.log(chalk_1.default.blue(' ────────────'));
113
+ config.dependencyPaths.forEach(depPath => {
114
+ const exists = fs.existsSync(depPath);
115
+ const status = exists ? chalk_1.default.green('OK') : chalk_1.default.yellow('WARN');
116
+ console.log(` ${status.padEnd(6)} ${chalk_1.default.gray(depPath)}`);
117
+ });
118
+ }
119
+ const failed = checks.filter(check => !check.ok).length;
120
+ console.log('');
121
+ if (failed === 0) {
122
+ console.log(chalk_1.default.green(' Ambiente básico validado com sucesso.'));
123
+ }
124
+ else {
125
+ console.log(chalk_1.default.yellow(` Diagnóstico concluído com ${failed} problema(s) principal(is).`));
126
+ process.exitCode = 1;
127
+ }
128
+ console.log('');
129
+ }
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.3",
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",