mega-brain-ai 1.2.2 → 1.2.4

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.
@@ -13,7 +13,7 @@
13
13
  * 6. Post-install summary
14
14
  */
15
15
 
16
- import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync } from 'fs';
16
+ import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync, readdirSync } from 'fs';
17
17
  import { resolve, dirname, join } from 'path';
18
18
  import { fileURLToPath } from 'url';
19
19
  import { execSync } from 'child_process';
@@ -261,64 +261,65 @@ async function selectEdition() {
261
261
  * This installer runs on other people's machines — we never risk data loss.
262
262
  */
263
263
  async function fetchPremiumContent(targetDir, token, spinner) {
264
- const premiumRepo = 'https://github.com/thiagofinch/mega-brain-premium.git';
265
264
  const tempDir = join(targetDir, '.layer-sync', 'premium-fetch');
266
265
 
267
- // Safety: ensure tempDir is strictly INSIDE targetDir (prevent path traversal)
266
+ // Safety: ensure tempDir is strictly INSIDE targetDir
268
267
  const resolvedTemp = resolve(tempDir);
269
268
  const resolvedTarget = resolve(targetDir);
270
269
  if (!resolvedTemp.startsWith(resolvedTarget + '/') && !resolvedTemp.startsWith(resolvedTarget + '\\')) {
271
270
  throw new Error('Erro interno: caminho de download fora do diretório de instalação.');
272
271
  }
273
272
 
274
- if (!existsSync(dirname(tempDir))) {
275
- mkdirSync(dirname(tempDir), { recursive: true });
276
- }
273
+ mkdirSync(dirname(tempDir), { recursive: true });
274
+
275
+ // Clone with token in URL — .layer-sync/ is in .gitignore so token stays local
276
+ const authUrl = `https://x-access-token:${token}@github.com/thiagofinch/mega-brain-premium.git`;
277
277
 
278
- // If a previous clone exists, reuse it (no delete + re-clone)
279
278
  if (!existsSync(join(tempDir, '.git'))) {
280
279
  spinner.text = 'Clonando repositório premium...';
281
280
 
282
- // Use http.extraheader so the token is NEVER written to .git/config.
283
- // The -c flag is a runtime-only override — not persisted to disk.
284
- const base64Auth = Buffer.from(`x-access-token:${token}`).toString('base64');
285
-
286
- execSync(
287
- `git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${base64Auth}" clone --depth 1 "${premiumRepo}" "${tempDir}"`,
288
- {
281
+ try {
282
+ execSync(`git clone --depth 1 "${authUrl}" "${tempDir}"`, {
289
283
  stdio: 'pipe',
290
284
  encoding: 'utf-8',
291
285
  timeout: 120000,
292
- }
293
- );
286
+ });
287
+ } catch (cloneErr) {
288
+ throw new Error(`Git clone falhou: ${cloneErr.message.split('\n')[0]}`);
289
+ }
294
290
  } else {
295
291
  spinner.text = 'Download anterior encontrado, reutilizando...';
296
292
  }
297
293
 
294
+ // Verify clone has content
295
+ if (!existsSync(tempDir) || readdirSync(tempDir).length <= 1) {
296
+ throw new Error('Repositório premium clonado mas vazio.');
297
+ }
298
+
298
299
  spinner.text = 'Integrando conteúdo premium na estrutura...';
299
300
 
300
301
  // Copy premium content over the shell (merge, not replace)
301
- const excludeDirs = ['.git', 'node_modules', 'bin', '.layer-sync'];
302
- const normalizedTemp = resolve(tempDir);
303
- cpSync(tempDir, targetDir, {
304
- recursive: true,
305
- force: true,
306
- filter: (src) => {
307
- const rel = resolve(src).slice(normalizedTemp.length);
308
- for (const exclude of excludeDirs) {
309
- if (rel.includes(`/${exclude}/`) || rel.includes(`\\${exclude}\\`)
310
- || rel.endsWith(`/${exclude}`) || rel.endsWith(`\\${exclude}`)) {
311
- return false;
312
- }
313
- }
314
- return true;
315
- },
316
- });
317
-
318
- // NOTE: .layer-sync/ is intentionally NOT deleted.
319
- // It is listed in .gitignore and contains no sensitive data
320
- // (token was never written to disk thanks to http.extraheader).
321
- // We NEVER use recursive delete operations on user machines.
302
+ const premiumExclude = ['.git', 'node_modules', 'bin', '.layer-sync'];
303
+ const premiumEntries = readdirSync(tempDir, { withFileTypes: true });
304
+ let copied = 0;
305
+
306
+ for (const entry of premiumEntries) {
307
+ if (premiumExclude.includes(entry.name)) continue;
308
+
309
+ const srcPath = join(tempDir, entry.name);
310
+ const destPath = join(targetDir, entry.name);
311
+
312
+ if (entry.isDirectory()) {
313
+ cpSync(srcPath, destPath, { recursive: true, force: true });
314
+ } else {
315
+ cpSync(srcPath, destPath, { force: true });
316
+ }
317
+ copied++;
318
+ }
319
+
320
+ if (copied === 0) {
321
+ throw new Error('Nenhum conteúdo premium copiado.');
322
+ }
322
323
  }
323
324
 
324
325
  /**
@@ -369,30 +370,38 @@ function showPostInstallCommunity() {
369
370
  }
370
371
 
371
372
  function copyTemplateFiles(source, target, excludeDirs) {
372
- // Normalize source path for reliable relative path computation
373
- const normalizedSource = resolve(source);
373
+ if (!existsSync(source)) {
374
+ throw new Error(`Template não encontrado: ${source}`);
375
+ }
374
376
 
375
- try {
376
- cpSync(source, target, {
377
- recursive: true,
378
- filter: (src) => {
379
- // Get the path RELATIVE to the source root.
380
- // This is critical because when running via npx, the absolute path
381
- // contains "node_modules/" which would match the exclude filter
382
- // and block ALL files from being copied.
383
- const relativePath = resolve(src).slice(normalizedSource.length);
384
-
385
- for (const exclude of excludeDirs) {
386
- if (relativePath.includes(`/${exclude}/`) || relativePath.includes(`\\${exclude}\\`)
387
- || relativePath.endsWith(`/${exclude}`) || relativePath.endsWith(`\\${exclude}`)) {
388
- return false;
389
- }
390
- }
391
- return true;
392
- },
393
- });
394
- } catch (err) {
395
- throw new Error(`Erro ao copiar arquivos: ${err.message}. Certifique-se de usar Node.js 18+.`);
377
+ const entries = readdirSync(source, { withFileTypes: true });
378
+
379
+ if (entries.length === 0) {
380
+ throw new Error(`Template vazio: ${source}`);
381
+ }
382
+
383
+ let copied = 0;
384
+ for (const entry of entries) {
385
+ if (excludeDirs.includes(entry.name)) continue;
386
+
387
+ const srcPath = join(source, entry.name);
388
+ const destPath = join(target, entry.name);
389
+
390
+ try {
391
+ if (entry.isDirectory()) {
392
+ cpSync(srcPath, destPath, { recursive: true, force: true });
393
+ } else {
394
+ mkdirSync(dirname(destPath), { recursive: true });
395
+ cpSync(srcPath, destPath, { force: true });
396
+ }
397
+ copied++;
398
+ } catch (err) {
399
+ console.error(` Aviso: falha ao copiar ${entry.name}: ${err.message}`);
400
+ }
401
+ }
402
+
403
+ if (copied === 0) {
404
+ throw new Error(`Nenhum arquivo copiado. Source: ${source} (${entries.length} entries, ${excludeDirs.length} excluded)`);
396
405
  }
397
406
  }
398
407
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mega-brain-ai",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "AI Knowledge Management System - Transform expert materials into actionable playbooks",
5
5
  "type": "module",
6
6
  "bin": {