aitk-cli 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/README.md +147 -0
- package/dist/bin/aitk.d.ts +3 -0
- package/dist/bin/aitk.d.ts.map +1 -0
- package/dist/bin/aitk.js +108 -0
- package/dist/bin/aitk.js.map +1 -0
- package/dist/commands/completions.d.ts +3 -0
- package/dist/commands/completions.d.ts.map +1 -0
- package/dist/commands/completions.js +244 -0
- package/dist/commands/completions.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +108 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +232 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +250 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +78 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +362 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +10 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/publish.d.ts +3 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +245 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/remove.d.ts +3 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +150 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/search.d.ts +3 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +77 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +177 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +3 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +178 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/team.d.ts +3 -0
- package/dist/commands/team.d.ts.map +1 -0
- package/dist/commands/team.js +236 -0
- package/dist/commands/team.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +311 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/core/api-client.d.ts +44 -0
- package/dist/core/api-client.d.ts.map +1 -0
- package/dist/core/api-client.js +111 -0
- package/dist/core/api-client.js.map +1 -0
- package/dist/core/auth.d.ts +12 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +48 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/config.d.ts +13 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +42 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/lockfile.d.ts +22 -0
- package/dist/core/lockfile.d.ts.map +1 -0
- package/dist/core/lockfile.js +75 -0
- package/dist/core/lockfile.js.map +1 -0
- package/dist/core/manifest.d.ts +12 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +57 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/resolver.d.ts +52 -0
- package/dist/core/resolver.d.ts.map +1 -0
- package/dist/core/resolver.js +108 -0
- package/dist/core/resolver.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/installers/base-installer.d.ts +19 -0
- package/dist/installers/base-installer.d.ts.map +1 -0
- package/dist/installers/base-installer.js +4 -0
- package/dist/installers/base-installer.js.map +1 -0
- package/dist/installers/config-installer.d.ts +10 -0
- package/dist/installers/config-installer.d.ts.map +1 -0
- package/dist/installers/config-installer.js +108 -0
- package/dist/installers/config-installer.js.map +1 -0
- package/dist/installers/hook-installer.d.ts +10 -0
- package/dist/installers/hook-installer.d.ts.map +1 -0
- package/dist/installers/hook-installer.js +41 -0
- package/dist/installers/hook-installer.js.map +1 -0
- package/dist/installers/mcp-installer.d.ts +14 -0
- package/dist/installers/mcp-installer.d.ts.map +1 -0
- package/dist/installers/mcp-installer.js +152 -0
- package/dist/installers/mcp-installer.js.map +1 -0
- package/dist/installers/skill-installer.d.ts +10 -0
- package/dist/installers/skill-installer.d.ts.map +1 -0
- package/dist/installers/skill-installer.js +41 -0
- package/dist/installers/skill-installer.js.map +1 -0
- package/dist/installers/template-installer.d.ts +16 -0
- package/dist/installers/template-installer.d.ts.map +1 -0
- package/dist/installers/template-installer.js +123 -0
- package/dist/installers/template-installer.js.map +1 -0
- package/dist/utils/logger.d.ts +66 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +211 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { exec } from 'node:child_process';
|
|
5
|
+
import { platform } from 'node:os';
|
|
6
|
+
import { getConfig } from '../core/config.js';
|
|
7
|
+
import { saveAuth, getAuth } from '../core/auth.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
// ── Constantes do Supabase ──────────────────────────────────────────────
|
|
10
|
+
const SUPABASE_URL = 'https://nxdcgmpvvyfgqerenxrx.supabase.co';
|
|
11
|
+
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im54ZGNnbXB2dnlmZ3FlcmVueHJ4Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzMwMjA4MDksImV4cCI6MjA4ODU5NjgwOX0.iT49b4UOLKmXPraadgNp3ejmrz7pjA3Gvc1sHO-lqqE';
|
|
12
|
+
// Tempo limite para aguardar o callback OAuth (em milissegundos)
|
|
13
|
+
const OAUTH_TIMEOUT_MS = 120_000;
|
|
14
|
+
// ── Página HTML que extrai o fragment do callback OAuth ────────────────
|
|
15
|
+
function buildCallbackHtml() {
|
|
16
|
+
return `<!DOCTYPE html>
|
|
17
|
+
<html lang="pt-BR">
|
|
18
|
+
<head>
|
|
19
|
+
<meta charset="UTF-8">
|
|
20
|
+
<title>AITK — Autenticacao</title>
|
|
21
|
+
<style>
|
|
22
|
+
body {
|
|
23
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
24
|
+
display: flex;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
align-items: center;
|
|
27
|
+
min-height: 100vh;
|
|
28
|
+
margin: 0;
|
|
29
|
+
background: #0a0a0a;
|
|
30
|
+
color: #fafafa;
|
|
31
|
+
}
|
|
32
|
+
.container {
|
|
33
|
+
text-align: center;
|
|
34
|
+
padding: 2rem;
|
|
35
|
+
}
|
|
36
|
+
.spinner {
|
|
37
|
+
width: 40px;
|
|
38
|
+
height: 40px;
|
|
39
|
+
border: 3px solid #333;
|
|
40
|
+
border-top-color: #0ea5e9;
|
|
41
|
+
border-radius: 50%;
|
|
42
|
+
animation: spin 0.8s linear infinite;
|
|
43
|
+
margin: 0 auto 1.5rem;
|
|
44
|
+
}
|
|
45
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
46
|
+
.success { color: #22c55e; }
|
|
47
|
+
.error { color: #ef4444; }
|
|
48
|
+
h1 { font-size: 1.5rem; font-weight: 600; }
|
|
49
|
+
p { color: #a1a1aa; margin-top: 0.5rem; }
|
|
50
|
+
</style>
|
|
51
|
+
</head>
|
|
52
|
+
<body>
|
|
53
|
+
<div class="container" id="content">
|
|
54
|
+
<div class="spinner"></div>
|
|
55
|
+
<h1>Autenticando...</h1>
|
|
56
|
+
<p>Aguarde enquanto processamos sua autenticacao.</p>
|
|
57
|
+
</div>
|
|
58
|
+
<script>
|
|
59
|
+
(function() {
|
|
60
|
+
// Extrai os tokens do fragment (#) da URL
|
|
61
|
+
var hash = window.location.hash.substring(1);
|
|
62
|
+
var params = new URLSearchParams(hash);
|
|
63
|
+
var accessToken = params.get('access_token');
|
|
64
|
+
var refreshToken = params.get('refresh_token');
|
|
65
|
+
|
|
66
|
+
if (!accessToken) {
|
|
67
|
+
document.getElementById('content').innerHTML =
|
|
68
|
+
'<h1 class="error">Erro na autenticacao</h1>' +
|
|
69
|
+
'<p>Nenhum token encontrado. Tente novamente.</p>';
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Envia os tokens de volta ao servidor local via POST
|
|
74
|
+
fetch('/callback', {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers: { 'Content-Type': 'application/json' },
|
|
77
|
+
body: JSON.stringify({
|
|
78
|
+
access_token: accessToken,
|
|
79
|
+
refresh_token: refreshToken || ''
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
.then(function(res) {
|
|
83
|
+
if (res.ok) {
|
|
84
|
+
document.getElementById('content').innerHTML =
|
|
85
|
+
'<h1 class="success">Autenticado com sucesso!</h1>' +
|
|
86
|
+
'<p>Pode fechar esta aba e voltar ao terminal.</p>';
|
|
87
|
+
} else {
|
|
88
|
+
throw new Error('Falha ao enviar tokens');
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
.catch(function() {
|
|
92
|
+
document.getElementById('content').innerHTML =
|
|
93
|
+
'<h1 class="error">Erro ao processar</h1>' +
|
|
94
|
+
'<p>Tente executar o login novamente no terminal.</p>';
|
|
95
|
+
});
|
|
96
|
+
})();
|
|
97
|
+
</script>
|
|
98
|
+
</body>
|
|
99
|
+
</html>`;
|
|
100
|
+
}
|
|
101
|
+
/** Abre uma URL no navegador padrão do sistema operacional */
|
|
102
|
+
function openBrowser(url) {
|
|
103
|
+
const os = platform();
|
|
104
|
+
let command;
|
|
105
|
+
switch (os) {
|
|
106
|
+
case 'darwin':
|
|
107
|
+
command = `open "${url}"`;
|
|
108
|
+
break;
|
|
109
|
+
case 'win32':
|
|
110
|
+
command = `start "" "${url}"`;
|
|
111
|
+
break;
|
|
112
|
+
default:
|
|
113
|
+
// Linux e outros sistemas Unix
|
|
114
|
+
command = `xdg-open "${url}"`;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
exec(command, (error) => {
|
|
118
|
+
if (error) {
|
|
119
|
+
// Se falhar ao abrir o navegador, mostra a URL para copiar manualmente
|
|
120
|
+
logger.warn('Nao foi possivel abrir o navegador automaticamente.');
|
|
121
|
+
logger.print(` ${chalk.gray('Abra manualmente:')} ${chalk.cyan.underline(url)}`);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Inicia servidor HTTP local temporário e aguarda callback do OAuth.
|
|
127
|
+
* Retorna os tokens recebidos do Supabase via redirect.
|
|
128
|
+
*/
|
|
129
|
+
function waitForOAuthCallback() {
|
|
130
|
+
return new Promise((resolve, reject) => {
|
|
131
|
+
let resolved = false;
|
|
132
|
+
const server = createServer((req, res) => {
|
|
133
|
+
// GET /callback — Serve a página HTML que extrai o fragment
|
|
134
|
+
if (req.method === 'GET' && req.url?.startsWith('/callback')) {
|
|
135
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
136
|
+
res.end(buildCallbackHtml());
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// POST /callback — Recebe os tokens enviados pela página HTML
|
|
140
|
+
if (req.method === 'POST' && req.url === '/callback') {
|
|
141
|
+
let body = '';
|
|
142
|
+
req.on('data', (chunk) => {
|
|
143
|
+
body += chunk.toString();
|
|
144
|
+
});
|
|
145
|
+
req.on('end', () => {
|
|
146
|
+
try {
|
|
147
|
+
const tokens = JSON.parse(body);
|
|
148
|
+
if (!tokens.access_token) {
|
|
149
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
150
|
+
res.end(JSON.stringify({ error: 'Token ausente' }));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
154
|
+
res.end(JSON.stringify({ ok: true }));
|
|
155
|
+
resolved = true;
|
|
156
|
+
// Fecha o servidor após enviar a resposta
|
|
157
|
+
server.close();
|
|
158
|
+
resolve(tokens);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
162
|
+
res.end(JSON.stringify({ error: 'JSON invalido' }));
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// Qualquer outra rota retorna 404
|
|
168
|
+
res.writeHead(404);
|
|
169
|
+
res.end('Not Found');
|
|
170
|
+
});
|
|
171
|
+
// Escuta em porta aleatória (0 = SO escolhe uma porta disponível)
|
|
172
|
+
server.listen(0, '127.0.0.1', () => {
|
|
173
|
+
const address = server.address();
|
|
174
|
+
if (!address || typeof address === 'string') {
|
|
175
|
+
reject(new Error('Falha ao iniciar servidor local'));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const port = address.port;
|
|
179
|
+
const redirectUrl = `http://localhost:${port}/callback`;
|
|
180
|
+
// Monta a URL de autorização OAuth do Supabase
|
|
181
|
+
const authUrl = `${SUPABASE_URL}/auth/v1/authorize?provider=github&redirect_to=${encodeURIComponent(redirectUrl)}`;
|
|
182
|
+
logger.print(` ${logger.stepIndicator(1, 3)} ${chalk.gray('Abrindo navegador para autenticacao...')}`);
|
|
183
|
+
logger.blank();
|
|
184
|
+
// URL para cópia manual caso o navegador não abra
|
|
185
|
+
const urlBox = logger.box([
|
|
186
|
+
chalk.gray('Se o navegador nao abrir, copie e cole o link:'),
|
|
187
|
+
'',
|
|
188
|
+
chalk.cyan.underline(authUrl),
|
|
189
|
+
]);
|
|
190
|
+
logger.print(urlBox);
|
|
191
|
+
logger.blank();
|
|
192
|
+
openBrowser(authUrl);
|
|
193
|
+
});
|
|
194
|
+
// Timeout para evitar que o servidor fique esperando indefinidamente
|
|
195
|
+
const timeout = setTimeout(() => {
|
|
196
|
+
if (!resolved) {
|
|
197
|
+
server.close();
|
|
198
|
+
reject(new Error(`Tempo limite de ${OAUTH_TIMEOUT_MS / 1000}s excedido. Tente novamente.`));
|
|
199
|
+
}
|
|
200
|
+
}, OAUTH_TIMEOUT_MS);
|
|
201
|
+
// Limpa o timeout quando o servidor fechar
|
|
202
|
+
server.on('close', () => {
|
|
203
|
+
clearTimeout(timeout);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Busca informações do usuário autenticado no Supabase usando o access_token.
|
|
209
|
+
* Chama GET /auth/v1/user com o token Bearer.
|
|
210
|
+
*/
|
|
211
|
+
async function fetchSupabaseUser(accessToken) {
|
|
212
|
+
const response = await fetch(`${SUPABASE_URL}/auth/v1/user`, {
|
|
213
|
+
headers: {
|
|
214
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
215
|
+
'apikey': SUPABASE_ANON_KEY,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
if (!response.ok) {
|
|
219
|
+
const errorBody = await response.text().catch(() => 'Erro desconhecido');
|
|
220
|
+
throw new Error(`Falha ao buscar perfil do usuario (HTTP ${response.status}): ${errorBody}`);
|
|
221
|
+
}
|
|
222
|
+
return response.json();
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Verifica um API token (aitk_xxx) chamando o endpoint de verificação do registry.
|
|
226
|
+
* Retorna os dados do usuário se o token for válido.
|
|
227
|
+
*/
|
|
228
|
+
async function verifyApiToken(token, registryUrl) {
|
|
229
|
+
const response = await fetch(`${registryUrl}/api/v1/auth/verify`, {
|
|
230
|
+
headers: {
|
|
231
|
+
'X-API-Token': token,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
if (!response.ok) {
|
|
235
|
+
if (response.status === 401) {
|
|
236
|
+
throw new Error('Token invalido ou expirado.');
|
|
237
|
+
}
|
|
238
|
+
throw new Error(`Erro ao verificar token (HTTP ${response.status})`);
|
|
239
|
+
}
|
|
240
|
+
const body = await response.json();
|
|
241
|
+
return body.data;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Fluxo de login via API token (para CI/CD).
|
|
245
|
+
* Verifica o token e salva as credenciais localmente.
|
|
246
|
+
*/
|
|
247
|
+
async function loginWithToken(token) {
|
|
248
|
+
const config = getConfig();
|
|
249
|
+
logger.blank();
|
|
250
|
+
logger.print(` ${chalk.white.bold('Autenticacao via API Token — AI Toolkit')}`);
|
|
251
|
+
logger.blank();
|
|
252
|
+
logger.print(` ${logger.stepIndicator(1, 2)} ${chalk.gray('Verificando token...')}`);
|
|
253
|
+
try {
|
|
254
|
+
const userData = await verifyApiToken(token, config.registry);
|
|
255
|
+
logger.print(` ${logger.stepIndicator(2, 2)} ${chalk.gray('Token verificado!')}`);
|
|
256
|
+
logger.blank();
|
|
257
|
+
// Salva as credenciais no arquivo de autenticação
|
|
258
|
+
const auth = {
|
|
259
|
+
token,
|
|
260
|
+
user: {
|
|
261
|
+
id: userData.userId,
|
|
262
|
+
username: userData.username,
|
|
263
|
+
email: '',
|
|
264
|
+
},
|
|
265
|
+
createdAt: new Date().toISOString(),
|
|
266
|
+
registry: config.registry,
|
|
267
|
+
};
|
|
268
|
+
saveAuth(auth);
|
|
269
|
+
const successBox = logger.box([
|
|
270
|
+
chalk.green.bold('Login realizado com sucesso!'),
|
|
271
|
+
'',
|
|
272
|
+
`${chalk.gray('Usuario:')} ${chalk.white.bold(userData.username)}`,
|
|
273
|
+
`${chalk.gray('Metodo:')} ${chalk.yellow('API Token')}`,
|
|
274
|
+
`${chalk.gray('Registry:')} ${chalk.cyan(config.registry)}`,
|
|
275
|
+
'',
|
|
276
|
+
chalk.gray('Voce ja pode publicar e instalar artefatos privados.'),
|
|
277
|
+
]);
|
|
278
|
+
logger.print(successBox);
|
|
279
|
+
logger.blank();
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
logger.blank();
|
|
283
|
+
logger.error(error instanceof Error ? error.message : 'Falha ao verificar token');
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Fluxo de login interativo via OAuth do GitHub (Supabase).
|
|
289
|
+
* Abre o navegador, aguarda callback e salva as credenciais.
|
|
290
|
+
*/
|
|
291
|
+
async function loginWithOAuth() {
|
|
292
|
+
const config = getConfig();
|
|
293
|
+
// Verifica se já está autenticado
|
|
294
|
+
const existingAuth = getAuth();
|
|
295
|
+
if (existingAuth) {
|
|
296
|
+
logger.warn(`Voce ja esta autenticado como ${chalk.bold(existingAuth.user.username)}.`);
|
|
297
|
+
logger.info('Use "aitk logout" para sair antes de fazer login novamente.');
|
|
298
|
+
logger.blank();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
logger.blank();
|
|
302
|
+
logger.print(` ${chalk.white.bold('Autenticacao — AI Toolkit Registry')}`);
|
|
303
|
+
logger.blank();
|
|
304
|
+
try {
|
|
305
|
+
// Passo 1: Aguarda callback OAuth (abre navegador internamente)
|
|
306
|
+
const tokens = await waitForOAuthCallback();
|
|
307
|
+
// Passo 2: Busca dados do usuário com o access_token
|
|
308
|
+
logger.print(` ${logger.stepIndicator(2, 3)} ${chalk.gray('Autenticando...')}`);
|
|
309
|
+
const user = await fetchSupabaseUser(tokens.access_token);
|
|
310
|
+
// Extrai username do GitHub dos metadados do usuário
|
|
311
|
+
const username = user.user_metadata?.user_name ||
|
|
312
|
+
user.user_metadata?.preferred_username ||
|
|
313
|
+
'unknown';
|
|
314
|
+
const email = user.email || '';
|
|
315
|
+
// Salva as credenciais no arquivo de autenticação
|
|
316
|
+
const auth = {
|
|
317
|
+
token: tokens.access_token,
|
|
318
|
+
user: {
|
|
319
|
+
id: user.id,
|
|
320
|
+
username,
|
|
321
|
+
email,
|
|
322
|
+
},
|
|
323
|
+
createdAt: new Date().toISOString(),
|
|
324
|
+
registry: config.registry,
|
|
325
|
+
};
|
|
326
|
+
saveAuth(auth);
|
|
327
|
+
// Passo 3: Finalização com sucesso
|
|
328
|
+
logger.print(` ${logger.stepIndicator(3, 3)} ${chalk.gray('Finalizado!')}`);
|
|
329
|
+
logger.blank();
|
|
330
|
+
const successBox = logger.box([
|
|
331
|
+
chalk.green.bold('Login realizado com sucesso!'),
|
|
332
|
+
'',
|
|
333
|
+
`${chalk.gray('Usuario:')} ${chalk.white.bold(username)}`,
|
|
334
|
+
`${chalk.gray('Email:')} ${chalk.white(email)}`,
|
|
335
|
+
`${chalk.gray('Registry:')} ${chalk.cyan(config.registry)}`,
|
|
336
|
+
'',
|
|
337
|
+
chalk.gray('Voce ja pode publicar e instalar artefatos privados.'),
|
|
338
|
+
]);
|
|
339
|
+
logger.print(successBox);
|
|
340
|
+
logger.blank();
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
logger.blank();
|
|
344
|
+
logger.error(error instanceof Error ? error.message : 'Falha na autenticacao');
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// ── Comando principal ───────────────────────────────────────────────────
|
|
349
|
+
export const loginCommand = new Command('login')
|
|
350
|
+
.description('Autenticar com o AI Toolkit registry')
|
|
351
|
+
.option('--token <token>', 'API token para autenticacao direta (CI/CD)')
|
|
352
|
+
.action(async (options) => {
|
|
353
|
+
if (options.token) {
|
|
354
|
+
// Fluxo direto com API token (para CI/CD e automacao)
|
|
355
|
+
await loginWithToken(options.token);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
// Fluxo interativo via OAuth do GitHub
|
|
359
|
+
await loginWithOAuth();
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,aAAa,SAKtB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { clearAuth } from '../core/auth.js';
|
|
4
|
+
export const logoutCommand = new Command('logout')
|
|
5
|
+
.description('Remover credenciais locais')
|
|
6
|
+
.action(async () => {
|
|
7
|
+
clearAuth();
|
|
8
|
+
console.log(chalk.green('Logout realizado com sucesso.'));
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,4BAA4B,CAAC;KACzC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,SAAS,EAAE,CAAC;IACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoHpC,eAAO,MAAM,cAAc,SA6LvB,CAAC"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { mkdirSync, rmSync } from 'node:fs';
|
|
10
|
+
import { artifactManifestSchema } from '@tarcisiojunior/shared';
|
|
11
|
+
import { createApiClient } from '../core/api-client.js';
|
|
12
|
+
import { requireAuth } from '../core/auth.js';
|
|
13
|
+
import { logger } from '../utils/logger.js';
|
|
14
|
+
/** Nome do arquivo de manifesto do artefato */
|
|
15
|
+
const ARTIFACT_MANIFEST_FILE = 'aitk-artifact.json';
|
|
16
|
+
/** Lê e valida o manifesto do artefato no diretório informado */
|
|
17
|
+
function readArtifactManifest(dir) {
|
|
18
|
+
const filePath = join(dir, ARTIFACT_MANIFEST_FILE);
|
|
19
|
+
if (!existsSync(filePath)) {
|
|
20
|
+
throw new Error(`Arquivo "${ARTIFACT_MANIFEST_FILE}" não encontrado no diretório atual.\n` +
|
|
21
|
+
`Execute este comando na raiz do artefato que deseja publicar.`);
|
|
22
|
+
}
|
|
23
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
24
|
+
let raw;
|
|
25
|
+
try {
|
|
26
|
+
raw = JSON.parse(content);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
throw new Error(`Erro ao parsear "${ARTIFACT_MANIFEST_FILE}": JSON inválido.`);
|
|
30
|
+
}
|
|
31
|
+
// Valida com Zod
|
|
32
|
+
const result = artifactManifestSchema.safeParse(raw);
|
|
33
|
+
if (!result.success) {
|
|
34
|
+
const errors = result.error.errors
|
|
35
|
+
.map((e) => ` - ${e.path.join('.')}: ${e.message}`)
|
|
36
|
+
.join('\n');
|
|
37
|
+
throw new Error(`Manifesto inválido:\n${errors}`);
|
|
38
|
+
}
|
|
39
|
+
return result.data;
|
|
40
|
+
}
|
|
41
|
+
/** Verifica se todos os arquivos listados no manifesto existem */
|
|
42
|
+
function validateFiles(manifest, dir) {
|
|
43
|
+
const missing = [];
|
|
44
|
+
for (const file of manifest.files) {
|
|
45
|
+
const filePath = join(dir, file);
|
|
46
|
+
if (!existsSync(filePath)) {
|
|
47
|
+
missing.push(file);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (missing.length > 0) {
|
|
51
|
+
throw new Error(`Arquivos listados no manifesto não encontrados:\n` +
|
|
52
|
+
missing.map((f) => ` - ${f}`).join('\n'));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Cria um tarball (.tgz) com os arquivos do artefato */
|
|
56
|
+
function createTarball(manifest, dir) {
|
|
57
|
+
// Diretório temporário para o tarball
|
|
58
|
+
const tmpDir = join(tmpdir(), `aitk-publish-${Date.now()}`);
|
|
59
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
60
|
+
const tarballName = `${manifest.scope}-${manifest.name}-${manifest.version}.tgz`;
|
|
61
|
+
const tarballPath = join(tmpDir, tarballName);
|
|
62
|
+
// Inclui o manifesto junto com os arquivos declarados
|
|
63
|
+
const allFiles = [...manifest.files, ARTIFACT_MANIFEST_FILE];
|
|
64
|
+
// Cria o tarball usando o comando tar do sistema
|
|
65
|
+
const fileList = allFiles.join(' ');
|
|
66
|
+
execSync(`tar -czf "${tarballPath}" ${fileList}`, {
|
|
67
|
+
cwd: dir,
|
|
68
|
+
stdio: 'pipe',
|
|
69
|
+
});
|
|
70
|
+
// Calcula checksum SHA-256
|
|
71
|
+
const fileBuffer = readFileSync(tarballPath);
|
|
72
|
+
const hash = createHash('sha256').update(fileBuffer).digest('hex');
|
|
73
|
+
const size = statSync(tarballPath).size;
|
|
74
|
+
return { tarballPath, size, checksum: `sha256-${hash}` };
|
|
75
|
+
}
|
|
76
|
+
/** Formata bytes para exibição legível */
|
|
77
|
+
function formatBytes(bytes) {
|
|
78
|
+
if (bytes < 1024)
|
|
79
|
+
return `${bytes} B`;
|
|
80
|
+
if (bytes < 1024 * 1024)
|
|
81
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
82
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
83
|
+
}
|
|
84
|
+
/** Limpa arquivos temporários criados durante a publicação */
|
|
85
|
+
function cleanup(tarballPath) {
|
|
86
|
+
try {
|
|
87
|
+
const tmpDir = join(tarballPath, '..');
|
|
88
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Ignora erros de limpeza
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export const publishCommand = new Command('publish')
|
|
95
|
+
.description('Publicar artefato no registry')
|
|
96
|
+
.option('--access <access>', 'Visibilidade: public, private, team', 'public')
|
|
97
|
+
.option('--team <slug>', 'Slug da equipe (para acesso team)')
|
|
98
|
+
.option('--dir <path>', 'Diretório do artefato (padrão: diretório atual)')
|
|
99
|
+
.action(async (options) => {
|
|
100
|
+
const totalSteps = 5;
|
|
101
|
+
let tarballPath = null;
|
|
102
|
+
try {
|
|
103
|
+
// Verifica autenticação
|
|
104
|
+
requireAuth();
|
|
105
|
+
const dir = resolve(options.dir || process.cwd());
|
|
106
|
+
logger.blank();
|
|
107
|
+
logger.print(` ${chalk.white.bold('Publicando artefato...')}`);
|
|
108
|
+
logger.blank();
|
|
109
|
+
// ── Passo 1: Ler e validar manifesto ────────────────────────────
|
|
110
|
+
const spinner1 = ora({
|
|
111
|
+
text: `${logger.stepIndicator(1, totalSteps)} Lendo manifesto...`,
|
|
112
|
+
color: 'cyan',
|
|
113
|
+
}).start();
|
|
114
|
+
const manifest = readArtifactManifest(dir);
|
|
115
|
+
validateFiles(manifest, dir);
|
|
116
|
+
const slug = `${manifest.scope}/${manifest.name}`;
|
|
117
|
+
spinner1.succeed(`${logger.stepIndicator(1, totalSteps)} Manifesto válido: ${chalk.cyan.bold(slug)}@${chalk.green(manifest.version)}`);
|
|
118
|
+
// ── Passo 2: Empacotar arquivos ─────────────────────────────────
|
|
119
|
+
const spinner2 = ora({
|
|
120
|
+
text: `${logger.stepIndicator(2, totalSteps)} Empacotando arquivos...`,
|
|
121
|
+
color: 'cyan',
|
|
122
|
+
}).start();
|
|
123
|
+
const { tarballPath: tPath, size, checksum } = createTarball(manifest, dir);
|
|
124
|
+
tarballPath = tPath;
|
|
125
|
+
spinner2.succeed(`${logger.stepIndicator(2, totalSteps)} Tarball criado ${chalk.gray(`(${formatBytes(size)}, ${checksum.slice(0, 15)}...)`)}`);
|
|
126
|
+
// ── Passo 3: Registrar artefato (se necessário) ─────────────────
|
|
127
|
+
const spinner3 = ora({
|
|
128
|
+
text: `${logger.stepIndicator(3, totalSteps)} Verificando registro no registry...`,
|
|
129
|
+
color: 'cyan',
|
|
130
|
+
}).start();
|
|
131
|
+
const client = createApiClient();
|
|
132
|
+
try {
|
|
133
|
+
// Tenta obter o artefato existente
|
|
134
|
+
await client.getArtifact(manifest.scope, manifest.name);
|
|
135
|
+
spinner3.succeed(`${logger.stepIndicator(3, totalSteps)} Artefato já registrado no registry`);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Artefato não existe, cria um novo
|
|
139
|
+
spinner3.text = `${logger.stepIndicator(3, totalSteps)} Criando artefato no registry...`;
|
|
140
|
+
await client.createArtifact({
|
|
141
|
+
scope: manifest.scope,
|
|
142
|
+
name: manifest.name,
|
|
143
|
+
type: manifest.type,
|
|
144
|
+
description: manifest.description,
|
|
145
|
+
visibility: options.access,
|
|
146
|
+
keywords: manifest.keywords,
|
|
147
|
+
categories: manifest.categories,
|
|
148
|
+
toolTargets: manifest.toolTargets,
|
|
149
|
+
repository: manifest.repository,
|
|
150
|
+
license: manifest.license,
|
|
151
|
+
});
|
|
152
|
+
spinner3.succeed(`${logger.stepIndicator(3, totalSteps)} Artefato criado no registry ${chalk.gray(`(${options.access})`)}`);
|
|
153
|
+
}
|
|
154
|
+
// ── Passo 4: Enviar versão ──────────────────────────────────────
|
|
155
|
+
const spinner4 = ora({
|
|
156
|
+
text: `${logger.stepIndicator(4, totalSteps)} Enviando versão ${manifest.version}...`,
|
|
157
|
+
color: 'cyan',
|
|
158
|
+
}).start();
|
|
159
|
+
// Monta o FormData para upload multipart
|
|
160
|
+
const tarballBuffer = readFileSync(tarballPath);
|
|
161
|
+
const tarballBlob = new Blob([tarballBuffer], { type: 'application/gzip' });
|
|
162
|
+
const formData = new FormData();
|
|
163
|
+
formData.append('version', manifest.version);
|
|
164
|
+
formData.append('file', tarballBlob, `${manifest.scope}-${manifest.name}-${manifest.version}.tgz`);
|
|
165
|
+
// Metadados opcionais
|
|
166
|
+
const metadata = {
|
|
167
|
+
type: manifest.type,
|
|
168
|
+
toolTargets: manifest.toolTargets,
|
|
169
|
+
files: manifest.files,
|
|
170
|
+
install: manifest.install,
|
|
171
|
+
keywords: manifest.keywords,
|
|
172
|
+
categories: manifest.categories,
|
|
173
|
+
};
|
|
174
|
+
formData.append('metadata', JSON.stringify(metadata));
|
|
175
|
+
// Dependências (se existirem)
|
|
176
|
+
if (manifest.dependencies && Object.keys(manifest.dependencies).length > 0) {
|
|
177
|
+
const deps = Object.entries(manifest.dependencies).map(([key, range]) => {
|
|
178
|
+
const [depScope, depName] = key.split('/');
|
|
179
|
+
return { scope: depScope, name: depName, versionRange: range, isOptional: false };
|
|
180
|
+
});
|
|
181
|
+
formData.append('dependencies', JSON.stringify(deps));
|
|
182
|
+
}
|
|
183
|
+
// Lê README.md se existir no diretório
|
|
184
|
+
const readmePath = join(dir, 'README.md');
|
|
185
|
+
if (existsSync(readmePath)) {
|
|
186
|
+
const readmeContent = readFileSync(readmePath, 'utf-8');
|
|
187
|
+
formData.append('readme', readmeContent);
|
|
188
|
+
}
|
|
189
|
+
// Lê CHANGELOG.md se existir no diretório
|
|
190
|
+
const changelogPath = join(dir, 'CHANGELOG.md');
|
|
191
|
+
if (existsSync(changelogPath)) {
|
|
192
|
+
const changelogContent = readFileSync(changelogPath, 'utf-8');
|
|
193
|
+
formData.append('changelog', changelogContent);
|
|
194
|
+
}
|
|
195
|
+
await client.publishVersion(manifest.scope, manifest.name, formData);
|
|
196
|
+
spinner4.succeed(`${logger.stepIndicator(4, totalSteps)} Versão ${chalk.green.bold(manifest.version)} enviada com sucesso`);
|
|
197
|
+
// ── Passo 5: Verificação final ──────────────────────────────────
|
|
198
|
+
const spinner5 = ora({
|
|
199
|
+
text: `${logger.stepIndicator(5, totalSteps)} Verificando publicação...`,
|
|
200
|
+
color: 'cyan',
|
|
201
|
+
}).start();
|
|
202
|
+
// Confirma que a versão foi registrada
|
|
203
|
+
const versions = await client.getVersions(manifest.scope, manifest.name);
|
|
204
|
+
const published = versions.data.find((v) => v.version === manifest.version);
|
|
205
|
+
if (!published) {
|
|
206
|
+
spinner5.warn(`${logger.stepIndicator(5, totalSteps)} Versão enviada mas não confirmada na listagem`);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
spinner5.succeed(`${logger.stepIndicator(5, totalSteps)} Publicação verificada`);
|
|
210
|
+
}
|
|
211
|
+
// ── Árvore de arquivos publicados ─────────────────────────────
|
|
212
|
+
logger.blank();
|
|
213
|
+
const tree = logger.fileTree(manifest.files, ` ${chalk.gray('Arquivos publicados:')}`);
|
|
214
|
+
logger.print(' ' + tree.split('\n').join('\n '));
|
|
215
|
+
// ── Mensagem de sucesso ───────────────────────────────────────
|
|
216
|
+
logger.blank();
|
|
217
|
+
const successBox = logger.box([
|
|
218
|
+
chalk.green.bold('Publicação concluída!'),
|
|
219
|
+
'',
|
|
220
|
+
`${chalk.gray('Artefato:')} ${chalk.cyan.bold(slug)}`,
|
|
221
|
+
`${chalk.gray('Versão:')} ${chalk.green.bold(manifest.version)}`,
|
|
222
|
+
`${chalk.gray('Tipo:')} ${logger.typeBadge(manifest.type)}`,
|
|
223
|
+
`${chalk.gray('Tamanho:')} ${chalk.white(formatBytes(size))}`,
|
|
224
|
+
`${chalk.gray('Checksum:')} ${chalk.gray(checksum)}`,
|
|
225
|
+
'',
|
|
226
|
+
chalk.gray(`Instale com: ${chalk.cyan(`aitk install ${slug}@${manifest.version}`)}`),
|
|
227
|
+
]);
|
|
228
|
+
logger.print(successBox);
|
|
229
|
+
logger.blank();
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
logger.blank();
|
|
233
|
+
logger.error('Erro ao publicar artefato');
|
|
234
|
+
logger.error(error instanceof Error ? error.message : 'Erro desconhecido');
|
|
235
|
+
logger.blank();
|
|
236
|
+
process.exitCode = 1;
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
// Limpa arquivos temporários
|
|
240
|
+
if (tarballPath) {
|
|
241
|
+
cleanup(tarballPath);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
//# sourceMappingURL=publish.js.map
|