theforge-cli 0.0.0-stage → 0.2.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 +662 -0
- package/LICENSE +21 -0
- package/README.md +271 -2
- package/dist/index.js +24307 -0
- package/docs/arquitetura.md +149 -0
- package/docs/capabilities.md +155 -0
- package/docs/registry-state-contract.md +81 -0
- package/docs/solucao-de-problemas.md +85 -0
- package/package.json +71 -4
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Arquitetura
|
|
2
|
+
|
|
3
|
+
O forge-cli é um CLI Node.js (ESM + TypeScript) de fluxo único: um
|
|
4
|
+
orquestrador fino coordena módulos pequenos e testáveis. A regra de
|
|
5
|
+
organização é simples — **`src/index.ts` só orquestra; toda lógica
|
|
6
|
+
vive em módulos especializados.**
|
|
7
|
+
|
|
8
|
+
## Mapa de módulos
|
|
9
|
+
|
|
10
|
+
| Módulo | Responsabilidade |
|
|
11
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
12
|
+
| `src/index.ts` | Só despacha: parse de args, menu, resolução do subcomando, SIGINT e erros fatais. |
|
|
13
|
+
| `src/cmd/shared.ts` | Banner, preflight, catálogo efetivo, `--json`, seleção de Forjas por nome. |
|
|
14
|
+
| `src/cmd/batch.ts` | Execução sequencial com spinner/taskLog por Forja. |
|
|
15
|
+
| `src/cmd/query.ts` | `doctor`, `list`, `status`, `update --check`, `versions` (com `--json`). |
|
|
16
|
+
| `src/cmd/manage.ts` | `pin`, `unpin`, `rollback`, `uninstall <forjas>`, `self update`, PATH. |
|
|
17
|
+
| `src/cmd/run.ts` | Fluxo de instalação/clone/update/reinstall e resumo de execução com aprovação. |
|
|
18
|
+
| `src/cmd/registry.ts` | `install/uninstall --method registry` e `registry`: plano, confirmação, `--json`/`--report`, probes. |
|
|
19
|
+
| `src/registry/` | Método registry-first: `catalog` (dists PyPI), `pypi` (resolve + cache), `versions` (PEP 440 subset), `install` (venv isolada, sha256, receipt/state). |
|
|
20
|
+
| `src/prompts.ts` | Prompts interativos (diretório, seleção, confirmação) e tratamento de cancelamento via `isCancel()`. |
|
|
21
|
+
| `src/preflight.ts` | Verificações de ambiente antes de qualquer prompt: `git`, Node.js >= 20, `powershell.exe` no Windows. |
|
|
22
|
+
| `src/runner.ts` | Pipeline por repositório com cronômetro e fases: sincronizar → `.env` → script de instalação. |
|
|
23
|
+
| `src/env.ts` | Provisionamento do `.env` (`planEnvFile` decide, `ensureEnvFile` executa). |
|
|
24
|
+
| `src/report.ts` | Badges de status, linha por repositório e relatório consolidado. |
|
|
25
|
+
| `src/ui/theme.ts` | Paleta de cores (picocolors) e ícones emoji. Único ponto de contato com cores. |
|
|
26
|
+
| `src/ui/strings.ts` | Todas as strings visíveis ao usuário, em PT-BR. |
|
|
27
|
+
| `src/constants/repos.ts` | Catálogo fixo dos oito repositórios Forge. |
|
|
28
|
+
| `src/utils/system.ts` | Primitivas: resolução de caminho, `.git`, seleção de script por SO, `execa`, detalhe de erro. |
|
|
29
|
+
| `src/commands.ts` | Resolve o subcomando (`install`, `clone`, `update`, `pin`, `self ...`) a partir dos posicionais. |
|
|
30
|
+
| `src/menu.ts` | Menu principal; só aparece com TTY e sem comando/flags de seleção. |
|
|
31
|
+
| `src/safety.ts` | Nomes/URLs de repositório válidos, bloqueio de symlink/junction, redação de segredos, escrita atômica. |
|
|
32
|
+
| `src/git-revs.ts` | Tags, checkout destacado por ref/versão, verificação de atualização via fetch. |
|
|
33
|
+
| `src/lifecycle.ts` | Plano e execução de uninstall (com backup) e rollback de checkout. |
|
|
34
|
+
| `src/native-install.ts` | Monta o `<cli> install` nativo da Forja com as flags que ela documenta. |
|
|
35
|
+
| `src/status.ts` | Fase local (não clonado, clonado, instalado, falha), versão e alterações. |
|
|
36
|
+
| `src/self.ts` | Detecta o método de instalação do CLI e planeja o `self update`. |
|
|
37
|
+
| `src/types.ts` | Tipos compartilhados (`ForgeRepo`, `RepoResult`, `InstallScript`, `PreflightCheck`). |
|
|
38
|
+
|
|
39
|
+
## Fluxo de execução
|
|
40
|
+
|
|
41
|
+
```mermaid
|
|
42
|
+
flowchart TD
|
|
43
|
+
A[Banner animado + intro] --> B[Preflight: git, Node, powershell]
|
|
44
|
+
B -->|falha| Z1[log.error + exit 1]
|
|
45
|
+
B -->|ok| C[Prompt: diretório de destino]
|
|
46
|
+
C --> D[Resolve caminho + mkdir -p]
|
|
47
|
+
D --> E[Multiselect: 8 repositórios]
|
|
48
|
+
E --> F[Resumo + confirmar]
|
|
49
|
+
F -->|cancelou| Z2[cancel + exit 0]
|
|
50
|
+
F -->|confirmou| G[Para cada repositório]
|
|
51
|
+
G --> H{Pasta tem .git?}
|
|
52
|
+
H -->|sim| I[git pull]
|
|
53
|
+
H -->|não| J[git clone]
|
|
54
|
+
I --> K[Provisionar .env]
|
|
55
|
+
J --> K
|
|
56
|
+
K -->|falha| L[ERRO: pula script]
|
|
57
|
+
K --> M{Script do SO existe?}
|
|
58
|
+
M -->|não| N[AVISO: sem script]
|
|
59
|
+
M -->|sim| O[install.ps1 ou install.sh]
|
|
60
|
+
O -->|falha| P[ERRO]
|
|
61
|
+
O -->|ok| Q[OK]
|
|
62
|
+
L & N & P & Q --> R[Próximo repositório]
|
|
63
|
+
R -->|fim da lista| S[Relatório + outro]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Camadas adicionadas no roadmap 2.0
|
|
67
|
+
|
|
68
|
+
- **Segurança antes de execução:** todo nome/URL passa por `safety.ts`; o
|
|
69
|
+
destino nunca é symlink; segredos são mascarados em logs, relatórios e erros.
|
|
70
|
+
- **Sync com política:** falha de pull, divergência ou remote diferente do
|
|
71
|
+
catálogo impedem a execução de scripts, salvo aprovação por flag.
|
|
72
|
+
- **Instalação em duas fases:** bootstrap (`setup.sh/ps1`) e, sob opt-in
|
|
73
|
+
(`--profile/--scope/--components`), o `<cli> install` da própria Forja —
|
|
74
|
+
sempre `--dry-run` sem `--yes`. Veja [capabilities.md](capabilities.md).
|
|
75
|
+
- **Independência:** nenhuma Forja depende do forge-cli; o estado em
|
|
76
|
+
`.forge-cli/` é auxiliar e pode ser descartado.
|
|
77
|
+
|
|
78
|
+
## Decisões de design
|
|
79
|
+
|
|
80
|
+
### `.env` antes do script de instalação
|
|
81
|
+
|
|
82
|
+
Os scripts `install.ps1`/`install.sh` presumem variáveis de ambiente.
|
|
83
|
+
O `runner` provisiona o `.env` entre a sincronização e o script: se o
|
|
84
|
+
provisionamento falhar, o script nem roda — falhar cedo evita
|
|
85
|
+
instalações parciais silenciosas.
|
|
86
|
+
|
|
87
|
+
### `.env` nunca é sobrescrito
|
|
88
|
+
|
|
89
|
+
`planEnvFile` retorna `exists` quando o `.env` já está presente. O
|
|
90
|
+
repo pode ter segredos reais configurados; o CLI só cria o arquivo
|
|
91
|
+
quando ele não existe. Esta regra é coberta por teste em
|
|
92
|
+
`tests/env.test.ts`.
|
|
93
|
+
|
|
94
|
+
### Preflight falha rápido
|
|
95
|
+
|
|
96
|
+
Ambiente sem `git` ou sem `powershell.exe` (Windows) não consegue
|
|
97
|
+
completar o fluxo. Melhor falhar com mensagem clara antes de criar
|
|
98
|
+
diretórios do que descobrir no meio do lote.
|
|
99
|
+
|
|
100
|
+
### Isolamento de erro por repositório
|
|
101
|
+
|
|
102
|
+
`processRepo` converte cada falha (clone, `.env`, script) em um
|
|
103
|
+
`RepoResult` com `status: 'error'` em vez de lançar exceção. O laço
|
|
104
|
+
continua e o relatório final mostra o quadro completo.
|
|
105
|
+
|
|
106
|
+
### Erro detalhado via execa
|
|
107
|
+
|
|
108
|
+
`errorDetail` extrai `stderr`, `shortMessage` ou `message` do erro do
|
|
109
|
+
`execa` — o relatório mostra a causa real (por exemplo, erro de
|
|
110
|
+
autenticação do git), não só "falhou".
|
|
111
|
+
|
|
112
|
+
### Strings e cores centralizadas
|
|
113
|
+
|
|
114
|
+
Todo texto PT-BR vive em `src/ui/strings.ts` e toda cor em
|
|
115
|
+
`src/ui/theme.ts`. Isso mantém o código livre de literais soltos e
|
|
116
|
+
abre caminho para i18n futura sem reescrever módulos.
|
|
117
|
+
|
|
118
|
+
## Tipos centrais
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
interface ForgeRepo {
|
|
122
|
+
name;
|
|
123
|
+
url;
|
|
124
|
+
description;
|
|
125
|
+
}
|
|
126
|
+
type RepoStatus = 'ok' | 'warning' | 'error';
|
|
127
|
+
type EnvAction = 'exists' | 'copied' | 'stub';
|
|
128
|
+
interface RepoResult {
|
|
129
|
+
repo;
|
|
130
|
+
status;
|
|
131
|
+
detail;
|
|
132
|
+
envNote?;
|
|
133
|
+
elapsedMs;
|
|
134
|
+
}
|
|
135
|
+
interface InstallScript {
|
|
136
|
+
file;
|
|
137
|
+
command;
|
|
138
|
+
args;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Build e distribuição
|
|
143
|
+
|
|
144
|
+
- `tsup` compila `src/index.ts` para `dist/index.js` (ESM único,
|
|
145
|
+
~12 KB), preservando o shebang do binário.
|
|
146
|
+
- `bin.forge-cli` aponta para `dist/index.js`; `npm link` registra o
|
|
147
|
+
comando global.
|
|
148
|
+
- Dependências ficam externas ao bundle e são instaladas via
|
|
149
|
+
`package.json`.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Matriz de capacidades das Forjas
|
|
2
|
+
|
|
3
|
+
Levantamento estático (leitura do código e da documentação dos repositórios,
|
|
4
|
+
clones rasos em diretório temporário, sem executar instaladores). Nada aqui é
|
|
5
|
+
suposição: o que não pôde ser confirmado está marcado **não verificado**.
|
|
6
|
+
|
|
7
|
+
Revisões inspecionadas (HEAD de `main` em 2026-10-12):
|
|
8
|
+
|
|
9
|
+
| Forja | Commit |
|
|
10
|
+
| ----------------- | --------- |
|
|
11
|
+
| the-forge | `2f1d8bf` |
|
|
12
|
+
| spark-forge-aws | `b554143` |
|
|
13
|
+
| spark-forge-azure | `2063dc5` |
|
|
14
|
+
| api-forge | `7fcdf12` |
|
|
15
|
+
| platform-forge | `9ace433` |
|
|
16
|
+
| forge-doctor-api | `b927742` |
|
|
17
|
+
| forge-doctor-data | `3ac1cae` |
|
|
18
|
+
| forge-portal | `d0b6ba9` |
|
|
19
|
+
|
|
20
|
+
## Métodos de instalação do forge-cli
|
|
21
|
+
|
|
22
|
+
- **git** (default) — clone + bootstrap `setup.sh`/`setup.ps1` +
|
|
23
|
+
instalador nativo sob opt-in (`--native`, `--profile`, `--scope`,
|
|
24
|
+
`--components`). É o fluxo descrito na matriz abaixo.
|
|
25
|
+
- **registry** — `install <forja> --method registry`: resolve a dist no
|
|
26
|
+
PyPI, cria venv isolada em `~/.forge-cli/forges/<nome>/venv`, baixa a
|
|
27
|
+
wheel para `~/.forge-cli/cache/wheels/`, confere sha256 contra o
|
|
28
|
+
digest publicado e instala pelo caminho do artefato verificado.
|
|
29
|
+
`uninstall --method registry` remove venv + wheel cache + receipt com
|
|
30
|
+
confirmação; `--plan`, `--offline`, `--clean`, `--version` pinado,
|
|
31
|
+
`--json` e `--report` são honrados. `--native` delega ao instalador
|
|
32
|
+
nativo **da venv** (dry-run sem `--yes`; `--profile`/`--scope`/
|
|
33
|
+
`--components`/`--host`/`--gateway-profile` passam adiante);
|
|
34
|
+
Forjas cujo instalador é script de repositório (forge-doctor-api)
|
|
35
|
+
recebem skip honesto — a wheel não carrega o script.
|
|
36
|
+
- **lifecycle registry** — `update` (mais nova no PyPI; `--check` só
|
|
37
|
+
planeja; respeita pin), `reinstall` (mesma versão do receipt — reparo
|
|
38
|
+
de drift), `rollback` (desempilha `history` do receipt; rollback de
|
|
39
|
+
rollback funciona), `pin`/`unpin` (trava a versão instalada no state).
|
|
40
|
+
Tudo com o mesmo contrato: receipts atômicos, `--json`/`--report`,
|
|
41
|
+
flags git ignoradas avisadas, nomes desconhecidos → exit 2, falhas → 1.
|
|
42
|
+
- **hosts/MCP sem clone** — `forge-cli mcp <forja>` resolve o argv MCP
|
|
43
|
+
(forge.json do clone ou template `mcp` do catálogo + receipt:
|
|
44
|
+
`{bin}` = bin da venv, `{binDir}/x` = script irmão); `--verify` roda
|
|
45
|
+
`--version` como handshake. `hosts plan|register|validate|rollback`
|
|
46
|
+
usam o mesmo descritor — `hosts register` grava `mcpServers` apontando
|
|
47
|
+
para o binário da venv registry.
|
|
48
|
+
- **portal** — `GET /api/v1/registry/state` no forge-portal projeta
|
|
49
|
+
`~/.forge-cli/forges/state.json` (contrato
|
|
50
|
+
`docs/registry-state-contract.md`).
|
|
51
|
+
|
|
52
|
+
## Matriz registry (PyPI)
|
|
53
|
+
|
|
54
|
+
| Forja | Dist PyPI | Piso Python | MCP (venv) | Nativo `--native` |
|
|
55
|
+
| ----------------- | ------------------- | ----------- | ---------------------------- | --------------------------- |
|
|
56
|
+
| the-forge | `theforge-core` | >=3.11 | — (sem mcp_command) | `theforge install apply` |
|
|
57
|
+
| api-forge | `apiforge-af` | >=3.12 | `apiforge-mcp` | `apiforge install` |
|
|
58
|
+
| platform-forge | `platformforge` | >=3.10 | `platformforge-mcp` | `platformforge install` |
|
|
59
|
+
| spark-forge-aws | `sparkforge-aws` | >=3.10 | `sparkforge-aws mcp serve` | `sparkforge-aws install` |
|
|
60
|
+
| spark-forge-azure | `sparkforge-azure` | >=3.10 | `sparkforge-azure mcp serve` | `sparkforge-azure install` |
|
|
61
|
+
| forge-doctor-data | `forge-doctor-data` | >=3.11 | `forge-doctor-data mcp` | `forge-doctor-data install` |
|
|
62
|
+
| forge-doctor-api | `forge-doctor-api` | >=3.11 | `forge-doctor-api mcp` | **não** (script de repo) |
|
|
63
|
+
|
|
64
|
+
`requires_python` publicado no PyPI é autoritativo por release; o piso da
|
|
65
|
+
tabela compõe com ele (o mais restritivo vence).
|
|
66
|
+
|
|
67
|
+
## Modelo de instalação em duas fases
|
|
68
|
+
|
|
69
|
+
1. **Bootstrap** — `setup.sh` / `setup.ps1` (todas as Forjas Python) chamam
|
|
70
|
+
`scripts/forge_bootstrap.py`. Aceita apenas: `--dry-run --editable
|
|
71
|
+
--extras --install-dir --no-deps --no-launcher --python --quiet --repo
|
|
72
|
+
--upgrade --version --allow-download` (`--persist-env` em api-forge).
|
|
73
|
+
**Não** aceita perfil, escopo ou componentes.
|
|
74
|
+
2. **Instalador nativo do produto** — CLI da própria Forja, após o bootstrap:
|
|
75
|
+
`<cli> install [--scope project|workspace|user] [--profile
|
|
76
|
+
minimal|recommended|full] [--components ...] [--host claude|devin|codex|copilot|all]
|
|
77
|
+
[--gateway-profile economy|balanced|deep] [--dry-run] [--yes]`, além de
|
|
78
|
+
`install doctor`.
|
|
79
|
+
|
|
80
|
+
O forge-cli executa a fase 1 por padrão (comportamento histórico). A fase 2 só
|
|
81
|
+
roda quando o usuário passa `--profile`, `--scope` ou `--components`, e sempre
|
|
82
|
+
com `--dry-run`, a menos que `--yes` seja informado.
|
|
83
|
+
|
|
84
|
+
## Matriz
|
|
85
|
+
|
|
86
|
+
| Capacidade | the-forge | spark-forge-aws | spark-forge-azure | api-forge | platform-forge | forge-doctor-api | forge-doctor-data | forge-portal |
|
|
87
|
+
| ------------------------------- | ------------------------ | ------------------------------- | -------------------------- | -------------------------- | ----------------------- | ---------------------------------------------------- | --------------------------- | ------------ |
|
|
88
|
+
| Clone Git | sim | sim | sim | sim | sim | sim | sim | sim |
|
|
89
|
+
| Bootstrap Windows | `setup.ps1` | `setup.ps1` | `setup.ps1` | `setup.ps1`, `install.ps1` | `setup.ps1` | `setup.ps1` | `setup.ps1` | — (npm) |
|
|
90
|
+
| Bootstrap Linux/macOS | `setup.sh` | `setup.sh` | `setup.sh` | `setup.sh`, `install.sh` | `setup.sh` | `setup.sh` | `setup.sh` | — (npm) |
|
|
91
|
+
| Instalador nativo (CLI) | `theforge install apply` | `sparkforge-aws install` | `sparkforge-azure install` | `apiforge install` | `platformforge install` | `scripts/forge_install.py install` (script, não CLI) | `forge-doctor-data install` | não |
|
|
92
|
+
| `--profile` | sim | sim | sim | sim | sim | sim (script) | sim | não |
|
|
93
|
+
| `--scope` | sim | sim | sim | sim | sim | sim (script) | sim | não |
|
|
94
|
+
| `--components` | sim | sim | sim | sim | sim | sim (script) | sim | não |
|
|
95
|
+
| Skills / agents / MCP | via instalador nativo | via instalador nativo | via instalador nativo | via instalador nativo | via instalador nativo | via `theforge install auto` | via instalador nativo | não |
|
|
96
|
+
| Perfis minimal/recommended/full | sim | sim | sim | sim | sim | **não verificado** | sim | não |
|
|
97
|
+
| Escopo workspace/user | sim | sim | sim | sim | sim | **não verificado** | sim | não |
|
|
98
|
+
| Doctor | `theforge doctor` | `sparkforge-aws install doctor` | **não verificado** | `apiforge doctor` | `platformforge doctor` | **não verificado** | **não verificado** | não |
|
|
99
|
+
| Atualização nativa | **não verificado** | **não verificado** | **não verificado** | `--upgrade` (bootstrap) | **não verificado** | **não verificado** | **não verificado** | `npm` |
|
|
100
|
+
| Desinstalação nativa | **não verificado** | **não verificado** | **não verificado** | **não verificado** | **não verificado** | **não verificado** | **não verificado** | não |
|
|
101
|
+
|
|
102
|
+
## Operações nativas de ciclo de vida (confirmadas no código)
|
|
103
|
+
|
|
104
|
+
Segunda inspeção (leitura do parser de cada instalador). Todas aceitam
|
|
105
|
+
`--dry-run`; **nenhuma** das operações abaixo aceita `--yes` (aplicam quando
|
|
106
|
+
`--dry-run` está ausente). O forge-cli só as aciona com `--native`.
|
|
107
|
+
|
|
108
|
+
| Forja | update | uninstall |
|
|
109
|
+
| ----------------- | ---------------------------------- | ------------------------------------- |
|
|
110
|
+
| the-forge | `theforge install update` | `theforge install uninstall` |
|
|
111
|
+
| spark-forge-aws | `sparkforge-aws update` | `sparkforge-aws uninstall` |
|
|
112
|
+
| spark-forge-azure | `sparkforge-azure install update` | `sparkforge-azure install uninstall` |
|
|
113
|
+
| api-forge | `apiforge install update` | `apiforge install uninstall` |
|
|
114
|
+
| platform-forge | `platformforge upgrade` | `platformforge uninstall` |
|
|
115
|
+
| forge-doctor-data | `forge-doctor-data install update` | `forge-doctor-data install uninstall` |
|
|
116
|
+
| forge-doctor-api | não verificado | não verificado |
|
|
117
|
+
| forge-portal | — | — |
|
|
118
|
+
|
|
119
|
+
Regras do forge-cli: sem `--yes`, `update --native` roda a operação com
|
|
120
|
+
`--dry-run`; `uninstall --native --yes` executa a desinstalação nativa
|
|
121
|
+
**antes** de remover o clone e preserva o clone se ela falhar.
|
|
122
|
+
|
|
123
|
+
## Flags adicionais do instalador nativo
|
|
124
|
+
|
|
125
|
+
| Forja | `--host` | `--gateway-profile` |
|
|
126
|
+
| ----------------- | -------------- | ------------------- |
|
|
127
|
+
| the-forge | sim | não verificado |
|
|
128
|
+
| spark-forge-aws | sim | sim |
|
|
129
|
+
| spark-forge-azure | sim | sim |
|
|
130
|
+
| api-forge | sim | sim |
|
|
131
|
+
| platform-forge | não verificado | não verificado |
|
|
132
|
+
| forge-doctor-data | não verificado | sim |
|
|
133
|
+
|
|
134
|
+
`forge-doctor-api` passou a usar o script documentado
|
|
135
|
+
`python scripts/forge_install.py install` (interpretador resolvido entre
|
|
136
|
+
`python3`, `python` e `py -3`).
|
|
137
|
+
|
|
138
|
+
Notas:
|
|
139
|
+
|
|
140
|
+
- A presença de `--scope`/`--profile`/`--components` foi confirmada no código
|
|
141
|
+
do parser de cada instalador (`install/service.py`, `cmd_install.py`,
|
|
142
|
+
`cli_install.py`, `install/cli.py`, `portable_cli.py`, `install_cmd.py`,
|
|
143
|
+
`scripts/forge_install.py`). Os valores aceitos vieram de `choices=` no
|
|
144
|
+
código.
|
|
145
|
+
- `forge-doctor-api` não expõe `install` como subcomando da CLI instalada na
|
|
146
|
+
documentação inspecionada; o fluxo documentado é `python scripts/forge_install.py
|
|
147
|
+
install` ou `theforge install auto --scope workspace`. Por isso o catálogo
|
|
148
|
+
**não** declara instalador nativo para ela (o forge-cli não simula suporte).
|
|
149
|
+
- `forge-portal` é Angular/Node: sem `setup.*`; o forge-cli usa `npm ci`/`npm
|
|
150
|
+
install` conforme a presença de `package-lock.json`.
|
|
151
|
+
- Atualização e desinstalação nativas não foram confirmadas; o forge-cli
|
|
152
|
+
atualiza o checkout Git (`update`) e remove clones limpos com backup
|
|
153
|
+
(`uninstall`), sem executar desinstaladores de terceiros.
|
|
154
|
+
- Cada repositório já possui `forge.json` (id, CLI, comando MCP). Pode ser
|
|
155
|
+
consumido opcionalmente no futuro, nunca como requisito.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Contrato de estado registry — `forge-cli/RegistryState/v1`
|
|
2
|
+
|
|
3
|
+
Fonte única do formato que `forge-cli` escreve e que leitores externos
|
|
4
|
+
(forge-portal, scripts, hosts) podem consumir. O CLI é o único escritor;
|
|
5
|
+
leitores são somente-leitura e nunca inventam campos.
|
|
6
|
+
|
|
7
|
+
## Arquivos
|
|
8
|
+
|
|
9
|
+
| Arquivo | Conteúdo | Escrita |
|
|
10
|
+
| ----------------------------------------- | ----------------------------------------------------- | --------------------------- |
|
|
11
|
+
| `~/.forge-cli/forges/state.json` | Índice agregado `{ "forges": { <nome>: <receipt> } }` | atômica (`writeFileAtomic`) |
|
|
12
|
+
| `~/.forge-cli/forges/<nome>/receipt.json` | Receipt por Forja | atômica |
|
|
13
|
+
| `~/.forge-cli/forges/<nome>/install.json` | Metadados da instalação ativa | atômica |
|
|
14
|
+
| `~/.forge-cli/forges/state.json.corrupt` | Backup quando o state não parseia | rename |
|
|
15
|
+
|
|
16
|
+
`~` = `os.homedir()` do processo CLI (override de testes: `home` explícito
|
|
17
|
+
nas APIs; o portal honra `FORGE_HOME_OVERRIDE`).
|
|
18
|
+
|
|
19
|
+
## `state.json`
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"forges": {
|
|
24
|
+
"<nome-da-forja>": { "<receipt>" }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Chaves são nomes de Forja validados por `isSafeRepoName`
|
|
30
|
+
(`[a-z0-9][a-z0-9-]*`, sem `..`, `/`, `\`) — leitores podem confiar que
|
|
31
|
+
chaves não carregam traversal.
|
|
32
|
+
- Valores não-objeto são filtrados na leitura (state poisoned degrada
|
|
33
|
+
para ausência, nunca crash).
|
|
34
|
+
|
|
35
|
+
## Receipt (por Forja)
|
|
36
|
+
|
|
37
|
+
| Campo | Tipo | Semântica |
|
|
38
|
+
| ---------------- | --------------------------- | ------------------------------------ |
|
|
39
|
+
| `forge` | string | nome da Forja |
|
|
40
|
+
| `method` | `"registry"` | método de instalação |
|
|
41
|
+
| `dist` | string | distribuição PyPI instalada |
|
|
42
|
+
| `version` | string | versão resolvida (PEP 440) |
|
|
43
|
+
| `requiresPython` | string? | spec do release (PyPI) |
|
|
44
|
+
| `python` | string | interpretador usado na venv |
|
|
45
|
+
| `source` | string | `pypi` ou `offline-cache` |
|
|
46
|
+
| `venv` | string | path absoluto da venv |
|
|
47
|
+
| `bin` | string | path absoluto do console script |
|
|
48
|
+
| `installedAt` | string | ISO 8601 |
|
|
49
|
+
| `verifiedHash` | string | `sha256:<hex>` do artefato instalado |
|
|
50
|
+
| `verify.ok` | bool | pós-install `<bin> --help` passou |
|
|
51
|
+
| `files` | string[] | artefatos gravados (bounded) |
|
|
52
|
+
| `yanked` | bool | release marcada yanked no PyPI |
|
|
53
|
+
| `staleCache` | bool | metadados vieram de cache expirado |
|
|
54
|
+
| `pinned` | string? | pin ativo (`pin --method registry`) |
|
|
55
|
+
| `history` | `{version, installedAt}[]`? | versões anteriores (rollback) |
|
|
56
|
+
|
|
57
|
+
Campos novos podem aparecer em versões futuras do CLI — leitores devem
|
|
58
|
+
tolerar campos desconhecidos e tratar campos conhecidos ausentes como
|
|
59
|
+
`null`/não-presentes.
|
|
60
|
+
|
|
61
|
+
## Leitura (forge-portal)
|
|
62
|
+
|
|
63
|
+
`portal_core.forge_portal.read_registry_state()` projeta o state em
|
|
64
|
+
`forge-cli/RegistryState/v1`:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"schema": "forge-cli/RegistryState/v1",
|
|
69
|
+
"state_path": "...",
|
|
70
|
+
"present": true,
|
|
71
|
+
"forges": { "<nome>": { "<receipt projetado>" } }
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `present: false` (+ `error: "malformed"` quando aplicável) se o
|
|
76
|
+
arquivo não existir, não parsear ou `forges` não for objeto —
|
|
77
|
+
o portal renderiza "não instalado", nunca um receipt inventado.
|
|
78
|
+
- `GET /api/v1/registry/state` expõe a mesma projeção (somente-leitura,
|
|
79
|
+
host loopback + sessão, como toda a API do portal).
|
|
80
|
+
- Projeção é whitelist de escalares/containers pequenos — nada de
|
|
81
|
+
objetos arbitrários vindos do disco.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Solução de problemas
|
|
2
|
+
|
|
3
|
+
Falhas comuns do forge-cli e como resolver cada uma.
|
|
4
|
+
|
|
5
|
+
## O preflight falha
|
|
6
|
+
|
|
7
|
+
O preflight roda antes de qualquer prompt e encerra com código `1`
|
|
8
|
+
quando algo falta:
|
|
9
|
+
|
|
10
|
+
| Falha | Causa | Correção |
|
|
11
|
+
| ----------------------------- | ----------------------------------- | ------------------------------------------------------ |
|
|
12
|
+
| `git` indisponível | Git não instalado ou fora do `PATH` | Instale o Git e abra um terminal novo |
|
|
13
|
+
| `Node.js >= 20` falha | Versão antiga | Atualize via [nodejs.org](https://nodejs.org) ou `nvm` |
|
|
14
|
+
| `powershell.exe` indisponível | Somente Windows; fora do `PATH` | Reinstale o PowerShell ou ajuste o `PATH` |
|
|
15
|
+
|
|
16
|
+
## Falha no clone/pull (`[ERRO]`)
|
|
17
|
+
|
|
18
|
+
- **Autenticação**: os repositórios são privados. Confirme que suas
|
|
19
|
+
credenciais do Git funcionam — teste `git clone` manualmente em um
|
|
20
|
+
repositório da organização.
|
|
21
|
+
- **Rede/VPN**: verifique acesso a `github.com`.
|
|
22
|
+
- **Pull com alterações locais**: se a pasta já existe e tem
|
|
23
|
+
modificações, o `git pull` pode falhar. Resolva dentro da pasta do
|
|
24
|
+
repositório e rode o CLI de novo — ele retoma normalmente.
|
|
25
|
+
|
|
26
|
+
## Falha ao provisionar `.env`
|
|
27
|
+
|
|
28
|
+
- **Permissão de escrita**: o diretório de destino precisa permitir
|
|
29
|
+
escrita. No Windows, evite pastas protegidas (por exemplo,
|
|
30
|
+
`C:\Program Files`).
|
|
31
|
+
- O erro no `.env` **pula o script de instalação** daquele
|
|
32
|
+
repositório de propósito: corrija a causa e rode de novo.
|
|
33
|
+
|
|
34
|
+
## O script de instalação falha
|
|
35
|
+
|
|
36
|
+
- **Windows**: o CLI executa
|
|
37
|
+
`powershell.exe -NoProfile -ExecutionPolicy Bypass -File install.ps1`.
|
|
38
|
+
Se a política de execução estiver restrita demais ou o PowerShell for
|
|
39
|
+
o Core (`pwsh`), ajuste o script ou o ambiente.
|
|
40
|
+
- **Linux/macOS**: o CLI executa `chmod +x install.sh && ./install.sh`.
|
|
41
|
+
Confirme que o script é válido para o seu shell.
|
|
42
|
+
- **Sem script para o SO**: o repositório sai como `[AVISO]`, não
|
|
43
|
+
`[ERRO]` — isso é esperado quando o repo não publica script para a
|
|
44
|
+
sua plataforma.
|
|
45
|
+
|
|
46
|
+
## Os scripts não rodaram (aviso de sync ou de repositório customizado)
|
|
47
|
+
|
|
48
|
+
- `Scripts não executados após falha de sincronização`: o pull falhou, o
|
|
49
|
+
branch divergiu ou o remote difere do catálogo. Resolva o repositório ou
|
|
50
|
+
reexecute com `--run-after-sync-failure`.
|
|
51
|
+
- `Repositório customizado: scripts não executados`: repositórios vindos de
|
|
52
|
+
`forge-cli.repos.json` exigem `--trust-custom`.
|
|
53
|
+
- `Working tree com alterações locais` ao usar `--ref`/`--version`: faça
|
|
54
|
+
commit ou stash antes de trocar de revisão.
|
|
55
|
+
|
|
56
|
+
## O spinner trava ou a saída quebra
|
|
57
|
+
|
|
58
|
+
- Use um terminal moderno (Windows Terminal, VS Code, ou similar). O
|
|
59
|
+
Prompt de Comando legado pode não renderizar cores/Unicode.
|
|
60
|
+
- Scripts de instalação interativos (que pedem input) podem travar —
|
|
61
|
+
prefira scripts não interativos nos repositórios.
|
|
62
|
+
|
|
63
|
+
## `Ctrl+C` durante a execução
|
|
64
|
+
|
|
65
|
+
- Nos prompts: `Ctrl+C` cancela de forma limpa.
|
|
66
|
+
- Durante clone/script: `SIGINT` encerra com código `130`. O `execa`
|
|
67
|
+
encerra o subprocesso filho junto; uma pasta parcialmente clonada
|
|
68
|
+
pode sobrar — o próximo run faz `git pull` se o `.git` existir, ou
|
|
69
|
+
`git clone` falha se a pasta existe sem `.git` (apague a pasta
|
|
70
|
+
parcial nesse caso).
|
|
71
|
+
|
|
72
|
+
## `npm install` avisa sobre esbuild
|
|
73
|
+
|
|
74
|
+
Em ambientes com `allowScripts` restritivo, o postinstall do esbuild é
|
|
75
|
+
bloqueado — **o build continua funcionando**, porque os binários de
|
|
76
|
+
plataforma vêm como dependências opcionais. Se o `tsup` falhar com
|
|
77
|
+
erro de binário esbuild, rode
|
|
78
|
+
`npm install-scripts approve esbuild` e reinstale.
|
|
79
|
+
|
|
80
|
+
## Dependências e versões
|
|
81
|
+
|
|
82
|
+
- `execa` é fixado em `^9` por decisão de spec — não atualize sem uma
|
|
83
|
+
spec nova.
|
|
84
|
+
- `vitest` é `^5` para evitar vulnerabilidades do `tinypool` (ver
|
|
85
|
+
`npm audit`).
|
package/package.json
CHANGED
|
@@ -1,6 +1,73 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theforge-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "CLI interativa para clonar e configurar o ecossistema Forge",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"forge-cli": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md",
|
|
15
|
+
"CHANGELOG.md",
|
|
16
|
+
"docs/*.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "tsx src/index.ts",
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"start": "node dist/index.js",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"format": "prettier --write .",
|
|
26
|
+
"format:check": "prettier --check .",
|
|
27
|
+
"lint": "eslint .",
|
|
28
|
+
"coverage": "vitest run --coverage",
|
|
29
|
+
"prepublishOnly": "npm run typecheck && npm test && npm run build",
|
|
30
|
+
"pack": "npm pack --dry-run"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@clack/prompts": "^1.8.1",
|
|
34
|
+
"execa": "^9.0.0",
|
|
35
|
+
"figlet": "^1.9.0",
|
|
36
|
+
"picocolors": "^1.1.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@eslint/js": "^10.0.1",
|
|
40
|
+
"@types/node": "^24.0.0",
|
|
41
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
42
|
+
"eslint": "^10.12.0",
|
|
43
|
+
"prettier": "^3.9.9",
|
|
44
|
+
"tsup": "^8.0.0",
|
|
45
|
+
"tsx": "^4.0.0",
|
|
46
|
+
"typescript": "^5.6.0",
|
|
47
|
+
"typescript-eslint": "^8.71.1",
|
|
48
|
+
"vitest": "^5.0.3"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/EdgarSocrates98/forge-cli.git"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/EdgarSocrates98/forge-cli#readme",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/EdgarSocrates98/forge-cli/issues"
|
|
57
|
+
},
|
|
58
|
+
"keywords": [
|
|
59
|
+
"forge",
|
|
60
|
+
"cli",
|
|
61
|
+
"installer",
|
|
62
|
+
"git",
|
|
63
|
+
"agents",
|
|
64
|
+
"skills",
|
|
65
|
+
"mcp"
|
|
66
|
+
],
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public",
|
|
69
|
+
"provenance": true
|
|
70
|
+
},
|
|
71
|
+
"license": "MIT",
|
|
72
|
+
"author": "Edgar Sócrates Caria"
|
|
73
|
+
}
|