kaven-cli 0.3.0 → 0.3.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/README.md +147 -84
- package/README.pt-BR.md +334 -0
- package/dist/core/ModuleDoctor.js +4 -4
- package/dist/core/ProjectInitializer.js +39 -2
- package/dist/core/SignatureVerifier.js +7 -4
- package/dist/index.js +0 -0
- package/package.json +9 -3
- package/dist/commands/modules/add.js +0 -53
- package/dist/commands/modules/list.js +0 -40
- package/dist/commands/modules/remove.js +0 -54
- package/dist/core/api/KavenApiClient.js +0 -61
- package/dist/core/auth/AuthManager.js +0 -91
- package/dist/core/modules/Injector.js +0 -86
- package/dist/core/modules/ModuleInstaller.js +0 -63
- package/dist/core/modules/ModuleManager.js +0 -59
- package/dist/core/modules/ModuleRemover.js +0 -60
- package/dist/lib/config.js +0 -66
- package/dist/lib/errors.js +0 -32
- package/dist/lib/logger.js +0 -70
- package/dist/types/module.js +0 -49
package/README.pt-BR.md
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# Kaven CLI
|
|
2
|
+
|
|
3
|
+
> 📖 English version: [README.md](./README.md)
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/kaven-cli)
|
|
6
|
+
[](https://www.npmjs.com/package/kaven-cli)
|
|
7
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
8
|
+
[](https://nodejs.org)
|
|
9
|
+
[](https://github.com/kaven-co/kaven-cli/actions/workflows/ci.yml)
|
|
10
|
+
|
|
11
|
+
A CLI oficial do [Kaven](https://kaven.site) — boilerplate enterprise-grade para SaaS.
|
|
12
|
+
Bootstrap de projetos, gerenciamento de módulos e integração com o Kaven Marketplace diretamente pelo terminal.
|
|
13
|
+
|
|
14
|
+
O Kaven é um projeto brasileiro. O boilerplate comprime de 3-6 meses para dias o trabalho de infraestrutura base de um SaaS (auth, multi-tenancy, pagamentos, design system).
|
|
15
|
+
|
|
16
|
+
> **Alpha:** APIs e comandos podem mudar antes da v1.0.0.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Instalação
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -g kaven-cli@alpha
|
|
24
|
+
# ou
|
|
25
|
+
pnpm add -g kaven-cli@alpha
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Requisitos:** Node.js >= 20, pnpm (necessário para o `kaven init`)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Início Rápido
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# 1. Bootstrap de um novo projeto
|
|
36
|
+
kaven init meu-saas
|
|
37
|
+
|
|
38
|
+
# 2. Autenticar com o marketplace
|
|
39
|
+
kaven auth login
|
|
40
|
+
|
|
41
|
+
# 3. Explorar módulos disponíveis
|
|
42
|
+
kaven marketplace browse
|
|
43
|
+
|
|
44
|
+
# 4. Instalar um módulo
|
|
45
|
+
kaven marketplace install payments
|
|
46
|
+
|
|
47
|
+
# 5. Verificar saúde do projeto
|
|
48
|
+
kaven module doctor
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Referência de Comandos
|
|
54
|
+
|
|
55
|
+
### `kaven init [nome-do-projeto]`
|
|
56
|
+
|
|
57
|
+
Cria um novo projeto Kaven a partir do template oficial.
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Opções:
|
|
61
|
+
--defaults Pular prompts interativos, usar valores padrão
|
|
62
|
+
--skip-install Pular o pnpm install após o setup
|
|
63
|
+
--skip-git Pular git init e commit inicial
|
|
64
|
+
--force Sobrescrever diretório existente
|
|
65
|
+
--with-squad Inicializar squad AIOX no projeto
|
|
66
|
+
|
|
67
|
+
Exemplos:
|
|
68
|
+
kaven init meu-app
|
|
69
|
+
kaven init meu-app --defaults
|
|
70
|
+
kaven init meu-app --skip-git --skip-install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### `kaven auth`
|
|
76
|
+
|
|
77
|
+
Gerenciar autenticação com o Kaven Marketplace.
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
Subcomandos:
|
|
81
|
+
login Iniciar fluxo de device code (RFC 8628) — abre o navegador para confirmar
|
|
82
|
+
logout Encerrar a sessão local
|
|
83
|
+
whoami Exibir informações do usuário autenticado
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### `kaven marketplace`
|
|
89
|
+
|
|
90
|
+
Explorar e instalar módulos do Kaven Marketplace.
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
Subcomandos:
|
|
94
|
+
list Listar módulos disponíveis
|
|
95
|
+
install Baixar e aplicar um módulo no projeto atual
|
|
96
|
+
browse Navegador interativo (TUI)
|
|
97
|
+
|
|
98
|
+
Opções (list):
|
|
99
|
+
--category <cat> Filtrar por categoria
|
|
100
|
+
--sort <campo> newest (padrão) | popular | name
|
|
101
|
+
--page <n> Número da página
|
|
102
|
+
--limit <n> Resultados por página (máx 100)
|
|
103
|
+
--json Saída em JSON bruto
|
|
104
|
+
|
|
105
|
+
Opções (install):
|
|
106
|
+
--version <ver> Instalar uma versão específica
|
|
107
|
+
--force Pular confirmação de sobrescrita
|
|
108
|
+
--skip-env Pular injeção no .env
|
|
109
|
+
--env-file <path> Caminho do .env alvo
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### `kaven module`
|
|
115
|
+
|
|
116
|
+
Gerenciar módulos instalados no projeto atual.
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Subcomandos:
|
|
120
|
+
doctor Executar health checks no projeto e nos módulos instalados
|
|
121
|
+
add Instalar um módulo a partir de um manifest local
|
|
122
|
+
remove Desinstalar um módulo instalado
|
|
123
|
+
publish Publicar um módulo no marketplace
|
|
124
|
+
|
|
125
|
+
Opções (doctor):
|
|
126
|
+
--fix Corrigir problemas automaticamente (pnpm install, prisma generate, env vars)
|
|
127
|
+
--json Saída em JSON legível por máquina
|
|
128
|
+
|
|
129
|
+
Exit codes (doctor):
|
|
130
|
+
0 Todos os checks passaram
|
|
131
|
+
1 Um ou mais erros encontrados
|
|
132
|
+
2 Apenas avisos (sem erros)
|
|
133
|
+
|
|
134
|
+
Opções (publish):
|
|
135
|
+
--dry-run Validar e empacotar sem fazer upload
|
|
136
|
+
--changelog <msg> Notas de release para esta versão
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
> `kaven doctor` é um alias para `kaven module doctor`.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### `kaven upgrade`
|
|
144
|
+
|
|
145
|
+
Fazer upgrade da licença via checkout Paddle.
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Opções:
|
|
149
|
+
--no-browser Imprimir URL do checkout em vez de abrir o navegador
|
|
150
|
+
|
|
151
|
+
Comportamento:
|
|
152
|
+
Abre o checkout Paddle no navegador → aguarda confirmação de pagamento (a cada 5s, máx 10 min)
|
|
153
|
+
→ atualiza a licença local em caso de sucesso
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### `kaven license`
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
Subcomandos:
|
|
162
|
+
status Exibir tier e validade da licença atual
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### `kaven cache`
|
|
168
|
+
|
|
169
|
+
Gerenciar o cache local de respostas da API (`~/.kaven/cache`, máx 50 MB).
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
Subcomandos:
|
|
173
|
+
status Exibir estatísticas do cache (tamanho, entradas, idade)
|
|
174
|
+
clear Apagar todos os dados em cache
|
|
175
|
+
|
|
176
|
+
TTLs do cache:
|
|
177
|
+
Listagem de módulos 24 horas
|
|
178
|
+
Manifests de módulos 7 dias
|
|
179
|
+
Status da licença 1 hora
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### `kaven telemetry`
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
Subcomandos:
|
|
188
|
+
view Exibir eventos de telemetria locais recentes
|
|
189
|
+
-l, --limit <n> Número de eventos (padrão: 10)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
### `kaven config`
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
Subcomandos:
|
|
198
|
+
set <chave> <valor> Definir um valor de configuração
|
|
199
|
+
get <chave> Ler um valor de configuração
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### `kaven init-ci`
|
|
205
|
+
|
|
206
|
+
Inicializa configuração de CI/CD no projeto atual. Gera workflows do GitHub Actions configurados para projetos Kaven.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Configuração
|
|
211
|
+
|
|
212
|
+
Toda a configuração fica em `~/.kaven/`:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
~/.kaven/
|
|
216
|
+
auth.json Tokens de autenticação (chmod 600)
|
|
217
|
+
config.json Configuração da CLI
|
|
218
|
+
license.json Chave e tier da licença
|
|
219
|
+
signing-key.json Chave Ed25519 para módulos (chmod 600)
|
|
220
|
+
cache/ Cache de respostas da API (máx 50 MB)
|
|
221
|
+
telemetry.log Eventos de telemetria locais
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Variáveis de Ambiente
|
|
225
|
+
|
|
226
|
+
| Variável | Descrição |
|
|
227
|
+
|----------|-----------|
|
|
228
|
+
| `KAVEN_API_URL` | Sobrescrever a URL da API do marketplace |
|
|
229
|
+
| `KAVEN_DEBUG=1` | Ativar saída de debug detalhada |
|
|
230
|
+
| `KAVEN_OFFLINE=1` | Usar apenas dados em cache, sem requisições de rede |
|
|
231
|
+
| `KAVEN_TELEMETRY=0` | Desativar telemetria completamente |
|
|
232
|
+
|
|
233
|
+
### Sobrescrever a URL da API (config file)
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
// ~/.kaven/config.json
|
|
237
|
+
{
|
|
238
|
+
"apiUrl": "https://api.seu-kaven.com"
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Modo Debug
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
KAVEN_DEBUG=1 kaven marketplace list
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Modo Offline
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
KAVEN_OFFLINE=1 kaven marketplace list
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Troubleshooting
|
|
257
|
+
|
|
258
|
+
**Erro "Not authenticated"**
|
|
259
|
+
```bash
|
|
260
|
+
kaven auth login
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**"module.json not found" ao publicar**
|
|
264
|
+
|
|
265
|
+
Execute `kaven module publish` de dentro do diretório do módulo (o que contém o `module.json`).
|
|
266
|
+
|
|
267
|
+
**pnpm install falha no `kaven init`**
|
|
268
|
+
```bash
|
|
269
|
+
npm install -g pnpm # instalar pnpm globalmente
|
|
270
|
+
# ou pular e instalar depois:
|
|
271
|
+
kaven init meu-app --skip-install
|
|
272
|
+
cd meu-app && pnpm install
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Prisma client desatualizado**
|
|
276
|
+
```bash
|
|
277
|
+
kaven module doctor --fix
|
|
278
|
+
# ou manualmente:
|
|
279
|
+
npx prisma generate
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Problemas de cache**
|
|
283
|
+
```bash
|
|
284
|
+
kaven cache clear
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Permission denied em `~/.kaven/`**
|
|
288
|
+
```bash
|
|
289
|
+
chmod 700 ~/.kaven
|
|
290
|
+
chmod 600 ~/.kaven/auth.json ~/.kaven/signing-key.json
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Contribuindo
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
git clone https://github.com/kaven-co/kaven-cli
|
|
299
|
+
cd kaven-cli
|
|
300
|
+
pnpm install
|
|
301
|
+
pnpm test # 310 testes
|
|
302
|
+
pnpm run typecheck
|
|
303
|
+
pnpm run lint
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Convenção de commits:** este repositório usa [Conventional Commits](https://www.conventionalcommits.org/).
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
feat: adicionar flag --with-squad ao kaven init
|
|
310
|
+
fix: corrigir corrupção de cache em escritas concorrentes
|
|
311
|
+
docs: atualizar seção de troubleshooting
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Fluxo de release:**
|
|
315
|
+
1. Abrir um PR contra `main`
|
|
316
|
+
2. CI deve estar verde (lint + typecheck + testes + build)
|
|
317
|
+
3. Merge → Semantic Release faz o bump de versão automaticamente e publica no npm (tag `@alpha`)
|
|
318
|
+
|
|
319
|
+
Tipos que disparam release: `feat` (minor), `fix` / `perf` / `refactor` (patch), `BREAKING CHANGE` (major).
|
|
320
|
+
Tipos que **não** disparam release: `chore`, `docs`, `test`, `style`, `ci`.
|
|
321
|
+
|
|
322
|
+
Consulte [`docs/releasing.md`](./docs/releasing.md) para a documentação completa do pipeline de release.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Licença
|
|
327
|
+
|
|
328
|
+
Apache 2.0 — veja [LICENSE](LICENSE)
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
Documentação: https://docs.kaven.site/cli
|
|
333
|
+
GitHub: https://github.com/kaven-co/kaven-cli
|
|
334
|
+
npm: https://www.npmjs.com/package/kaven-cli
|
|
@@ -28,9 +28,9 @@ class ModuleDoctor {
|
|
|
28
28
|
async checkAnchors() {
|
|
29
29
|
const results = [];
|
|
30
30
|
const expectedAnchors = [
|
|
31
|
-
{ file: "apps/api/src/
|
|
32
|
-
{ file: "apps/api/src/
|
|
33
|
-
{ file: "apps/
|
|
31
|
+
{ file: "apps/api/src/app.ts", anchor: "// [KAVEN_MODULE_IMPORTS]" },
|
|
32
|
+
{ file: "apps/api/src/app.ts", anchor: "// [KAVEN_MODULE_HOOKS]" },
|
|
33
|
+
{ file: "apps/api/src/app.ts", anchor: "// [KAVEN_MODULE_REGISTRATION]" },
|
|
34
34
|
];
|
|
35
35
|
for (const { file, anchor } of expectedAnchors) {
|
|
36
36
|
const filePath = path_1.default.join(this.projectRoot, file);
|
|
@@ -433,7 +433,7 @@ class ModuleDoctor {
|
|
|
433
433
|
return results;
|
|
434
434
|
}
|
|
435
435
|
async readKavenConfig() {
|
|
436
|
-
const configPath = path_1.default.join(this.projectRoot, "kaven.
|
|
436
|
+
const configPath = path_1.default.join(this.projectRoot, "kaven.json");
|
|
437
437
|
if (!(await fs_extra_1.default.pathExists(configPath))) {
|
|
438
438
|
return { modules: [] };
|
|
439
439
|
}
|
|
@@ -8,6 +8,7 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const child_process_1 = require("child_process");
|
|
10
10
|
const TEMPLATE_REPO = "https://github.com/kaven-co/kaven-template.git";
|
|
11
|
+
const KAVEN_SQUAD_REPO = "https://github.com/bychrisr/kaven-squad";
|
|
11
12
|
/** Run a shell command via spawn, returning exit code. */
|
|
12
13
|
function runCommand(cmd, args, cwd, onData) {
|
|
13
14
|
return new Promise((resolve, reject) => {
|
|
@@ -64,7 +65,7 @@ class ProjectInitializer {
|
|
|
64
65
|
const filesToProcess = [
|
|
65
66
|
"package.json",
|
|
66
67
|
".env.example",
|
|
67
|
-
"prisma/schema.prisma",
|
|
68
|
+
"packages/database/prisma/schema.prisma",
|
|
68
69
|
"apps/api/package.json",
|
|
69
70
|
"apps/admin/package.json",
|
|
70
71
|
"apps/tenant/package.json",
|
|
@@ -79,6 +80,15 @@ class ProjectInitializer {
|
|
|
79
80
|
}
|
|
80
81
|
await fs_extra_1.default.writeFile(filePath, content, "utf-8");
|
|
81
82
|
}
|
|
83
|
+
// Safety net: directly update root package.json name field regardless of placeholder
|
|
84
|
+
const pkgPath = path_1.default.join(targetDir, "package.json");
|
|
85
|
+
if (await fs_extra_1.default.pathExists(pkgPath)) {
|
|
86
|
+
const pkg = await fs_extra_1.default.readJson(pkgPath);
|
|
87
|
+
if (pkg.name !== values.projectName) {
|
|
88
|
+
pkg.name = values.projectName;
|
|
89
|
+
await fs_extra_1.default.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
82
92
|
}
|
|
83
93
|
/** Run pnpm install in the target directory. */
|
|
84
94
|
async runInstall(targetDir) {
|
|
@@ -93,11 +103,38 @@ class ProjectInitializer {
|
|
|
93
103
|
await runCommand("git", ["add", "."], targetDir);
|
|
94
104
|
await runCommand("git", ["commit", "-m", "chore: initial kaven setup"], targetDir);
|
|
95
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Clone kaven-squad into squads/kaven-squad/ inside the project.
|
|
108
|
+
* Returns { installed: true } on success, { installed: false, reason } on failure.
|
|
109
|
+
* Never throws — squad installation is non-fatal.
|
|
110
|
+
*/
|
|
111
|
+
async installSquad(targetDir) {
|
|
112
|
+
const squadsDir = path_1.default.join(targetDir, "squads");
|
|
113
|
+
const squadDir = path_1.default.join(squadsDir, "kaven-squad");
|
|
114
|
+
// Squad already present — skip
|
|
115
|
+
if (await fs_extra_1.default.pathExists(squadDir)) {
|
|
116
|
+
return { installed: false, reason: "already-exists" };
|
|
117
|
+
}
|
|
118
|
+
await fs_extra_1.default.ensureDir(squadsDir);
|
|
119
|
+
const exitCode = await runCommand("git", ["clone", "--depth", "1", KAVEN_SQUAD_REPO, squadDir], process.cwd());
|
|
120
|
+
if (exitCode !== 0) {
|
|
121
|
+
return {
|
|
122
|
+
installed: false,
|
|
123
|
+
reason: `git clone exited with code ${exitCode}`,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// Remove .git — squad history not needed in user project
|
|
127
|
+
const squadGitDir = path_1.default.join(squadDir, ".git");
|
|
128
|
+
if (await fs_extra_1.default.pathExists(squadGitDir)) {
|
|
129
|
+
await fs_extra_1.default.remove(squadGitDir);
|
|
130
|
+
}
|
|
131
|
+
return { installed: true };
|
|
132
|
+
}
|
|
96
133
|
/** Health check after project initialization. */
|
|
97
134
|
async healthCheck(targetDir) {
|
|
98
135
|
const issues = [];
|
|
99
136
|
// Check key files exist
|
|
100
|
-
const requiredFiles = ["package.json", ".env.example", "prisma/schema.prisma"];
|
|
137
|
+
const requiredFiles = ["package.json", ".env.example", "packages/database/prisma/schema.prisma"];
|
|
101
138
|
for (const file of requiredFiles) {
|
|
102
139
|
if (!(await fs_extra_1.default.pathExists(path_1.default.join(targetDir, file)))) {
|
|
103
140
|
issues.push(`Missing required file: ${file}`);
|
|
@@ -33,9 +33,8 @@ function decodeSignature(encoded) {
|
|
|
33
33
|
* Verify Ed25519 signature against a SHA-256 checksum.
|
|
34
34
|
*
|
|
35
35
|
* Accepts signature in either hex or base64 encoding.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* in the release metadata.
|
|
36
|
+
* Tolerates signatures made over checksum with trailing newline
|
|
37
|
+
* (common when signing via `echo checksum > file && openssl sign`).
|
|
39
38
|
*/
|
|
40
39
|
function verifyEd25519Signature(checksum, signature, publicKeyBase64) {
|
|
41
40
|
try {
|
|
@@ -45,7 +44,11 @@ function verifyEd25519Signature(checksum, signature, publicKeyBase64) {
|
|
|
45
44
|
format: "der",
|
|
46
45
|
});
|
|
47
46
|
const sigBuffer = decodeSignature(signature);
|
|
48
|
-
|
|
47
|
+
if (crypto_1.default.verify(null, Buffer.from(checksum), publicKey, sigBuffer)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
// Tolerate trailing newline from shell-based signing
|
|
51
|
+
return crypto_1.default.verify(null, Buffer.from(checksum + "\n"), publicKey, sigBuffer);
|
|
49
52
|
}
|
|
50
53
|
catch {
|
|
51
54
|
return false;
|
package/dist/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kaven-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Kaven CLI - The official command line tool for Kaven",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsc",
|
|
15
|
-
"prepublishOnly": "pnpm run build
|
|
15
|
+
"prepublishOnly": "pnpm run build",
|
|
16
16
|
"lint": "eslint 'src/**/*.{ts,tsx}' --max-warnings 0",
|
|
17
17
|
"lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix",
|
|
18
18
|
"test": "vitest run",
|
|
@@ -39,9 +39,14 @@
|
|
|
39
39
|
"license": "Apache-2.0",
|
|
40
40
|
"repository": {
|
|
41
41
|
"type": "git",
|
|
42
|
-
"url": "https://github.com/
|
|
42
|
+
"url": "https://github.com/kaven-co/kaven-cli"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
46
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
47
|
+
"@semantic-release/github": "^12.0.6",
|
|
48
|
+
"@semantic-release/npm": "^13.1.5",
|
|
49
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
45
50
|
"@types/fs-extra": "^11.0.4",
|
|
46
51
|
"@types/node": "^20.0.0",
|
|
47
52
|
"@types/tar": "^6.1.13",
|
|
@@ -49,6 +54,7 @@
|
|
|
49
54
|
"@typescript-eslint/parser": "^8.53.1",
|
|
50
55
|
"eslint": "^8.0.0",
|
|
51
56
|
"msw": "^2.12.10",
|
|
57
|
+
"semantic-release": "^25.0.3",
|
|
52
58
|
"typescript": "^5.0.0",
|
|
53
59
|
"vitest": "^1.0.0"
|
|
54
60
|
},
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.addCommand = void 0;
|
|
7
|
-
const commander_1 = require("commander");
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const ModuleManager_1 = require("../../core/modules/ModuleManager");
|
|
11
|
-
const ModuleInstaller_1 = require("../../core/modules/ModuleInstaller");
|
|
12
|
-
const logger_1 = require("../../lib/logger");
|
|
13
|
-
exports.addCommand = new commander_1.Command('add')
|
|
14
|
-
.description('Install a module')
|
|
15
|
-
.argument('<slug>', 'Module slug to install')
|
|
16
|
-
.action(async (slug) => {
|
|
17
|
-
try {
|
|
18
|
-
const projectRoot = process.cwd();
|
|
19
|
-
// Locate modules source:
|
|
20
|
-
// In dev: ./modules
|
|
21
|
-
// In prod (installed): ../modules relative to dist
|
|
22
|
-
// For now, assume we run from CLI root or use logic to find 'modules' folder.
|
|
23
|
-
// Ideally CLI should be installed in a way that 'modules' folder is known.
|
|
24
|
-
// Fallback logic for finding modules source:
|
|
25
|
-
// 1. Env var KAVEN_MODULES_PATH
|
|
26
|
-
// 2. Local ./modules
|
|
27
|
-
// 3. Resolve relative to __dirname (dist) -> ../modules
|
|
28
|
-
let modulesSource = process.env.KAVEN_MODULES_PATH;
|
|
29
|
-
if (!modulesSource) {
|
|
30
|
-
if (await fs_extra_1.default.pathExists(path_1.default.resolve('modules'))) {
|
|
31
|
-
modulesSource = path_1.default.resolve('modules');
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
modulesSource = path_1.default.resolve(__dirname, '../../modules');
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (!await fs_extra_1.default.pathExists(modulesSource)) {
|
|
38
|
-
logger_1.Logger.error(`Module source not found at ${modulesSource}`);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const manifestPath = path_1.default.join(modulesSource, slug, 'module.json');
|
|
42
|
-
if (!await fs_extra_1.default.pathExists(manifestPath)) {
|
|
43
|
-
logger_1.Logger.error(`Module ${slug} not found in catalog.`);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const manifest = await ModuleManager_1.ModuleManager.loadManifest(manifestPath);
|
|
47
|
-
await ModuleInstaller_1.ModuleInstaller.install(manifest, projectRoot, modulesSource);
|
|
48
|
-
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
logger_1.Logger.error('Failed to add module', error);
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.listCommand = void 0;
|
|
7
|
-
const commander_1 = require("commander");
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const ModuleManager_1 = require("../../core/modules/ModuleManager");
|
|
10
|
-
const logger_1 = require("../../lib/logger");
|
|
11
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
-
exports.listCommand = new commander_1.Command('list')
|
|
13
|
-
.description('List available modules')
|
|
14
|
-
.action(async () => {
|
|
15
|
-
try {
|
|
16
|
-
logger_1.Logger.startSpinner('Loading modules...');
|
|
17
|
-
// By default, Kaven CLI looks for modules in the current project's ./kaven-cli/modules
|
|
18
|
-
// OR internal modules directory. For dev/bootstrap, we use the local 'modules' dir relative to CWD or __dirname.
|
|
19
|
-
// Strategy:
|
|
20
|
-
// 1. Check local repo structure (dev mode): ./modules
|
|
21
|
-
// 2. Check installed structure (production): ../modules
|
|
22
|
-
const modulesPath = path_1.default.resolve('modules');
|
|
23
|
-
const modules = await ModuleManager_1.ModuleManager.listAvailableModules(modulesPath);
|
|
24
|
-
logger_1.Logger.stopSpinner();
|
|
25
|
-
if (modules.length === 0) {
|
|
26
|
-
logger_1.Logger.warn('No modules found in ' + modulesPath);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
logger_1.Logger.info(`Found ${modules.length} modules:`);
|
|
30
|
-
modules.forEach(mod => {
|
|
31
|
-
console.log('');
|
|
32
|
-
console.log(chalk_1.default.bold.cyan(mod.displayName) + ' ' + chalk_1.default.dim(`(${mod.slug})`));
|
|
33
|
-
console.log(chalk_1.default.white(mod.description));
|
|
34
|
-
console.log(chalk_1.default.dim(`Version: ${mod.version}`));
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
logger_1.Logger.error('Failed to list modules', error);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.removeCommand = void 0;
|
|
7
|
-
const commander_1 = require("commander");
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
-
const ModuleManager_1 = require("../../core/modules/ModuleManager");
|
|
11
|
-
const ModuleRemover_1 = require("../../core/modules/ModuleRemover");
|
|
12
|
-
const logger_1 = require("../../lib/logger");
|
|
13
|
-
exports.removeCommand = new commander_1.Command('remove')
|
|
14
|
-
.description('Remove a module')
|
|
15
|
-
.argument('<slug>', 'Module slug to remove')
|
|
16
|
-
.action(async (slug) => {
|
|
17
|
-
try {
|
|
18
|
-
const projectRoot = process.cwd();
|
|
19
|
-
// For removal, we need the manifest to know what to eject.
|
|
20
|
-
// We look for the installed module first?
|
|
21
|
-
// Doc 3: "The engine behaves as if it’s 'playing back' the manifest in reverse."
|
|
22
|
-
// We need the manifest. Where do we get it?
|
|
23
|
-
// Option A: From the installed module directory (if we copied the manifest there).
|
|
24
|
-
// Option B: From the store (but what if version changed?).
|
|
25
|
-
// Best practice: We should have copied module.json to the installed location.
|
|
26
|
-
// Current Installer (Phase 2) does NOT copy module.json to installed location explicitly (it copies `api` folder content).
|
|
27
|
-
// Let's check `ModuleInstaller.ts`:
|
|
28
|
-
// if (manifest.slug) -> copy `api` to `modules/slug`.
|
|
29
|
-
// Does `api` contain `module.json`? No, `module.json` is at root of module source.
|
|
30
|
-
// FIX REQUIRED: We should probably look up the manifest from the *store* (catalog) matching the installed version,
|
|
31
|
-
// OR we should store the manifest upon installation.
|
|
32
|
-
// For MVP (Phase 3), let's assume we can find the manifest in the same Store logic as `add`.
|
|
33
|
-
let modulesSource = process.env.KAVEN_MODULES_PATH;
|
|
34
|
-
if (!modulesSource) {
|
|
35
|
-
if (await fs_extra_1.default.pathExists(path_1.default.resolve('modules'))) {
|
|
36
|
-
modulesSource = path_1.default.resolve('modules');
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
modulesSource = path_1.default.resolve(__dirname, '../../modules');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const manifestPath = path_1.default.join(modulesSource, slug, 'module.json');
|
|
43
|
-
if (!await fs_extra_1.default.pathExists(manifestPath)) {
|
|
44
|
-
logger_1.Logger.error(`Module manifest not found in store for ${slug}. Cannot safely remove.`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
const manifest = await ModuleManager_1.ModuleManager.loadManifest(manifestPath);
|
|
48
|
-
await ModuleRemover_1.ModuleRemover.remove(manifest, projectRoot);
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
logger_1.Logger.error('Failed to remove module', error);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
});
|