aiteam-x 0.8.1 → 0.9.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.
- package/package.json +1 -1
- package/scripts/cli.mjs +101 -45
package/package.json
CHANGED
package/scripts/cli.mjs
CHANGED
|
@@ -3,83 +3,140 @@
|
|
|
3
3
|
* AITEAM-X CLI — Instalação simplificada via npx
|
|
4
4
|
*
|
|
5
5
|
* Uso:
|
|
6
|
-
* npx aiteam-x@latest →
|
|
6
|
+
* npx aiteam-x@latest → instala no diretório atual
|
|
7
7
|
* npx aiteam-x@latest meu-projeto → cria em meu-projeto/
|
|
8
8
|
*
|
|
9
|
-
* Fluxo: degit (baixa template) → npm install → npm run setup → npm run dev
|
|
9
|
+
* Fluxo: degit (baixa template) → mescla arquivos → npm install → npm run setup → npm run dev
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { execSync, spawn } from "child_process";
|
|
13
13
|
import fs from "fs";
|
|
14
14
|
import path from "path";
|
|
15
|
+
import os from "os";
|
|
16
|
+
import readline from "readline";
|
|
15
17
|
import { fileURLToPath } from "url";
|
|
16
18
|
|
|
17
19
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
20
|
const REPO = "INOSX/AITeam";
|
|
19
21
|
|
|
20
22
|
const C = {
|
|
21
|
-
green:
|
|
23
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
22
24
|
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
23
|
-
cyan:
|
|
24
|
-
bold:
|
|
25
|
-
dim:
|
|
25
|
+
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
26
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
27
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
function isDirEmpty(dir) {
|
|
29
31
|
if (!fs.existsSync(dir)) return true;
|
|
30
|
-
|
|
31
|
-
return entries.length === 0;
|
|
32
|
+
return fs.readdirSync(dir).length === 0;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
function
|
|
35
|
+
function detectBmad(dir) {
|
|
36
|
+
return (
|
|
37
|
+
fs.existsSync(path.join(dir, "bmad")) ||
|
|
38
|
+
fs.existsSync(path.join(dir, ".cursor", "rules", "bmad"))
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function ask(question) {
|
|
43
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
44
|
+
return new Promise((resolve) => {
|
|
45
|
+
rl.question(question, (answer) => {
|
|
46
|
+
rl.close();
|
|
47
|
+
resolve(answer.trim().toLowerCase());
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function mergePackageJson(templatePath, targetPath) {
|
|
53
|
+
const tpl = JSON.parse(fs.readFileSync(templatePath, "utf-8"));
|
|
54
|
+
const cur = JSON.parse(fs.readFileSync(targetPath, "utf-8"));
|
|
55
|
+
const merged = {
|
|
56
|
+
...cur,
|
|
57
|
+
dependencies: { ...(tpl.dependencies ?? {}), ...(cur.dependencies ?? {}) },
|
|
58
|
+
devDependencies: { ...(tpl.devDependencies ?? {}), ...(cur.devDependencies ?? {}) },
|
|
59
|
+
scripts: { ...(tpl.scripts ?? {}), ...(cur.scripts ?? {}) },
|
|
60
|
+
};
|
|
61
|
+
if (tpl.bin && !cur.bin) merged.bin = tpl.bin;
|
|
62
|
+
fs.writeFileSync(targetPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
63
|
+
console.log(C.dim(" package.json mesclado (deps + scripts adicionados)"));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function copyMerge(src, dest) {
|
|
67
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
68
|
+
for (const entry of entries) {
|
|
69
|
+
if (entry.name === ".git") continue;
|
|
70
|
+
if (entry.name === "node_modules") continue;
|
|
71
|
+
const srcPath = path.join(src, entry.name);
|
|
72
|
+
const destPath = path.join(dest, entry.name);
|
|
73
|
+
if (entry.isDirectory()) {
|
|
74
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
75
|
+
copyMerge(srcPath, destPath);
|
|
76
|
+
} else if (entry.name === "package.json" && fs.existsSync(destPath)) {
|
|
77
|
+
mergePackageJson(srcPath, destPath);
|
|
78
|
+
} else if (!fs.existsSync(destPath)) {
|
|
79
|
+
fs.copyFileSync(srcPath, destPath);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function main() {
|
|
35
85
|
const targetDir = process.argv[2] || ".";
|
|
36
|
-
const cwd
|
|
86
|
+
const cwd = process.cwd();
|
|
37
87
|
const absTarget = path.resolve(cwd, targetDir);
|
|
38
88
|
|
|
39
89
|
console.log("\n" + C.bold(C.cyan("╔══════════════════════════════════╗")));
|
|
40
|
-
console.log(C.bold(C.cyan("║ AITEAM-X — Instalação rápida
|
|
90
|
+
console.log(C.bold(C.cyan("║ AITEAM-X — Instalação rápida ║")));
|
|
41
91
|
console.log(C.bold(C.cyan("╚══════════════════════════════════╝")) + "\n");
|
|
42
92
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
93
|
+
const empty = isDirEmpty(absTarget);
|
|
94
|
+
const hasBmad = !empty && detectBmad(absTarget);
|
|
95
|
+
|
|
96
|
+
if (!empty) {
|
|
97
|
+
if (hasBmad) {
|
|
98
|
+
console.log(C.green(" Projeto BMAD detectado!"));
|
|
99
|
+
console.log(C.dim(" Os agentes existentes serão reconhecidos automaticamente."));
|
|
100
|
+
console.log(C.dim(" Arquivos existentes não serão sobrescritos.\n"));
|
|
101
|
+
} else {
|
|
102
|
+
console.log(C.yellow(" Diretório não está vazio."));
|
|
103
|
+
console.log(C.dim(" Arquivos existentes não serão sobrescritos.\n"));
|
|
104
|
+
}
|
|
105
|
+
const answer = await ask(" Instalar AITEAM-X aqui? (s/N) ");
|
|
106
|
+
if (answer !== "s" && answer !== "sim") {
|
|
107
|
+
console.log(C.dim("\n Instalação cancelada.\n"));
|
|
108
|
+
process.exit(0);
|
|
109
|
+
}
|
|
110
|
+
console.log();
|
|
49
111
|
}
|
|
50
112
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
113
|
+
fs.mkdirSync(absTarget, { recursive: true });
|
|
114
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "aiteam-x-"));
|
|
55
115
|
|
|
56
116
|
try {
|
|
57
|
-
// 1. Baixar template via degit
|
|
58
117
|
console.log(C.bold("1. Baixando template AITEAM-X..."));
|
|
59
|
-
execSync(`npx degit@latest ${REPO} ${
|
|
60
|
-
stdio: "inherit",
|
|
61
|
-
cwd,
|
|
62
|
-
});
|
|
118
|
+
execSync(`npx degit@latest ${REPO} "${tmpDir}" --force`, { stdio: "inherit", cwd });
|
|
63
119
|
console.log(C.green(" ✓ Template baixado\n"));
|
|
64
120
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
121
|
+
if (!empty) {
|
|
122
|
+
console.log(C.bold("2. Mesclando arquivos (existentes preservados)..."));
|
|
123
|
+
copyMerge(tmpDir, absTarget);
|
|
124
|
+
console.log(C.green(" ✓ Arquivos mesclados\n"));
|
|
125
|
+
} else {
|
|
126
|
+
copyMerge(tmpDir, absTarget);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const n = empty ? 2 : 3;
|
|
130
|
+
|
|
131
|
+
console.log(C.bold(`${n}. Instalando dependências...`));
|
|
132
|
+
execSync("npm install", { stdio: "inherit", cwd: absTarget });
|
|
71
133
|
console.log(C.green(" ✓ Dependências instaladas\n"));
|
|
72
134
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
execSync("npm run setup", {
|
|
76
|
-
stdio: "inherit",
|
|
77
|
-
cwd: absTarget,
|
|
78
|
-
});
|
|
135
|
+
console.log(C.bold(`${n + 1}. Executando wizard de configuração...`));
|
|
136
|
+
execSync("npm run setup", { stdio: "inherit", cwd: absTarget });
|
|
79
137
|
console.log(C.green(" ✓ Configuração concluída\n"));
|
|
80
138
|
|
|
81
|
-
|
|
82
|
-
console.log(C.bold("4. Iniciando servidor de desenvolvimento..."));
|
|
139
|
+
console.log(C.bold(`${n + 2}. Iniciando servidor de desenvolvimento...`));
|
|
83
140
|
console.log(C.dim(" Acesse http://localhost:3000 quando estiver pronto.\n"));
|
|
84
141
|
|
|
85
142
|
const child = spawn("npm", ["run", "dev"], {
|
|
@@ -87,19 +144,18 @@ function main() {
|
|
|
87
144
|
cwd: absTarget,
|
|
88
145
|
shell: true,
|
|
89
146
|
});
|
|
90
|
-
|
|
91
147
|
child.on("error", (err) => {
|
|
92
|
-
console.error(C.yellow("Erro ao iniciar:"), err);
|
|
148
|
+
console.error(C.yellow("Erro ao iniciar servidor:"), err.message);
|
|
93
149
|
process.exit(1);
|
|
94
150
|
});
|
|
151
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
95
152
|
|
|
96
|
-
child.on("exit", (code) => {
|
|
97
|
-
process.exit(code ?? 0);
|
|
98
|
-
});
|
|
99
153
|
} catch (err) {
|
|
100
154
|
if (err.status !== undefined) process.exit(err.status);
|
|
101
155
|
console.error("\n" + C.yellow("Erro:"), err.message);
|
|
102
156
|
process.exit(1);
|
|
157
|
+
} finally {
|
|
158
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
|
|
103
159
|
}
|
|
104
160
|
}
|
|
105
161
|
|