trackfw 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trackfw",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Governed software delivery framework: ADR → REQ → ROADMAP → kanban",
5
5
  "keywords": [
6
6
  "cli",
@@ -7,7 +7,6 @@ const fs = require('fs');
7
7
  const path = require('path');
8
8
  const os = require('os');
9
9
  const child_process = require('child_process');
10
- const zlib = require('zlib');
11
10
 
12
11
  // ---------------------------------------------------------------------------
13
12
  // Mapeamento de plataforma e arquitetura
@@ -28,9 +27,7 @@ const platform = PLATFORM_MAP[process.platform];
28
27
  const arch = ARCH_MAP[process.arch];
29
28
 
30
29
  if (!platform || !arch) {
31
- console.warn(
32
- 'trackfw: plataforma não suportada, pulando instalação do binário'
33
- );
30
+ console.warn('trackfw: plataforma não suportada, pulando instalação do binário');
34
31
  process.exit(0);
35
32
  }
36
33
 
@@ -58,7 +55,6 @@ const binDir = path.join(__dirname, '..', 'bin');
58
55
  const binName = isWindows ? 'trackfw-bin.exe' : 'trackfw-bin';
59
56
  const binDest = path.join(binDir, binName);
60
57
 
61
- // Garantir que o diretório bin existe
62
58
  if (!fs.existsSync(binDir)) {
63
59
  fs.mkdirSync(binDir, { recursive: true });
64
60
  }
@@ -67,12 +63,6 @@ if (!fs.existsSync(binDir)) {
67
63
  // Helpers
68
64
  // ---------------------------------------------------------------------------
69
65
 
70
- /**
71
- * Baixa uma URL para um arquivo local, seguindo redirects 301/302.
72
- * @param {string} url
73
- * @param {string} destFile
74
- * @returns {Promise<void>}
75
- */
76
66
  function download(url, destFile) {
77
67
  return new Promise((resolve, reject) => {
78
68
  const file = fs.createWriteStream(destFile);
@@ -81,23 +71,30 @@ function download(url, destFile) {
81
71
  https
82
72
  .get(currentUrl, (res) => {
83
73
  if (res.statusCode === 301 || res.statusCode === 302) {
84
- // Seguir redirect
85
74
  const location = res.headers['location'];
86
75
  if (!location) {
87
76
  reject(new Error('Redirect sem Location header'));
88
77
  return;
89
78
  }
90
- res.resume(); // descartar body
91
- get(location);
79
+ res.resume();
80
+ // reabrir o arquivo para a requisição seguinte não acumular lixo
81
+ file.close(() => {
82
+ const file2 = fs.createWriteStream(destFile);
83
+ file2.on('finish', () => file2.close(resolve));
84
+ file2.on('error', (err) => { fs.unlink(destFile, () => {}); reject(err); });
85
+ https.get(location, (res2) => {
86
+ if (res2.statusCode !== 200) {
87
+ reject(new Error(`Falha ao baixar ${location}: HTTP ${res2.statusCode}`));
88
+ return;
89
+ }
90
+ res2.pipe(file2);
91
+ }).on('error', (err) => { fs.unlink(destFile, () => {}); reject(err); });
92
+ });
92
93
  return;
93
94
  }
94
95
 
95
96
  if (res.statusCode !== 200) {
96
- reject(
97
- new Error(
98
- `Falha ao baixar ${currentUrl}: HTTP ${res.statusCode}`
99
- )
100
- );
97
+ reject(new Error(`Falha ao baixar ${currentUrl}: HTTP ${res.statusCode}`));
101
98
  return;
102
99
  }
103
100
 
@@ -118,42 +115,45 @@ function download(url, destFile) {
118
115
  });
119
116
  }
120
117
 
121
- /**
122
- * Extrai um arquivo .tar.gz ou .zip para um diretório.
123
- * @param {string} archiveFile caminho do arquivo baixado
124
- * @param {string} destDir diretório de destino da extração
125
- */
126
118
  function extract(archiveFile, destDir) {
127
119
  if (isWindows) {
128
120
  child_process.execSync(
129
- `powershell -command "Expand-Archive -Path '${archiveFile}' -DestinationPath '${destDir}' -Force"`,
130
- { stdio: 'inherit' }
121
+ `powershell -NoProfile -Command "Expand-Archive -LiteralPath '${archiveFile}' -DestinationPath '${destDir}' -Force"`,
122
+ { stdio: 'pipe' }
131
123
  );
132
124
  } else {
133
125
  child_process.execSync(
134
126
  `tar -xzf "${archiveFile}" -C "${destDir}"`,
135
- { stdio: 'inherit' }
127
+ { stdio: 'pipe' }
136
128
  );
137
129
  }
138
130
  }
139
131
 
140
- /**
141
- * Remove um arquivo ou diretório silenciosamente.
142
- * @param {string} target
143
- */
132
+ // Busca recursiva pelo binário em qualquer subdiretório após extração
133
+ function findBinary(dir, name) {
134
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
135
+ for (const entry of entries) {
136
+ const full = path.join(dir, entry.name);
137
+ if (entry.isDirectory()) {
138
+ const found = findBinary(full, name);
139
+ if (found) return found;
140
+ } else if (entry.name === name) {
141
+ return full;
142
+ }
143
+ }
144
+ return null;
145
+ }
146
+
144
147
  function cleanup(target) {
145
148
  try {
146
149
  if (!fs.existsSync(target)) return;
147
150
  const stat = fs.statSync(target);
148
151
  if (stat.isDirectory()) {
149
- // Node 14 não tem rm({recursive}) confiável em todas as versões; usar rmdir
150
- fs.rmdirSync(target, { recursive: true });
152
+ fs.rmSync(target, { recursive: true, force: true });
151
153
  } else {
152
154
  fs.unlinkSync(target);
153
155
  }
154
- } catch (_) {
155
- // Limpeza é best-effort — não falhar por causa disso
156
- }
156
+ } catch (_) {}
157
157
  }
158
158
 
159
159
  // ---------------------------------------------------------------------------
@@ -170,16 +170,29 @@ async function main() {
170
170
 
171
171
  await download(downloadUrl, tmpFile);
172
172
 
173
+ const fileSize = fs.statSync(tmpFile).size;
174
+ if (fileSize < 1000) {
175
+ throw new Error(`Arquivo baixado suspeito (${fileSize} bytes) — verifique a conexão ou se a versão v${version} foi publicada no GitHub`);
176
+ }
177
+
173
178
  console.log('trackfw: extraindo arquivo...');
174
179
  extract(tmpFile, tmpDir);
175
180
 
176
- // GoReleaser extrai o binário com o nome original ("trackfw" / "trackfw.exe")
177
181
  const extractedBinName = isWindows ? 'trackfw.exe' : 'trackfw';
178
- const extractedBin = path.join(tmpDir, extractedBinName);
179
-
180
- if (!fs.existsSync(extractedBin)) {
182
+ const extractedBin = findBinary(tmpDir, extractedBinName);
183
+
184
+ if (!extractedBin) {
185
+ const files = [];
186
+ function listAll(d) {
187
+ for (const e of fs.readdirSync(d, { withFileTypes: true })) {
188
+ const p = path.join(d, e.name);
189
+ files.push(p);
190
+ if (e.isDirectory()) listAll(p);
191
+ }
192
+ }
193
+ listAll(tmpDir);
181
194
  throw new Error(
182
- `Binário não encontrado após extração: ${extractedBin}`
195
+ `Binário "${extractedBinName}" não encontrado após extração.\nArquivos encontrados:\n${files.join('\n')}`
183
196
  );
184
197
  }
185
198
 
@@ -189,7 +202,7 @@ async function main() {
189
202
  fs.chmodSync(binDest, 0o755);
190
203
  }
191
204
 
192
- console.log('trackfw: binário instalado com sucesso');
205
+ console.log('trackfw: binário instalado com sucesso em ' + binDest);
193
206
  } finally {
194
207
  cleanup(tmpFile);
195
208
  cleanup(tmpDir);
@@ -197,7 +210,12 @@ async function main() {
197
210
  }
198
211
 
199
212
  main().catch((err) => {
200
- console.error('trackfw: erro ao instalar binário:', err.message);
201
- // Sair com 0 para não bloquear CIs que não precisam do binário pré-instalado
213
+ console.error('\ntrackfw: ERRO ao instalar binário:');
214
+ console.error(' ' + err.message);
215
+ console.error('\nAlternativas de instalação:');
216
+ console.error(' curl -sSfL https://github.com/kgsaran/trackfw/releases/latest/download/install.sh | sh');
217
+ console.error(' brew install kgsaran/tap/trackfw (macOS/Linux)');
218
+ console.error(' go install github.com/kgsaran/trackfw/cmd/trackfw@latest\n');
219
+ // Sair com 0 para não bloquear npm install em CIs sem acesso ao GitHub
202
220
  process.exit(0);
203
221
  });