cistack 6.1.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,137 +1,276 @@
1
1
  {
2
+ "copy_button": {
3
+ "idle": "Copiar",
4
+ "success": "Copiado"
5
+ },
2
6
  "navigation": {
3
- "version": "VERSÃO",
4
- "status": "Pipelines_Sincronizados",
5
- "repository": "Repositório",
6
- "registry": "Registro",
7
- "core_manifest": "MANIFESTO_NÚCLEO",
8
- "docs": "Docs"
7
+ "repository": "GitHub",
8
+ "registry": "npm",
9
+ "reference": "Referência",
10
+ "version": "Versão",
11
+ "status": "Estável"
9
12
  },
10
13
  "hero": {
11
- "scan_identity": "IDENTIDADE_VARREDURA",
12
- "s1_label": "S_01 // MOTOR_INGESTÃO",
13
- "s1_title": "SUA STACK",
14
- "s2_label": "S_02 // SÍNTESE_PIPELINE",
15
- "s2_title": "SEU PIPELINE",
16
- "s3_label": "S_03 // VALIDAÇÃO_AÇÃO",
17
- "s3_title": "ORQUESTRADO",
18
- "description": "cistack realiza uma varredura profunda no seu repositório para gerar instantaneamente fluxos de trabalho do GitHub Actions prontos para produção em mais de 30 frameworks e 12 plataformas.",
14
+ "product_name": "cistack",
15
+ "tagline": "Gere pipelines CI/CD no GitHub Actions analisando o código que já tem.",
16
+ "intro": "O cistack analisa o seu projeto, deteta o stack e escreve workflows GitHub Actions prontos para produção: CI, implementação, Docker e releases. Pensado para repositórios reais, não demonstrações: lê ficheiros de lock, sinais de framework, configuração de release, workspaces monorepo, alojamento e metadados de ramos Git antes de gerar o YAML.",
19
17
  "npx_command": "npx cistack",
20
- "active_installs": "Instalações Ativas",
21
- "per_week": "/ semana",
22
- "realtime_synth": "SÍNTESE_TEMPO_REAL",
23
- "integrations": "Integrações",
24
- "stack_aware": "Compatível com Stack",
25
- "success_rate": "Taxa de Sucesso"
18
+ "weekly_downloads": "Transferências semanais",
19
+ "per_week": "última semana no npm",
20
+ "live_registry": "Em direto a partir do registo"
21
+ },
22
+ "preview": {
23
+ "title": "Pré-visualização",
24
+ "caption": "Saída CLI animada após analisar um projeto típico."
25
+ },
26
+ "why": {
27
+ "title": "Porquê o cistack",
28
+ "items": [
29
+ "Deteta automaticamente linguagens, frameworks, ferramentas de teste, fornecedores de alojamento e ferramentas de release",
30
+ "Utiliza o ramo Git predefinido do repositório quando disponível, em vez de assumir main",
31
+ "Suporta monorepos, workflows por pacote e comandos conscientes do gestor de pacotes",
32
+ "Gera configuração Dependabot alinhada com o ecossistema, incluindo Bun quando existe bun.lock",
33
+ "Funde de forma inteligente os workflows gerados com os ficheiros existentes sem sobrescrever à cega",
34
+ "Gera pipelines de implementação para Vercel, Netlify, Firebase, GitHub Pages, AWS, Azure, Heroku, Render e Railway",
35
+ "Inclui comandos integrados de auditoria e atualização de workflows",
36
+ "Suporta cistack.config.js tipado via index.d.ts",
37
+ "Com suíte de regressão automatizada (ramos, release, fusão inteligente, scripts monorepo, testes smoke da CLI)"
38
+ ]
39
+ },
40
+ "install": {
41
+ "title": "Instalação",
42
+ "quick_command": "Instalação rápida",
43
+ "node_note": "O cistack suporta Node.js 16+; o projeto é verificado continuamente em Node.js 18, 20 e 22 no GitHub Actions."
44
+ },
45
+ "cli": {
46
+ "section_title": "Utilização da CLI",
47
+ "items": [
48
+ {
49
+ "title": "Gerar workflows",
50
+ "paragraphs": [
51
+ "generate é o comando predefinido: funcionam npx cistack e npx cistack generate.",
52
+ "Opções comuns:"
53
+ ],
54
+ "snippets": [
55
+ "npx cistack",
56
+ "npx cistack generate",
57
+ "npx cistack generate --path /path/to/project",
58
+ "npx cistack generate --dry-run",
59
+ "npx cistack generate --explain",
60
+ "npx cistack generate --output .github/workflows",
61
+ "npx cistack generate --no-prompt"
62
+ ]
63
+ },
64
+ {
65
+ "title": "Auditar workflows existentes",
66
+ "paragraphs": [
67
+ "Verifica o diretório de workflows gerados (concorrência em falta, ações desatualizadas, versões antigas do Node, cache de dependências, etc.). Se definir outputDir em cistack.config.js, audit e upgrade também usam esse diretório."
68
+ ],
69
+ "snippets": ["npx cistack audit"]
70
+ },
71
+ {
72
+ "title": "Atualizar ações do workflow",
73
+ "paragraphs": [
74
+ "Atualiza as GitHub Actions conhecidas para as últimas versões estáveis suportadas."
75
+ ],
76
+ "snippets": ["npx cistack upgrade", "npx cistack upgrade --dry-run"]
77
+ },
78
+ {
79
+ "title": "Criar configuração inicial",
80
+ "paragraphs": [
81
+ "Escreve cistack.config.js com as chaves de substituição suportadas."
82
+ ],
83
+ "snippets": ["npx cistack init"]
84
+ }
85
+ ]
86
+ },
87
+ "generated": {
88
+ "section_title": "O que é gerado",
89
+ "items": [
90
+ {
91
+ "title": "pipeline.yml",
92
+ "paragraphs": [
93
+ "Por predefinição, o cistack gera um único workflow GitHub Actions que agrupa trabalhos de CI, implementação, Docker e release para acompanhar todo o pipeline num só ficheiro.",
94
+ "Inclui lint, test, build, E2E, implementação, Docker e release quando o stack permite, usa o ramo predefinido detetado ou configurado, mantém pré-visualizações e releases no mesmo ficheiro e documenta os segredos necessários no cabeçalho."
95
+ ],
96
+ "snippets": []
97
+ },
98
+ {
99
+ "title": "dependabot.yml",
100
+ "paragraphs": [
101
+ "O Dependabot permanece num ficheiro separado em .github/dependabot.yml, pois não é um workflow GitHub Actions.",
102
+ "Para pré-visualizações em PRs Dependabot, adicione também credenciais como segredos Dependabot, não só Actions. Na Vercel: VERCEL_TOKEN, VERCEL_ORG_ID e VERCEL_PROJECT_ID."
103
+ ],
104
+ "snippets": []
105
+ },
106
+ {
107
+ "title": "Modo dividido (split)",
108
+ "paragraphs": [
109
+ "Se preferir o esquema antigo multi-ficheiro, defina workflowLayout como split em cistack.config.js. Em modo split, o cistack volta a escrever ci.yml, deploy.yml, docker.yml e release.yml em separado."
110
+ ],
111
+ "snippets": [
112
+ "module.exports = {\n workflowLayout: 'split',\n};"
113
+ ]
114
+ }
115
+ ]
116
+ },
117
+ "detection": {
118
+ "section_title": "Deteção suportada",
119
+ "hosting_title": "Alojamento",
120
+ "hosting_tags": [
121
+ "Firebase",
122
+ "Vercel",
123
+ "Netlify",
124
+ "GitHub Pages",
125
+ "AWS",
126
+ "GCP App Engine",
127
+ "Azure",
128
+ "Heroku",
129
+ "Render",
130
+ "Railway",
131
+ "Docker"
132
+ ],
133
+ "frameworks_title": "Frameworks",
134
+ "frameworks_tags": [
135
+ "Next.js",
136
+ "Nuxt",
137
+ "SvelteKit",
138
+ "Remix",
139
+ "Astro",
140
+ "Vite",
141
+ "React",
142
+ "Vue",
143
+ "Angular",
144
+ "Svelte",
145
+ "Gatsby",
146
+ "Express",
147
+ "Fastify",
148
+ "NestJS",
149
+ "Hono",
150
+ "Koa",
151
+ "Django",
152
+ "Flask",
153
+ "FastAPI",
154
+ "Rails",
155
+ "Spring Boot",
156
+ "Laravel",
157
+ "Go",
158
+ "Rust"
159
+ ],
160
+ "testing_title": "Ferramentas de teste",
161
+ "testing_tags": [
162
+ "Jest",
163
+ "Vitest",
164
+ "Mocha",
165
+ "Cypress",
166
+ "Playwright",
167
+ "Pytest",
168
+ "RSpec",
169
+ "Go test",
170
+ "Cargo test",
171
+ "PHPUnit",
172
+ "Maven / JUnit",
173
+ "Storybook"
174
+ ]
175
+ },
176
+ "configuration": {
177
+ "section_title": "Configuração",
178
+ "intro": "Crie cistack.config.js quando quiser substituir a deteção.",
179
+ "example_caption": "Exemplo",
180
+ "keys_title": "Chaves de configuração de nível superior",
181
+ "keys": [
182
+ "nodeVersion",
183
+ "packageManager",
184
+ "hosting",
185
+ "frameworks",
186
+ "testing",
187
+ "branches",
188
+ "workflowLayout",
189
+ "cache",
190
+ "monorepo",
191
+ "release",
192
+ "secrets",
193
+ "outputDir"
194
+ ],
195
+ "branches_title": "Comportamento dos ramos",
196
+ "branches": [
197
+ "Se branches estiver definido na config, o cistack usa-o exatamente",
198
+ "Caso contrário, lê o ramo predefinido do repositório a partir dos metadados Git quando possível",
199
+ "Sem metadados Git, recua para valores seguros como main, master e develop consoante o tipo de workflow"
200
+ ],
201
+ "config_snippet": "/** @type {import('cistack').Config} */\nmodule.exports = {\n nodeVersion: '20',\n packageManager: 'pnpm',\n branches: ['main', 'staging'],\n workflowLayout: 'single',\n hosting: ['Vercel'],\n outputDir: '.github/workflows',\n cache: {\n npm: true,\n cargo: true,\n pip: true,\n },\n monorepo: {\n perPackage: true,\n },\n release: {\n tool: 'semantic-release',\n },\n};"
202
+ },
203
+ "secrets": {
204
+ "section_title": "Segredos",
205
+ "body": "Os workflows de implementação e release gerados documentam os segredos necessários no topo de cada ficheiro. Adicione-os no GitHub: Definições → Secrets and variables → Actions."
26
206
  },
27
- "docs": {
28
- "badge": "Especificação Técnica v",
29
- "title_part1": "Projetado para consistência.",
30
- "title_part2": "Gerado para velocidade.",
31
- "description": "cistack realiza uma varredura profunda no diretório do seu projeto para produzir YAML do GitHub Actions com qualidade de produção. Detecta sua linguagem, framework, ferramentas de teste e plataforma de hospedagem — depois escreve o melhor pipeline para sua stack.",
32
- "section1_id": "01 / 04",
33
- "section1_num": "01. Capacidades",
34
- "section1_title": "Análise e Detecção",
35
- "capabilities": {
36
- "analysis": { "label": "Análise profunda de código", "sub": "Lê package.json, arquivos lock, configs" },
37
- "detection": { "label": "Detecção inteligente", "sub": "Identifica mais de 30 frameworks e 12 linguagens" },
38
- "cache": { "label": "Suporte a Cache nativo", "sub": "Acelera pipelines para npm, pip, go, cargo e mais" },
39
- "preview": { "label": "Despuegues PR Preview", "sub": "Ambientes automáticos para Vercel e Netlify" },
40
- "audit": { "label": "Auditoria e Upgrade de Workflow", "sub": "Atualiza versões de ações e verifica as melhores práticas" },
41
- "hosting": { "label": "Auto-detecção de hospedagem", "sub": "AWS, Vercel, Firebase, Docker e mais" },
42
- "multi_workflow": { "label": "Saída multi-workflow", "sub": "ci.yml, deploy.yml, docker.yml, security.yml" },
43
- "security": { "label": "Segurança integrada", "sub": "Pontos de verificação CodeQL + auditoria de dependências" },
44
- "monorepo": { "label": "Compatível com Monorepo", "sub": "Turborepo, Nx, Lerna, pnpm workspaces" },
45
- "interactive": { "label": "Modo interativo", "sub": "Confirma configurações antes de escrever arquivos" },
46
- "zero_config": { "label": "Zero config", "sub": "Funciona imediatamente sem necessidade de configuração" }
47
- },
48
- "section2_num": "02. Ativação",
49
- "section2_title": "Instalação",
50
- "command_registry": "REGISTRO_COMANDOS",
51
- "commands": {
52
- "audit": "Verifica fluxos de trabalho por ações desatualizadas",
53
- "upgrade": "Atualiza todas as ações para as últimas versões",
54
- "init": "Cria um arquivo de configuração de sobreposição"
55
- },
56
- "recommended_npx": "Recomendado: Use npx para uma geração única.",
57
- "parameters_manifest": "MANIFESTO_PARÂMETROS",
58
- "flags": {
59
- "explain": "Mostra o raciocínio da stack detectada",
60
- "path": "Caminho do diretório alvo para varredura",
61
- "output": "Redefine o diretório de saída do fluxo de trabalho",
62
- "dry_run": "Simula a saída sem escrever",
63
- "no_prompt": "Ignora verificações de segurança interativas",
64
- "verbose": "Ativa o rastreamento stdout máximo",
65
- "force": "Ignora arquivos existentes e sobrescreve"
66
- },
67
- "detection_logic_title": "Lógica de Detecção",
68
- "detection_logic_desc": "Gatilhos de reconhecimento automático baseados em sinais do sistema de arquivos.",
69
- "signal_source": "Fonte do sinal:",
70
- "framework_coverage": "Cobertura Framework",
71
- "testing_tools": "Ferramentas de teste",
72
- "section3_num": "03. Artefatos",
73
- "section3_title": "Workflows Gerados",
74
- "workflows": {
75
- "ci": { "label": "Integração Contínua", "desc": "Executado em push/PR: Lint (ESLint, TS type-check), Test (matriz de versões Node), Build (produção), e E2E." },
76
- "deploy": { "label": "Despuegue Contínuo", "desc": "Acionado na main: Despuegue de plataforma com ambientes PR Preview automáticos para Vercel e Netlify." },
77
- "docker": { "label": "Build & Push Docker", "desc": "Acionado na main/tags: Build multi-plataforma via Docker Buildx, push GHCR, e cache GitHub Actions." },
78
- "security": { "label": "Auditoria de Segurança", "desc": "Executado em push/PR/cronogramas semanais: Análise de dependências e auditoria profunda CodeQL para a linguagem detectada." }
79
- },
80
- "security_requirement": "Requisito de Segurança",
81
- "encrypted_secrets": "Segredos Criptografados",
82
- "add_secrets_at": "Adicionar segredos em:",
83
- "section4_num": "04. Exemplos Estruturais",
84
- "section4_title": "Cenários de Stacks Padrão",
85
- "validated_output": "Saída Validada"
207
+ "quality": {
208
+ "section_title": "Desenvolvimento e qualidade",
209
+ "intro": "O projeto inclui uma suíte de regressão nas áreas historicamente mais frágeis:",
210
+ "items": [
211
+ "tratamento de substituições de configuração",
212
+ "deteção do ramo predefinido",
213
+ "seleção do ramo de implementação",
214
+ "ramo de produção Netlify",
215
+ "comportamento de fusão inteligente",
216
+ "procura de scripts de build por pacote em monorepo",
217
+ "deteção da configuração de release",
218
+ "geração do workflow de release",
219
+ "testes smoke da CLI em dry-run"
220
+ ],
221
+ "commands_title": "Executar verificações localmente",
222
+ "commands": [
223
+ "npm test",
224
+ "npm run test:smoke",
225
+ "node bin/ciflow.js audit --path .",
226
+ "node bin/ciflow.js upgrade --path . --dry-run"
227
+ ],
228
+ "repo_note": "Com o pacote publicado, o executável é cistack. No repositório cistack, o ponto de entrada local é bin/ciflow.js."
86
229
  },
87
230
  "footer": {
88
- "project_origin": "Origem_Projeto",
89
- "architected_by": "Arquitetado_Por",
90
- "status": "Status",
91
- "operational": "Todos os sistemas operacionais",
92
- "license": "Licença",
93
- "open_source": "Código Aberto",
94
- "footer_desc": "Geração automatizada de infraestrutura CI/CD para a web moderna. Construído com precisão para desenvolvedores que valorizam visibilidade e segurança em seus pipelines de deploy.",
95
- "global_install": "Instalação_Global",
96
- "copyright": "CISTACK ENGINE — TODOS OS PIPELINES REIFICADOS."
231
+ "license": "Licença MIT",
232
+ "tagline": "Geração de workflows CI/CD a partir do repositório que já tem.",
233
+ "architect_credit": "Criado por",
234
+ "architect_name": "Edwin Vakayil",
235
+ "copyright_suffix": "cistack. Todos os direitos reservados quando aplicável."
97
236
  },
98
237
  "install_toggle": {
99
238
  "recommended": "recomendado",
100
239
  "npm_global": "npm install -g",
101
240
  "recommended_badge": "Recomendado",
102
241
  "global_badge": "Global",
103
- "npx_desc": "Sempre obtém a última versão. Sem etapa de instalação.",
104
- "npm_desc": "Melhor para desenvolvedores em múltiplos repositórios."
242
+ "npx_desc": "Obtém sempre a versão mais recente. Sem instalação global.",
243
+ "npm_desc": "Ideal se usar o cistack em muitos repositórios."
105
244
  },
106
245
  "terminal": {
107
246
  "label": "TERMINAL",
108
247
  "mission": "MISSÃO_NÚCLEO // L_02",
109
- "project_scanned": "✔ Projeto escaneado",
110
- "stack_detected": "✔ Stack detectada",
111
- "detected_stack": "Stack Detectada",
248
+ "project_scanned": "✔ Projeto analisado",
249
+ "stack_detected": "✔ Stack detetado",
250
+ "detected_stack": "Stack detetado",
112
251
  "languages": "Linguagens:",
113
252
  "frameworks": "Frameworks:",
114
- "hosting": "Hospedagem:",
253
+ "hosting": "Alojamento:",
115
254
  "testing": "Testes:",
116
- "release_tool": "Ferramenta release:",
117
- "look_correct": "? Isso parece correto? Gerar pipeline com essas configurações? Sim",
118
- "generated_workflows": "✔ Gerados 3 fluxos de trabalho CI",
119
- "smart_merged": "↻ Mesclagem inteligente: ci.yml",
255
+ "release_tool": "Ferramenta de release:",
256
+ "look_correct": "Está correto? Gerar o pipeline com estes parâmetros? Sim",
257
+ "generated_workflows": "✔ Gerados 3 workflow(s) de CI",
258
+ "smart_merged": "↻ Fusão inteligente: ci.yml",
120
259
  "updated_on": "atualizado \"on\" de nível superior",
121
260
  "updated_concurrency": "atualizado \"concurrency\" de nível superior",
122
261
  "added_lint": "adicionado job \"lint\"",
123
- "updated_build": "job \"build\" → nome atualizado",
124
- "updated_needs": "job \"build\" → needs atualizado",
125
- "added_checkout": "job \"build\" → adicionada etapa \"Checkout code\"",
126
- "added_node": "job \"build\" → adicionada etapa \"Set up Node.js\"",
127
- "updated_step_build": "job \"build\" → etapa \"Build\" atualizada",
128
- "added_upload": "job \"build\" → adicionada etapa \"Upload build artifact\"",
262
+ "updated_build": "job \"build\" → atualizado \"name\"",
263
+ "updated_needs": "job \"build\" → atualizado \"needs\"",
264
+ "added_checkout": "job \"build\" → adicionado passo \"Checkout code\"",
265
+ "added_node": "job \"build\" → adicionado passo \"Set up Node.js\"",
266
+ "updated_step_build": "job \"build\" → atualizado passo \"Build\"",
267
+ "added_upload": "job \"build\" → adicionado passo \"Upload build artifact\"",
129
268
  "written_deploy": "Escrito: deploy.yml",
130
269
  "written_security": "Escrito: security.yml",
131
270
  "written_dependabot": "Escrito: .github/dependabot.yml",
132
- "done_msg": "Pronto! Seu pipeline de GitHub Actions está preparado.",
133
- "workflows_path": "Fluxos de trabalho → cistack/.github/workflows",
271
+ "done_msg": "Pronto! O seu pipeline GitHub Actions está preparado.",
272
+ "workflows_path": "Workflows → cistack/.github/workflows",
134
273
  "dependabot_path": "Dependabot → cistack/.github/dependabot.yml",
135
- "processing": "Processando Saída..."
274
+ "processing": "A processar saída…"
136
275
  }
137
276
  }
@@ -8,6 +8,7 @@
8
8
  "start": "next start",
9
9
  "lint": "eslint",
10
10
  "sync-i18n": "node scripts/sync-i18n.mjs",
11
+ "validate:i18n": "node scripts/validate-i18n.mjs",
11
12
  "typecheck": "tsc --noEmit --incremental false",
12
13
  "build:ci": "next build"
13
14
  },
@@ -0,0 +1,45 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ const DICTIONARY_DIR = path.join(__dirname, "../dictionaries");
7
+ const SOURCE = "en.json";
8
+
9
+ function keyPaths(value, prefix = "") {
10
+ if (value === null || typeof value !== "object") {
11
+ return [prefix || "(root)"];
12
+ }
13
+ if (Array.isArray(value)) {
14
+ if (value.length === 0) return [prefix + "[]"];
15
+ return value.flatMap((item, i) => keyPaths(item, `${prefix}[${i}]`));
16
+ }
17
+ const keys = Object.keys(value).sort();
18
+ if (keys.length === 0) return [prefix || "(empty)"];
19
+ return keys.flatMap((k) => keyPaths(value[k], prefix ? `${prefix}.${k}` : k));
20
+ }
21
+
22
+ const sourceRaw = fs.readFileSync(path.join(DICTIONARY_DIR, SOURCE), "utf8");
23
+ const en = JSON.parse(sourceRaw);
24
+ const enPaths = new Set(keyPaths(en).sort());
25
+
26
+ let failed = false;
27
+ for (const file of fs.readdirSync(DICTIONARY_DIR)) {
28
+ if (!file.endsWith(".json") || file === SOURCE) continue;
29
+ const data = JSON.parse(fs.readFileSync(path.join(DICTIONARY_DIR, file), "utf8"));
30
+ const paths = new Set(keyPaths(data).sort());
31
+ const missing = [...enPaths].filter((p) => !paths.has(p));
32
+ const extra = [...paths].filter((p) => !enPaths.has(p));
33
+ if (missing.length || extra.length) {
34
+ console.error(`\n${file}:`);
35
+ if (missing.length) console.error(" missing:", missing.slice(0, 8).join(", "), missing.length > 8 ? `… +${missing.length - 8}` : "");
36
+ if (extra.length) console.error(" extra:", extra.slice(0, 8).join(", "), extra.length > 8 ? `… +${extra.length - 8}` : "");
37
+ failed = true;
38
+ }
39
+ }
40
+
41
+ if (failed) {
42
+ console.error("\nvalidate-i18n: locale key paths must match en.json\n");
43
+ process.exit(1);
44
+ }
45
+ console.log("validate-i18n: all locales match en.json key paths");
package/src/index.js CHANGED
@@ -230,34 +230,33 @@ class CIFlow {
230
230
  _printSummary(config, releaseInfo, envVars, monorepoPackages) {
231
231
  const { hosting, frameworks, languages, testing } = config;
232
232
  const line = (label, value, reasons = []) => {
233
- console.log(` ${chalk.dim(label.padEnd(20))} ${chalk.cyan(value || chalk.italic('none detected'))}`);
233
+ console.log(` ${chalk.dim(label.padEnd(20))} ${chalk.cyan(value || chalk.italic('None'))}`);
234
234
  if (this.explain && reasons && reasons.length > 0) {
235
235
  for (const reason of reasons) {
236
- console.log(` ${chalk.dim('')} ${chalk.italic.gray(reason)}`);
236
+ console.log(` ${chalk.dim('-')} ${chalk.gray(reason)}`);
237
237
  }
238
238
  }
239
239
  };
240
240
 
241
- console.log('\n' + chalk.bold(' 📊 Detected Stack'));
242
- console.log(chalk.dim(' ' + '─'.repeat(48)));
243
-
244
- line('Languages:', languages.map((l) => l.name).join(', '), languages[0] && languages[0].reasons);
245
- line('Frameworks:', frameworks.map((f) => f.name).join(', '), frameworks[0] && frameworks[0].reasons);
246
- line('Hosting:', hosting.map((h) => h.name).join(', ') || 'none', hosting[0] && hosting[0].reasons);
247
- line('Testing:', testing.map((t) => t.name).join(', ') || 'none', testing[0] && testing[0].reasons);
248
- line('Release tool:', releaseInfo ? releaseInfo.tool : 'none', releaseInfo && releaseInfo.reasons);
241
+ console.log('\n' + chalk.bold(' Stack detection summary'));
242
+
243
+ line('Languages:', languages.map((l) => l.name).join(', '), languages[0] && languages[0].reasons);
244
+ line('Frameworks:', frameworks.map((f) => f.name).join(', '), frameworks[0] && frameworks[0].reasons);
245
+ line('Hosting:', hosting.map((h) => h.name).join(', ') || 'None', hosting[0] && hosting[0].reasons);
246
+ line('Testing:', testing.map((t) => t.name).join(', ') || 'None', testing[0] && testing[0].reasons);
247
+ line('Release tool:', releaseInfo ? releaseInfo.tool : 'None', releaseInfo && releaseInfo.reasons);
249
248
 
250
249
  if (monorepoPackages.length > 0) {
251
- line('Monorepo pkgs:', monorepoPackages.map((p) => p.name).join(', '));
250
+ line('Monorepo packages:', monorepoPackages.map((p) => p.name).join(', '));
252
251
  }
253
252
 
254
253
  if (envVars.sourceFile) {
255
- line('Env file:', envVars.sourceFile);
254
+ line('Environment file:', envVars.sourceFile);
256
255
  if (envVars.secrets.length > 0) {
257
256
  line(' Secrets:', envVars.secrets.join(', '));
258
257
  }
259
258
  if (envVars.public.length > 0) {
260
- line(' Public vars:', envVars.public.join(', '));
259
+ line(' Public variables:', envVars.public.join(', '));
261
260
  }
262
261
  }
263
262