@danhachuel/pandanews 0.0.0-stage → 0.1.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/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +54 -2
- package/backend/app/__init__.py +1 -0
- package/backend/app/main.py +13 -0
- package/backend/app/routers/__init__.py +1 -0
- package/backend/app/schemas.py +1 -0
- package/backend/core/__init__.py +1 -0
- package/backend/core/config.py +1 -0
- package/backend/core/database.py +6 -0
- package/backend/core/image_gen.py +6 -0
- package/backend/core/llm_router.py +6 -0
- package/backend/core/pipeline.py +6 -0
- package/backend/requirements.txt +10 -0
- package/bin/cli.js +56 -0
- package/frontend/README.md +8 -0
- package/package.json +47 -4
- package/scripts/build.js +25 -0
- package/scripts/install.js +57 -0
- package/scripts/start.js +23 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Todas as versões publicadas são registradas aqui antes do publish (regra em AGENTS.md). A etiqueta visual usa PATCH de dois dígitos (ex.: 0.1.00); o registry npm normaliza para a versão canônica (ex.: 0.1.0).
|
|
4
|
+
|
|
5
|
+
## 0.1.00 (2026-10-23)
|
|
6
|
+
|
|
7
|
+
Bootstrap inicial do repositório PandaNews.
|
|
8
|
+
|
|
9
|
+
- Estrutura base de pastas: `bin/`, `scripts/`, `backend/` (app + core), `frontend/`, `.github/workflows/`
|
|
10
|
+
- `AGENTS.md` com as regras permanentes do projeto (versionamento de dois dígitos, push obrigatório, release via GitHub Actions, CHANGELOG obrigatório, sessões simultâneas)
|
|
11
|
+
- `package.json` com pacote `@danhachuel/pandanews` e binário `pandanews`
|
|
12
|
+
- CLI `pandanews` com comandos `install`, `start` e `build` (instalação estrutural funcional; Python portátil chega na 0.2.00, Fase 4)
|
|
13
|
+
- Workflow `publish-npm.yml`: validação de metadados, smoke test do instalador, publicação com dist-tag `next` via dispatch e promoção a `latest` via tags `vX.Y.ZZ`
|
|
14
|
+
- Correção do passo `Apply requested version`: a etiqueta visual de dois dígitos (ex.: `0.1.00`) é normalizada para semver canônico (ex.: `0.1.0`) antes do `npm version` — o primeiro dispatch falhou com "Version not changed"
|
|
15
|
+
- `README.md`, `LICENSE` (MIT), `.gitignore`, `CHANGELOG.md`
|
|
16
|
+
- Release placeholder no registry npm para criar o pacote `@danhachuel/pandanews`
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DanHachuel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,55 @@
|
|
|
1
|
-
#
|
|
1
|
+
# PandaNews
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
SaaS **local** (roda no navegador) para criação e automação de múltiplos blogs de notícias com IA.
|
|
4
|
+
|
|
5
|
+
- Blogs multi-tenant com tema (esporte, política, economia, tecnologia, geral) e recorte regional
|
|
6
|
+
- Coleta de feeds RSS → redação via LLM com fallback **NVIDIA NIM → Google Gemini**
|
|
7
|
+
- Imagens fotojornalísticas via Gemini Image
|
|
8
|
+
- Fluxo editorial: rascunho → revisão humana opcional → aprovado/publicado
|
|
9
|
+
- 100% local por padrão (SQLite + arquivos), com Supabase opcional
|
|
10
|
+
- Agendamento automático por blog (APScheduler)
|
|
11
|
+
|
|
12
|
+
## Instalação
|
|
13
|
+
|
|
14
|
+
CMD / MobaXterm:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
npx.cmd --yes --prefer-online @danhachuel/pandanews@latest install
|
|
18
|
+
npx.cmd --yes --prefer-online @danhachuel/pandanews@latest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Shell (PowerShell, Linux, macOS):
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
npx --yes @danhachuel/pandanews@latest install
|
|
25
|
+
npx --yes @danhachuel/pandanews@latest
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Requisitos: **Node.js >= 20**. Nenhum Python pré-instalado é necessário — o instalador provisiona um runtime Python portátil na primeira execução (`.runtime/` na raiz do pacote; sobrescreva com a variável de ambiente `PANDANEWS_HOME`).
|
|
29
|
+
|
|
30
|
+
## Status (versão 0.1.00)
|
|
31
|
+
|
|
32
|
+
Versão inicial de **bootstrap**: estrutura do repositório, CLI (`pandanews install/start/build`) e workflow de publicação via GitHub Actions. O backend FastAPI e a UI React chegam na **0.2.00** (Fases 1 a 4 do plano de implementação — ver `CHANGELOG.md`).
|
|
33
|
+
|
|
34
|
+
## Desenvolvimento
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
# Backend
|
|
38
|
+
pip install -r backend/requirements.txt
|
|
39
|
+
uvicorn backend.app.main:app --reload --port 8000
|
|
40
|
+
|
|
41
|
+
# Frontend
|
|
42
|
+
cd frontend && npm install && npm run dev
|
|
43
|
+
|
|
44
|
+
# CLI local
|
|
45
|
+
node bin/cli.js install --skip-python-deps
|
|
46
|
+
node bin/cli.js
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Regras do projeto
|
|
50
|
+
|
|
51
|
+
Versionamento (PATCH de dois dígitos), release via GitHub Actions, CHANGELOG obrigatório e demais regras permanentes estão em [`AGENTS.md`](AGENTS.md).
|
|
52
|
+
|
|
53
|
+
## Licença
|
|
54
|
+
|
|
55
|
+
MIT — veja [LICENSE](LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""PandaNews — aplicação backend (FastAPI)."""
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""PandaNews API — FastAPI.
|
|
2
|
+
|
|
3
|
+
Fase 0 (0.1.00): aplicação mínima com endpoint de health.
|
|
4
|
+
Fase 1: CRUD de blogs, configurações e router de LLM (NVIDIA NIM -> Google Gemini).
|
|
5
|
+
"""
|
|
6
|
+
from fastapi import FastAPI
|
|
7
|
+
|
|
8
|
+
app = FastAPI(title="PandaNews API", version="0.1.00")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.get("/api/v1/health")
|
|
12
|
+
def health() -> dict:
|
|
13
|
+
return {"status": "ok", "service": "pandanews", "version": app.version}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Routers do PandaNews: blogs, noticias, configuracoes, imagens, health (Fase 1+)."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Schemas Pydantic do PandaNews (preenchidos na Fase 1)."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Core do PandaNews: config, database, llm_router, image_gen, pipeline."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Configuração de runtime do PandaNews (Fase 1): .env, caminhos e constantes."""
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"""Camada de dados do PandaNews (Fase 1).
|
|
2
|
+
|
|
3
|
+
SQLite local por padrão (data/pandanews.db) via SQLAlchemy 2.0, com detecção
|
|
4
|
+
automática de Supabase quando SUPABASE_URL e SUPABASE_SERVICE_ROLE_KEY estão
|
|
5
|
+
definidas no ambiente. Tabelas: blogs, noticias, configuracoes, logs.
|
|
6
|
+
"""
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"""Router de LLM do PandaNews (Fase 1).
|
|
2
|
+
|
|
3
|
+
Fallback ordenado configurável (padrão: NVIDIA NIM -> Google Gemini) usando
|
|
4
|
+
llmswitch-client: roteamento por prioridade com circuit breaker. Retorna o
|
|
5
|
+
texto gerado e o provedor que respondeu (registrado em noticias.llm_provider).
|
|
6
|
+
"""
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"""Pipeline de notícias do PandaNews (Fase 3).
|
|
2
|
+
|
|
3
|
+
Coleta RSS -> filtragem por relevância -> rascunho via LLM -> imagem via Gemini
|
|
4
|
+
-> revisão humana opcional -> publicação. Disparado por APScheduler conforme a
|
|
5
|
+
frequência de cada blog ou manualmente pela interface.
|
|
6
|
+
"""
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// PandaNews CLI (@danhachuel/pandanews)
|
|
3
|
+
// Comandos: install | start (padrão) | build | help | version
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { runInstall } from '../scripts/install.js';
|
|
6
|
+
import { runStart } from '../scripts/start.js';
|
|
7
|
+
import { runBuild } from '../scripts/build.js';
|
|
8
|
+
|
|
9
|
+
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
10
|
+
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
const command = args.find((a) => !a.startsWith('--')) || 'start';
|
|
13
|
+
const flags = new Set(args.filter((a) => a.startsWith('--')));
|
|
14
|
+
|
|
15
|
+
function printHelp() {
|
|
16
|
+
console.log(`
|
|
17
|
+
PandaNews ${pkg.version} — automação de blogs de notícias com IA
|
|
18
|
+
|
|
19
|
+
Uso:
|
|
20
|
+
pandanews install Prepara o runtime local (estrutura + Python portátil)
|
|
21
|
+
pandanews Inicia backend (127.0.0.1:8000) e UI (127.0.0.1:3030)
|
|
22
|
+
pandanews build Compila o frontend de desenvolvimento
|
|
23
|
+
|
|
24
|
+
Opções:
|
|
25
|
+
--skip-python-deps Instalação estrutural sem Python (uso em CI)
|
|
26
|
+
--help Mostra esta ajuda
|
|
27
|
+
--version Mostra a versão
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function main() {
|
|
32
|
+
if (flags.has('--help') || command === 'help') {
|
|
33
|
+
printHelp();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (flags.has('--version') || command === 'version') {
|
|
37
|
+
console.log(pkg.version);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (command === 'install') {
|
|
41
|
+
await runInstall({ skipPythonDeps: flags.has('--skip-python-deps') });
|
|
42
|
+
} else if (command === 'start') {
|
|
43
|
+
await runStart();
|
|
44
|
+
} else if (command === 'build') {
|
|
45
|
+
await runBuild();
|
|
46
|
+
} else {
|
|
47
|
+
console.error(`Comando desconhecido: ${command}`);
|
|
48
|
+
printHelp();
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
main().catch((err) => {
|
|
54
|
+
console.error(`pandanews: ${err && err.message ? err.message : err}`);
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frontend/
|
|
2
|
+
|
|
3
|
+
UI do PandaNews (React + Vite + Tailwind), inicializada na Fase 2 do plano de implementação.
|
|
4
|
+
|
|
5
|
+
- Páginas: Dashboard, Blogs, Notícias, Imagens, Automação, Configurações, Logs
|
|
6
|
+
- Sidebar + topbar no padrão Leadmaster
|
|
7
|
+
- 7 leis de usabilidade aplicadas (Fitts, Hick, Zeigarnik, Jakob, Gradiente de Meta, von Restorff, Miller)
|
|
8
|
+
- Build: `npm run build` → `dist/` servido em 127.0.0.1:3030
|
package/package.json
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danhachuel/pandanews",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SaaS local de criação e automação de múltiplos blogs de notícias com IA (FastAPI + React + Tailwind).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"pandanews": "bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin/",
|
|
12
|
+
"scripts/",
|
|
13
|
+
"backend/",
|
|
14
|
+
"frontend/dist/",
|
|
15
|
+
"CHANGELOG.md",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build:frontend": "node scripts/build.js"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/DanHachuel/PandaNews.git"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/DanHachuel/PandaNews/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/DanHachuel/PandaNews#readme",
|
|
32
|
+
"keywords": [
|
|
33
|
+
"news",
|
|
34
|
+
"blog",
|
|
35
|
+
"ai",
|
|
36
|
+
"automation",
|
|
37
|
+
"rss",
|
|
38
|
+
"llm"
|
|
39
|
+
],
|
|
40
|
+
"author": "DanHachuel",
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"chalk": "^5.4.1",
|
|
43
|
+
"extract-zip": "^2.0.1",
|
|
44
|
+
"fs-extra": "^11.3.0",
|
|
45
|
+
"node-fetch": "^3.3.2",
|
|
46
|
+
"open": "^10.2.0",
|
|
47
|
+
"ora": "^8.2.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
package/scripts/build.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Compila o frontend de desenvolvimento (frontend/ -> frontend/dist).
|
|
2
|
+
// A UI React + Vite + Tailwind é inicializada na Fase 2 do plano.
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
9
|
+
const PKG_ROOT = join(__dirname, '..');
|
|
10
|
+
|
|
11
|
+
export async function runBuild() {
|
|
12
|
+
const frontendDir = join(PKG_ROOT, 'frontend');
|
|
13
|
+
if (!existsSync(join(frontendDir, 'package.json'))) {
|
|
14
|
+
console.log('frontend/ ainda não foi inicializado — chega na Fase 2 (versão 0.2.00).');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
18
|
+
console.log('Instalando dependências do frontend...');
|
|
19
|
+
const install = spawnSync(npmCmd, ['install'], { cwd: frontendDir, stdio: 'inherit' });
|
|
20
|
+
if (install.status !== 0) throw new Error('Falha ao instalar dependências do frontend.');
|
|
21
|
+
console.log('Compilando o frontend...');
|
|
22
|
+
const build = spawnSync(npmCmd, ['run', 'build'], { cwd: frontendDir, stdio: 'inherit' });
|
|
23
|
+
if (build.status !== 0) throw new Error('Falha ao compilar o frontend.');
|
|
24
|
+
console.log('Frontend compilado em frontend/dist.');
|
|
25
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Instalador do runtime PandaNews.
|
|
2
|
+
//
|
|
3
|
+
// Fase 0 (0.1.00): detecta plataforma, cria a estrutura de pastas (data/, .runtime/)
|
|
4
|
+
// e grava o marcador .runtime/.ready. O provisionamento completo de Python
|
|
5
|
+
// portátil + venv + dependências chega na versão 0.2.00 (Fase 4 do plano).
|
|
6
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { join, resolve } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
11
|
+
export const PKG_ROOT = join(__dirname, '..');
|
|
12
|
+
|
|
13
|
+
// Raiz de instalação: PANDANEWS_HOME sobrepõe o padrão (raiz do pacote instalado).
|
|
14
|
+
export function resolveHome() {
|
|
15
|
+
return process.env.PANDANEWS_HOME ? resolve(process.env.PANDANEWS_HOME) : PKG_ROOT;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Detecta plataforma e arquitetura para o download de python-build-standalone (Fase 4).
|
|
19
|
+
export function detectPlatform() {
|
|
20
|
+
const arch = process.arch === 'arm64' ? 'aarch64' : 'x86_64';
|
|
21
|
+
if (process.platform === 'win32') {
|
|
22
|
+
return { os: 'windows', arch, asset: `${arch}-pc-windows-msvc-shared-install_only.zip` };
|
|
23
|
+
}
|
|
24
|
+
if (process.platform === 'darwin') {
|
|
25
|
+
return { os: 'macos', arch, asset: `${arch}-apple-darwin-install_only.tar.gz` };
|
|
26
|
+
}
|
|
27
|
+
return { os: 'linux', arch, asset: `${arch}-unknown-linux-gnu-install_only.tar.gz` };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function runInstall({ skipPythonDeps = false } = {}) {
|
|
31
|
+
const home = resolveHome();
|
|
32
|
+
const platform = detectPlatform();
|
|
33
|
+
|
|
34
|
+
console.log(`PandaNews install — plataforma: ${platform.os} (${platform.arch})`);
|
|
35
|
+
console.log(`Raiz do runtime: ${home}`);
|
|
36
|
+
|
|
37
|
+
// Estrutura de pastas do runtime local
|
|
38
|
+
const dirs = [
|
|
39
|
+
join(home, 'data'),
|
|
40
|
+
join(home, 'data', 'imagens'),
|
|
41
|
+
join(home, '.runtime'),
|
|
42
|
+
];
|
|
43
|
+
for (const dir of dirs) {
|
|
44
|
+
mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Fase 4 (0.2.00): download de Python 3.12 portátil, venv e requirements.
|
|
48
|
+
if (skipPythonDeps) {
|
|
49
|
+
console.log('--skip-python-deps: instalação estrutural (uso em CI).');
|
|
50
|
+
} else {
|
|
51
|
+
console.log('Provisionamento de Python portátil e dependências: chega na versão 0.2.00 (Fase 4).');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
writeFileSync(join(home, '.runtime', '.ready'), new Date().toISOString());
|
|
55
|
+
console.log('Estrutura pronta. Runtime inicializado.');
|
|
56
|
+
return home;
|
|
57
|
+
}
|
package/scripts/start.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Inicia o PandaNews: backend FastAPI (127.0.0.1:8000) + UI estática (127.0.0.1:3030).
|
|
2
|
+
//
|
|
3
|
+
// Fase 0 (0.1.00): garante que o runtime esteja instalado e informa o status.
|
|
4
|
+
// Fase 4 (0.2.00): sobe o uvicorn, serve frontend/dist e abre o navegador.
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { resolveHome, runInstall } from './install.js';
|
|
8
|
+
|
|
9
|
+
export async function runStart() {
|
|
10
|
+
const home = resolveHome();
|
|
11
|
+
const readyMarker = join(home, '.runtime', '.ready');
|
|
12
|
+
|
|
13
|
+
if (!existsSync(readyMarker)) {
|
|
14
|
+
console.log('Runtime não encontrado — executando install...');
|
|
15
|
+
await runInstall({});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log('');
|
|
19
|
+
console.log('PandaNews 0.1.00 — versão inicial de bootstrap.');
|
|
20
|
+
console.log('O backend FastAPI (127.0.0.1:8000) e a UI (127.0.0.1:3030) serão');
|
|
21
|
+
console.log('servidos por este comando a partir da versão 0.2.00 (Fases 1 a 4 do plano).');
|
|
22
|
+
console.log(`Raiz do runtime: ${home}`);
|
|
23
|
+
}
|