agroplan-ai-cli 1.0.3 → 1.0.5
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/backend-template/requirements.txt +3 -4
- package/dist/index.js +227 -95
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,9 +5,6 @@ var __require = import.meta.require;
|
|
|
5
5
|
// src/commands/doctor.ts
|
|
6
6
|
import { existsSync as existsSync4 } from "fs";
|
|
7
7
|
|
|
8
|
-
// src/utils/python.ts
|
|
9
|
-
import { existsSync as existsSync2 } from "fs";
|
|
10
|
-
|
|
11
8
|
// src/utils/paths.ts
|
|
12
9
|
import { join, dirname } from "path";
|
|
13
10
|
import { existsSync, mkdirSync } from "fs";
|
|
@@ -116,59 +113,16 @@ function checkPip() {
|
|
|
116
113
|
} catch {}
|
|
117
114
|
return { available: false };
|
|
118
115
|
}
|
|
119
|
-
function createVenv() {
|
|
120
|
-
const paths = getProjectPaths();
|
|
121
|
-
const python = checkPython();
|
|
122
|
-
if (!python.available || !python.path) {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
try {
|
|
126
|
-
console.log("\uD83D\uDC0D Criando ambiente virtual...");
|
|
127
|
-
const result = Bun.spawnSync([python.path, "-m", "venv", ".venv"], {
|
|
128
|
-
cwd: paths.backend
|
|
129
|
-
});
|
|
130
|
-
return result.success;
|
|
131
|
-
} catch {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
function installRequirements() {
|
|
136
|
-
const paths = getProjectPaths();
|
|
137
|
-
if (!existsSync2(paths.venv)) {
|
|
138
|
-
console.log("\u274C Ambiente virtual n\xE3o encontrado");
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
try {
|
|
142
|
-
console.log("\uD83D\uDCE6 Instalando depend\xEAncias...");
|
|
143
|
-
const isWindows = process.platform === "win32";
|
|
144
|
-
const pipPath = isWindows ? `${paths.venv}/Scripts/pip.exe` : `${paths.venv}/bin/pip`;
|
|
145
|
-
const result = Bun.spawnSync([pipPath, "install", "-r", "requirements.txt"], {
|
|
146
|
-
cwd: paths.backend
|
|
147
|
-
});
|
|
148
|
-
return result.success;
|
|
149
|
-
} catch {
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
function getVenvPython() {
|
|
154
|
-
const paths = getProjectPaths();
|
|
155
|
-
if (!existsSync2(paths.venv)) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
const isWindows = process.platform === "win32";
|
|
159
|
-
const pythonPath = isWindows ? `${paths.venv}/Scripts/python.exe` : `${paths.venv}/bin/python`;
|
|
160
|
-
return existsSync2(pythonPath) ? pythonPath : null;
|
|
161
|
-
}
|
|
162
116
|
|
|
163
117
|
// src/utils/process.ts
|
|
164
|
-
import { existsSync as
|
|
118
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
165
119
|
function savePid(pid) {
|
|
166
120
|
const paths = getProjectPaths();
|
|
167
121
|
writeFileSync(paths.pidFile, pid.toString());
|
|
168
122
|
}
|
|
169
123
|
function readPid() {
|
|
170
124
|
const paths = getProjectPaths();
|
|
171
|
-
if (!
|
|
125
|
+
if (!existsSync2(paths.pidFile)) {
|
|
172
126
|
return null;
|
|
173
127
|
}
|
|
174
128
|
try {
|
|
@@ -180,7 +134,7 @@ function readPid() {
|
|
|
180
134
|
}
|
|
181
135
|
function removePidFile() {
|
|
182
136
|
const paths = getProjectPaths();
|
|
183
|
-
if (
|
|
137
|
+
if (existsSync2(paths.pidFile)) {
|
|
184
138
|
unlinkSync(paths.pidFile);
|
|
185
139
|
}
|
|
186
140
|
}
|
|
@@ -219,6 +173,43 @@ function checkPort(port) {
|
|
|
219
173
|
});
|
|
220
174
|
}
|
|
221
175
|
|
|
176
|
+
// src/utils/setup-state.ts
|
|
177
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
178
|
+
import { join as join2 } from "path";
|
|
179
|
+
function getSetupStatePath() {
|
|
180
|
+
return join2(getHomeAgroplanDir(), "setup.json");
|
|
181
|
+
}
|
|
182
|
+
function readSetupState() {
|
|
183
|
+
const statePath = getSetupStatePath();
|
|
184
|
+
if (!existsSync3(statePath)) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const content = readFileSync2(statePath, "utf-8");
|
|
189
|
+
return JSON.parse(content);
|
|
190
|
+
} catch {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function saveSetupState(state) {
|
|
195
|
+
const statePath = getSetupStatePath();
|
|
196
|
+
writeFileSync2(statePath, JSON.stringify(state, null, 2));
|
|
197
|
+
}
|
|
198
|
+
function isSetupComplete() {
|
|
199
|
+
const state = readSetupState();
|
|
200
|
+
if (!state)
|
|
201
|
+
return false;
|
|
202
|
+
const homeDir = getHomeAgroplanDir();
|
|
203
|
+
const backendDir = join2(homeDir, "backend");
|
|
204
|
+
const venvDir = join2(backendDir, ".venv");
|
|
205
|
+
const backendExists = existsSync3(backendDir);
|
|
206
|
+
const venvExists = existsSync3(venvDir);
|
|
207
|
+
const isWindows = process.platform === "win32";
|
|
208
|
+
const uvicornPath = isWindows ? join2(venvDir, "Scripts", "uvicorn.exe") : join2(venvDir, "bin", "uvicorn");
|
|
209
|
+
const uvicornExists = existsSync3(uvicornPath);
|
|
210
|
+
return backendExists && venvExists && uvicornExists && state.dependenciesInstalled;
|
|
211
|
+
}
|
|
212
|
+
|
|
222
213
|
// src/commands/doctor.ts
|
|
223
214
|
async function doctorCommand() {
|
|
224
215
|
console.log(`\uD83D\uDD0D AgroPlan AI - Diagn\xF3stico do Sistema
|
|
@@ -228,6 +219,9 @@ async function doctorCommand() {
|
|
|
228
219
|
const python = checkPython();
|
|
229
220
|
if (python.available) {
|
|
230
221
|
console.log(` \u2705 ${python.version} (${python.path})`);
|
|
222
|
+
if (python.version && python.version.includes("3.13")) {
|
|
223
|
+
console.log(" \u26A0\uFE0F Python 3.13 detectado. Se a instala\xE7\xE3o for lenta, use Python 3.11 ou 3.12.");
|
|
224
|
+
}
|
|
231
225
|
} else {
|
|
232
226
|
console.log(" \u274C Python n\xE3o encontrado");
|
|
233
227
|
console.log(" Instale Python 3.8+ em https://python.org");
|
|
@@ -243,6 +237,20 @@ async function doctorCommand() {
|
|
|
243
237
|
allGood = false;
|
|
244
238
|
}
|
|
245
239
|
console.log(`
|
|
240
|
+
\uD83D\uDEE0\uFE0F Setup Local:`);
|
|
241
|
+
const setupComplete = isSetupComplete();
|
|
242
|
+
const setupState = readSetupState();
|
|
243
|
+
if (setupComplete && setupState) {
|
|
244
|
+
console.log(" \u2705 Setup conclu\xEDdo");
|
|
245
|
+
console.log(` \uD83D\uDCC5 Instalado em: ${new Date(setupState.installedAt).toLocaleString()}`);
|
|
246
|
+
console.log(` \uD83D\uDCE6 Vers\xE3o: ${setupState.version}`);
|
|
247
|
+
console.log(` \uD83D\uDC0D Python: ${setupState.python}`);
|
|
248
|
+
} else {
|
|
249
|
+
console.log(" \u274C Setup n\xE3o conclu\xEDdo");
|
|
250
|
+
console.log(" Execute: agroplan setup");
|
|
251
|
+
allGood = false;
|
|
252
|
+
}
|
|
253
|
+
console.log(`
|
|
246
254
|
\uD83D\uDCC1 Estrutura do Projeto:`);
|
|
247
255
|
try {
|
|
248
256
|
const paths = getProjectPaths();
|
|
@@ -266,8 +274,17 @@ async function doctorCommand() {
|
|
|
266
274
|
}
|
|
267
275
|
if (existsSync4(paths.venv)) {
|
|
268
276
|
console.log(" \u2705 Ambiente virtual (.venv) encontrado");
|
|
277
|
+
const isWindows = process.platform === "win32";
|
|
278
|
+
const uvicornPath = isWindows ? `${paths.venv}/Scripts/uvicorn.exe` : `${paths.venv}/bin/uvicorn`;
|
|
279
|
+
if (existsSync4(uvicornPath)) {
|
|
280
|
+
console.log(" \u2705 Uvicorn instalado");
|
|
281
|
+
} else {
|
|
282
|
+
console.log(" \u274C Uvicorn n\xE3o encontrado");
|
|
283
|
+
allGood = false;
|
|
284
|
+
}
|
|
269
285
|
} else {
|
|
270
|
-
console.log(" \
|
|
286
|
+
console.log(" \u274C Ambiente virtual n\xE3o encontrado");
|
|
287
|
+
allGood = false;
|
|
271
288
|
}
|
|
272
289
|
} catch (error) {
|
|
273
290
|
console.log(" \u274C Erro ao verificar estrutura do projeto");
|
|
@@ -278,7 +295,30 @@ async function doctorCommand() {
|
|
|
278
295
|
\uD83C\uDF10 Conectividade:`);
|
|
279
296
|
const localRunning = await checkPort(8000);
|
|
280
297
|
if (localRunning) {
|
|
281
|
-
|
|
298
|
+
try {
|
|
299
|
+
const response = await fetch("http://localhost:8000/health", {
|
|
300
|
+
signal: AbortSignal.timeout(2000)
|
|
301
|
+
});
|
|
302
|
+
if (response.ok) {
|
|
303
|
+
const data = await response.json();
|
|
304
|
+
if (data.status && (data.culturas !== undefined || data.talhoes !== undefined)) {
|
|
305
|
+
console.log(" \u2705 API local rodando em http://localhost:8000");
|
|
306
|
+
console.log(` Status: ${data.status}`);
|
|
307
|
+
if (data.culturas !== undefined)
|
|
308
|
+
console.log(` Culturas: ${data.culturas}`);
|
|
309
|
+
if (data.talhoes !== undefined)
|
|
310
|
+
console.log(` Talh\xF5es: ${data.talhoes}`);
|
|
311
|
+
if (data.cache_items !== undefined)
|
|
312
|
+
console.log(` Cache items: ${data.cache_items}`);
|
|
313
|
+
} else {
|
|
314
|
+
console.log(" \u26A0\uFE0F Porta 8000 ocupada por outro servi\xE7o");
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
console.log(" \u26A0\uFE0F Porta 8000 ocupada (n\xE3o \xE9 AgroPlan)");
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
console.log(" \u26A0\uFE0F Porta 8000 ocupada (servi\xE7o n\xE3o identificado)");
|
|
321
|
+
}
|
|
282
322
|
} else {
|
|
283
323
|
console.log(" \u26A0\uFE0F API local n\xE3o est\xE1 rodando");
|
|
284
324
|
}
|
|
@@ -290,6 +330,8 @@ async function doctorCommand() {
|
|
|
290
330
|
const data = await renderResponse.json();
|
|
291
331
|
console.log(" \u2705 API Render online");
|
|
292
332
|
console.log(` Culturas: ${data.culturas}, Talh\xF5es: ${data.talhoes}`);
|
|
333
|
+
if (data.cache_items !== undefined)
|
|
334
|
+
console.log(` Cache items: ${data.cache_items}`);
|
|
293
335
|
} else {
|
|
294
336
|
console.log(" \u26A0\uFE0F API Render com problemas");
|
|
295
337
|
}
|
|
@@ -302,18 +344,21 @@ async function doctorCommand() {
|
|
|
302
344
|
console.log("\u2705 Sistema pronto para uso!");
|
|
303
345
|
console.log(`
|
|
304
346
|
Pr\xF3ximos passos:`);
|
|
305
|
-
console.log("
|
|
306
|
-
console.log("
|
|
347
|
+
console.log(" agroplan serve on # Iniciar API local");
|
|
348
|
+
console.log(" agroplan open # Abrir no navegador");
|
|
307
349
|
} else {
|
|
308
350
|
console.log("\u274C Alguns problemas foram encontrados");
|
|
309
351
|
console.log(`
|
|
310
|
-
Correja os problemas acima
|
|
311
|
-
|
|
352
|
+
Correja os problemas acima:`);
|
|
353
|
+
if (!setupComplete) {
|
|
354
|
+
console.log(" agroplan setup # Configurar API local");
|
|
355
|
+
}
|
|
356
|
+
console.log(" agroplan doctor # Verificar novamente");
|
|
312
357
|
}
|
|
313
358
|
}
|
|
314
359
|
|
|
315
360
|
// src/commands/serve.ts
|
|
316
|
-
import { existsSync as existsSync5, readFileSync as
|
|
361
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
317
362
|
import { spawn } from "child_process";
|
|
318
363
|
async function serveOnCommand() {
|
|
319
364
|
console.log(`\uD83D\uDE80 Iniciando API local do AgroPlan AI...
|
|
@@ -341,31 +386,41 @@ async function serveOnCommand() {
|
|
|
341
386
|
}
|
|
342
387
|
ensureAgroplanDir();
|
|
343
388
|
if (!existsSync5(paths.venv)) {
|
|
344
|
-
console.log("\uD83D\uDC0D Criando ambiente virtual...");
|
|
345
|
-
if (!createVenv()) {
|
|
346
|
-
console.log("\u274C Falha ao criar ambiente virtual");
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
const venvPython = getVenvPython();
|
|
351
|
-
if (!venvPython) {
|
|
352
389
|
console.log("\u274C Ambiente virtual n\xE3o encontrado");
|
|
390
|
+
console.log(" Execute: agroplan setup");
|
|
353
391
|
return;
|
|
354
392
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
393
|
+
const isWindows = process.platform === "win32";
|
|
394
|
+
const uvicornPath = isWindows ? `${paths.venv}/Scripts/uvicorn.exe` : `${paths.venv}/bin/uvicorn`;
|
|
395
|
+
if (!existsSync5(uvicornPath)) {
|
|
396
|
+
console.log("\u274C Depend\xEAncias n\xE3o instaladas");
|
|
397
|
+
console.log(" Execute: agroplan setup");
|
|
358
398
|
return;
|
|
359
399
|
}
|
|
360
400
|
const portInUse = await checkPort(8000);
|
|
361
401
|
if (portInUse) {
|
|
362
|
-
|
|
363
|
-
|
|
402
|
+
try {
|
|
403
|
+
const response = await fetch("http://localhost:8000/health", {
|
|
404
|
+
signal: AbortSignal.timeout(2000)
|
|
405
|
+
});
|
|
406
|
+
if (response.ok) {
|
|
407
|
+
const data = await response.json();
|
|
408
|
+
if (data.status && (data.culturas !== undefined || data.talhoes !== undefined)) {
|
|
409
|
+
console.log("\u2705 API local j\xE1 est\xE1 rodando em http://localhost:8000");
|
|
410
|
+
console.log(` Status: ${data.status}`);
|
|
411
|
+
if (data.culturas !== undefined)
|
|
412
|
+
console.log(` Culturas: ${data.culturas}`);
|
|
413
|
+
if (data.talhoes !== undefined)
|
|
414
|
+
console.log(` Talh\xF5es: ${data.talhoes}`);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
} catch {}
|
|
419
|
+
console.log("\u274C Porta 8000 est\xE1 ocupada por outro processo");
|
|
420
|
+
console.log(" Feche o processo ou use outro modo de API");
|
|
364
421
|
return;
|
|
365
422
|
}
|
|
366
423
|
console.log("\uD83C\uDF10 Iniciando servidor uvicorn...");
|
|
367
|
-
const isWindows = process.platform === "win32";
|
|
368
|
-
const uvicornPath = isWindows ? `${paths.venv}/Scripts/uvicorn.exe` : `${paths.venv}/bin/uvicorn`;
|
|
369
424
|
const child = spawn(uvicornPath, [
|
|
370
425
|
"api:app",
|
|
371
426
|
"--host",
|
|
@@ -404,13 +459,13 @@ async function serveOnCommand() {
|
|
|
404
459
|
console.log(" URL: http://localhost:8000");
|
|
405
460
|
console.log(" Health: http://localhost:8000/health");
|
|
406
461
|
console.log(`
|
|
407
|
-
\uD83D\uDCA1 Use '
|
|
462
|
+
\uD83D\uDCA1 Use 'agroplan serve off' para parar`);
|
|
408
463
|
return;
|
|
409
464
|
}
|
|
410
465
|
attempts++;
|
|
411
466
|
}
|
|
412
467
|
console.log("\u274C Falha ao iniciar API local");
|
|
413
|
-
console.log(" Verifique os logs:
|
|
468
|
+
console.log(" Verifique os logs: agroplan serve logs");
|
|
414
469
|
}
|
|
415
470
|
async function serveOffCommand() {
|
|
416
471
|
console.log(`\uD83D\uDED1 Parando API local...
|
|
@@ -493,7 +548,7 @@ function serveLogsCommand() {
|
|
|
493
548
|
return;
|
|
494
549
|
}
|
|
495
550
|
try {
|
|
496
|
-
const logs =
|
|
551
|
+
const logs = readFileSync3(paths.logFile, "utf-8");
|
|
497
552
|
const lines = logs.split(`
|
|
498
553
|
`);
|
|
499
554
|
const recentLines = lines.slice(-50).filter((line) => line.trim());
|
|
@@ -552,23 +607,61 @@ function openCommand() {
|
|
|
552
607
|
}
|
|
553
608
|
|
|
554
609
|
// src/commands/setup.ts
|
|
555
|
-
import { existsSync as existsSync6, cpSync } from "fs";
|
|
556
|
-
import { join as
|
|
557
|
-
|
|
610
|
+
import { existsSync as existsSync6, cpSync, rmSync } from "fs";
|
|
611
|
+
import { join as join3, dirname as dirname2 } from "path";
|
|
612
|
+
var __dirname = "C:\\Users\\Defal\\Documents\\Projetos\\AgroPlan\\tools\\agroplan-cli\\src\\commands";
|
|
613
|
+
async function setupCommand(force = false, pythonPath) {
|
|
558
614
|
console.log(`\uD83D\uDEE0\uFE0F Configurando AgroPlan AI - API Local
|
|
559
615
|
`);
|
|
560
616
|
const homeDir = getHomeAgroplanDir();
|
|
561
|
-
const backendDir =
|
|
617
|
+
const backendDir = join3(homeDir, "backend");
|
|
562
618
|
console.log(`\uD83D\uDCC1 Diret\xF3rio de instala\xE7\xE3o: ${homeDir}`);
|
|
619
|
+
if (!force && isSetupComplete()) {
|
|
620
|
+
console.log(`
|
|
621
|
+
\u2705 API local j\xE1 est\xE1 configurada!`);
|
|
622
|
+
console.log(`
|
|
623
|
+
\uD83D\uDE80 Pr\xF3ximos passos:`);
|
|
624
|
+
console.log(" agroplan serve on # Iniciar API local");
|
|
625
|
+
console.log(" agroplan open # Abrir no navegador");
|
|
626
|
+
console.log(`
|
|
627
|
+
\uD83D\uDCA1 Para reinstalar: agroplan setup --force`);
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
563
630
|
console.log(`
|
|
564
631
|
\uD83D\uDC0D Verificando Python...`);
|
|
565
|
-
|
|
632
|
+
let python;
|
|
633
|
+
if (pythonPath) {
|
|
634
|
+
console.log(` \uD83C\uDFAF Usando Python espec\xEDfico: ${pythonPath}`);
|
|
635
|
+
if (!existsSync6(pythonPath)) {
|
|
636
|
+
console.log("\u274C Python especificado n\xE3o encontrado");
|
|
637
|
+
console.log(` Caminho: ${pythonPath}`);
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
const versionResult = Bun.spawnSync([pythonPath, "--version"], {});
|
|
641
|
+
if (!versionResult.success) {
|
|
642
|
+
console.log("\u274C Falha ao verificar vers\xE3o do Python especificado");
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const versionOutput = new TextDecoder().decode(versionResult.stdout);
|
|
646
|
+
python = {
|
|
647
|
+
available: true,
|
|
648
|
+
path: pythonPath,
|
|
649
|
+
version: versionOutput.trim()
|
|
650
|
+
};
|
|
651
|
+
} else {
|
|
652
|
+
python = checkPython();
|
|
653
|
+
}
|
|
566
654
|
if (!python.available) {
|
|
567
655
|
console.log("\u274C Python n\xE3o encontrado");
|
|
568
656
|
console.log(" Instale Python 3.8+ em https://python.org/downloads");
|
|
657
|
+
console.log(" Ou use: agroplan setup --python=<caminho>");
|
|
569
658
|
return;
|
|
570
659
|
}
|
|
571
660
|
console.log(` \u2705 ${python.version}`);
|
|
661
|
+
if (python.version && python.version.includes("3.13")) {
|
|
662
|
+
console.log(" \u26A0\uFE0F Python 3.13 detectado. Se a instala\xE7\xE3o for lenta, use Python 3.11 ou 3.12.");
|
|
663
|
+
console.log(' \uD83D\uDCA1 Exemplo: agroplan setup --python="C:\\Python311\\python.exe"');
|
|
664
|
+
}
|
|
572
665
|
console.log(`
|
|
573
666
|
\uD83D\uDCC2 Criando estrutura de diret\xF3rios...`);
|
|
574
667
|
ensureAgroplanDir();
|
|
@@ -577,21 +670,20 @@ async function setupCommand() {
|
|
|
577
670
|
try {
|
|
578
671
|
const packagePath = __require.resolve("agroplan-ai-cli/package.json");
|
|
579
672
|
const packageDir = dirname2(packagePath);
|
|
580
|
-
templateDir =
|
|
673
|
+
templateDir = join3(packageDir, "backend-template");
|
|
581
674
|
} catch {
|
|
582
675
|
const cliDir = dirname2(dirname2(dirname2(import.meta.url.replace("file://", ""))));
|
|
583
|
-
templateDir =
|
|
676
|
+
templateDir = join3(cliDir, "backend-template");
|
|
584
677
|
}
|
|
585
678
|
if (!existsSync6(templateDir)) {
|
|
586
679
|
console.log("\u274C Template do backend n\xE3o encontrado");
|
|
587
680
|
console.log(` Esperado em: ${templateDir}`);
|
|
588
|
-
console.log(" Reinstale a CLI: bun add -g
|
|
681
|
+
console.log(" Reinstale a CLI: bun add -g agroplan-ai-cli");
|
|
589
682
|
return;
|
|
590
683
|
}
|
|
591
684
|
try {
|
|
592
685
|
if (existsSync6(backendDir)) {
|
|
593
686
|
console.log(" \uD83D\uDDD1\uFE0F Removendo instala\xE7\xE3o anterior...");
|
|
594
|
-
const { rmSync } = await import("fs");
|
|
595
687
|
rmSync(backendDir, { recursive: true, force: true });
|
|
596
688
|
}
|
|
597
689
|
cpSync(templateDir, backendDir, { recursive: true });
|
|
@@ -603,7 +695,7 @@ async function setupCommand() {
|
|
|
603
695
|
}
|
|
604
696
|
console.log(`
|
|
605
697
|
\uD83D\uDC0D Criando ambiente virtual...`);
|
|
606
|
-
const venvPath =
|
|
698
|
+
const venvPath = join3(backendDir, ".venv");
|
|
607
699
|
if (!existsSync6(venvPath)) {
|
|
608
700
|
const result = Bun.spawnSync([python.path, "-m", "venv", ".venv"], {
|
|
609
701
|
cwd: backendDir
|
|
@@ -616,25 +708,48 @@ async function setupCommand() {
|
|
|
616
708
|
console.log(" \u2705 Ambiente virtual criado");
|
|
617
709
|
console.log(`
|
|
618
710
|
\uD83D\uDCE6 Instalando depend\xEAncias Python...`);
|
|
711
|
+
console.log(" \uD83D\uDCA1 Isso pode levar alguns minutos na primeira vez...");
|
|
619
712
|
const isWindows = process.platform === "win32";
|
|
620
|
-
const pipPath = isWindows ?
|
|
621
|
-
const
|
|
713
|
+
const pipPath = isWindows ? join3(venvPath, "Scripts", "pip.exe") : join3(venvPath, "bin", "pip");
|
|
714
|
+
const upgradeResult = Bun.spawnSync([pipPath, "install", "--upgrade", "pip"], {
|
|
715
|
+
cwd: backendDir
|
|
716
|
+
});
|
|
717
|
+
if (!upgradeResult.success) {
|
|
718
|
+
console.log("\u26A0\uFE0F Falha ao atualizar pip, continuando...");
|
|
719
|
+
}
|
|
720
|
+
const installResult = Bun.spawnSync([pipPath, "install", "--only-binary=:all:", "-r", "requirements.txt"], {
|
|
622
721
|
cwd: backendDir
|
|
623
722
|
});
|
|
624
723
|
if (!installResult.success) {
|
|
625
|
-
console.log("\
|
|
626
|
-
|
|
627
|
-
|
|
724
|
+
console.log(" \u26A0\uFE0F Instala\xE7\xE3o com bin\xE1rios falhou, tentando instala\xE7\xE3o normal...");
|
|
725
|
+
const fallbackResult = Bun.spawnSync([pipPath, "install", "-r", "requirements.txt"], {
|
|
726
|
+
cwd: backendDir
|
|
727
|
+
});
|
|
728
|
+
if (!fallbackResult.success) {
|
|
729
|
+
console.log("\u274C Falha ao instalar depend\xEAncias");
|
|
730
|
+
console.log(" Verifique sua conex\xE3o com a internet");
|
|
731
|
+
console.log(" Para depend\xEAncias cient\xEDficas, recomendamos Python 3.11 ou 3.12");
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
628
734
|
}
|
|
629
735
|
console.log(" \u2705 Depend\xEAncias instaladas");
|
|
630
736
|
console.log(`
|
|
631
737
|
\uD83C\uDF10 Verificando servidor web...`);
|
|
632
|
-
const uvicornPath = isWindows ?
|
|
738
|
+
const uvicornPath = isWindows ? join3(venvPath, "Scripts", "uvicorn.exe") : join3(venvPath, "bin", "uvicorn");
|
|
633
739
|
if (!existsSync6(uvicornPath)) {
|
|
634
740
|
console.log("\u274C Uvicorn n\xE3o encontrado");
|
|
635
741
|
return;
|
|
636
742
|
}
|
|
637
743
|
console.log(" \u2705 Servidor web configurado");
|
|
744
|
+
const packageJson = __require(join3(dirname2(dirname2(dirname2(__dirname))), "package.json"));
|
|
745
|
+
saveSetupState({
|
|
746
|
+
version: packageJson.version || "1.0.5",
|
|
747
|
+
installedAt: new Date().toISOString(),
|
|
748
|
+
backendPath: backendDir,
|
|
749
|
+
python: python.version || "unknown",
|
|
750
|
+
pythonPath: python.path || "",
|
|
751
|
+
dependenciesInstalled: true
|
|
752
|
+
});
|
|
638
753
|
console.log(`
|
|
639
754
|
` + "=".repeat(50));
|
|
640
755
|
console.log("\u2705 Configura\xE7\xE3o conclu\xEDda com sucesso!");
|
|
@@ -649,6 +764,8 @@ async function setupCommand() {
|
|
|
649
764
|
// src/index.ts
|
|
650
765
|
var COMMANDS = {
|
|
651
766
|
setup: "Configura a API local no seu computador",
|
|
767
|
+
"setup --force": "Reinstala a API local (remove instala\xE7\xE3o anterior)",
|
|
768
|
+
"setup --python=<path>": "Usa Python espec\xEDfico para instala\xE7\xE3o",
|
|
652
769
|
doctor: "Verifica se o sistema est\xE1 configurado corretamente",
|
|
653
770
|
"serve on": "Inicia a API local em http://localhost:8000",
|
|
654
771
|
"serve off": "Para a API local",
|
|
@@ -657,12 +774,12 @@ var COMMANDS = {
|
|
|
657
774
|
open: "Abre o AgroPlan AI no navegador"
|
|
658
775
|
};
|
|
659
776
|
function showHelp() {
|
|
660
|
-
console.log("\uD83C\uDF31 AgroPlan AI - CLI Local v1.0.
|
|
777
|
+
console.log("\uD83C\uDF31 AgroPlan AI - CLI Local v1.0.5");
|
|
661
778
|
console.log(` Launcher para modo local acelerado
|
|
662
779
|
`);
|
|
663
780
|
console.log("\uD83D\uDCCB Comandos dispon\xEDveis:");
|
|
664
781
|
Object.entries(COMMANDS).forEach(([cmd, desc]) => {
|
|
665
|
-
console.log(`
|
|
782
|
+
console.log(` agroplan ${cmd.padEnd(20)} # ${desc}`);
|
|
666
783
|
});
|
|
667
784
|
console.log(`
|
|
668
785
|
\uD83C\uDFAF Fluxo recomendado:`);
|
|
@@ -671,6 +788,9 @@ function showHelp() {
|
|
|
671
788
|
console.log(" 3. agroplan open # Abrir no navegador");
|
|
672
789
|
console.log(" 4. agroplan serve off # Parar quando terminar");
|
|
673
790
|
console.log(`
|
|
791
|
+
\uD83D\uDC0D Para Python 3.13 (Windows):`);
|
|
792
|
+
console.log(' agroplan setup --python="C:\\Python311\\python.exe"');
|
|
793
|
+
console.log(`
|
|
674
794
|
\uD83D\uDCA1 Modo h\xEDbrido:`);
|
|
675
795
|
console.log(" \u2022 API Local: R\xE1pida, n\xE3o dorme, ideal para uso di\xE1rio");
|
|
676
796
|
console.log(" \u2022 API Render: Fallback universal, funciona em qualquer PC");
|
|
@@ -682,11 +802,23 @@ async function main() {
|
|
|
682
802
|
showHelp();
|
|
683
803
|
return;
|
|
684
804
|
}
|
|
685
|
-
|
|
805
|
+
let command = "";
|
|
806
|
+
let pythonPath;
|
|
807
|
+
let force = false;
|
|
808
|
+
for (let i = 0;i < args.length; i++) {
|
|
809
|
+
const arg = args[i];
|
|
810
|
+
if (arg.startsWith("--python=")) {
|
|
811
|
+
pythonPath = arg.split("=")[1];
|
|
812
|
+
} else if (arg === "--force") {
|
|
813
|
+
force = true;
|
|
814
|
+
} else {
|
|
815
|
+
command += (command ? " " : "") + arg;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
686
818
|
try {
|
|
687
819
|
switch (command) {
|
|
688
820
|
case "setup":
|
|
689
|
-
await setupCommand();
|
|
821
|
+
await setupCommand(force, pythonPath);
|
|
690
822
|
break;
|
|
691
823
|
case "doctor":
|
|
692
824
|
await doctorCommand();
|
|
@@ -714,7 +846,7 @@ async function main() {
|
|
|
714
846
|
default:
|
|
715
847
|
console.log(`\u274C Comando desconhecido: ${command}`);
|
|
716
848
|
console.log(`
|
|
717
|
-
\uD83D\uDCA1 Use '
|
|
849
|
+
\uD83D\uDCA1 Use 'agroplan help' para ver comandos dispon\xEDveis`);
|
|
718
850
|
process.exit(1);
|
|
719
851
|
}
|
|
720
852
|
} catch (error) {
|