@fefsbenson/jarvis 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +68 -23
- package/bin/cli.js.bak-antes-windows +297 -0
- package/package.json +3 -3
package/bin/cli.js
CHANGED
|
@@ -117,7 +117,7 @@ function barra(feito, total) {
|
|
|
117
117
|
return ` ${laranja('█'.repeat(cheio))}${fraco('░'.repeat(largura - cheio))} ${cinza(`${Math.round(pct * 100)}%`)}`;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
async function baixar(token, destino) {
|
|
120
|
+
async function baixar(token, destino, plataforma = 'linux') {
|
|
121
121
|
// 1. qual é a versão mais recente
|
|
122
122
|
const rel = await api(`/repos/${REPO}/releases/latest`, token);
|
|
123
123
|
if (rel.status === 401) throw new Error('TOKEN_INVALIDO');
|
|
@@ -125,8 +125,20 @@ async function baixar(token, destino) {
|
|
|
125
125
|
if (!rel.ok) throw new Error(`GitHub respondeu ${rel.status}`);
|
|
126
126
|
const dados = await rel.json();
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
// 2. o pacote da plataforma escolhida.
|
|
129
|
+
// Um release traz os dois assets (jarvis-X.Y.Z-windows.tar.gz e -linux).
|
|
130
|
+
// Só cai no primeiro .tar.gz disponível quando o release é antigo e tem um
|
|
131
|
+
// pacote único — assim uma versão nova do baixador continua instalando
|
|
132
|
+
// releases publicados antes desta separação.
|
|
133
|
+
const sufixo = PLATAFORMAS[plataforma]?.sufixo || 'linux';
|
|
134
|
+
const tarballs = (dados.assets || []).filter(a => a.name.endsWith('.tar.gz'));
|
|
135
|
+
const asset = tarballs.find(a => a.name.includes(`-${sufixo}`)) ||
|
|
136
|
+
(tarballs.length === 1 ? tarballs[0] : null);
|
|
137
|
+
if (!asset) {
|
|
138
|
+
const nomes = tarballs.map(a => a.name).join(', ') || 'nenhum';
|
|
139
|
+
throw new Error(
|
|
140
|
+
`Release ${dados.tag_name} não tem pacote para ${sufixo}. Assets: ${nomes}`);
|
|
141
|
+
}
|
|
130
142
|
|
|
131
143
|
console.log(` ${verde('✓')} ${branco('Versão')} ${cinza(dados.tag_name)} ${fraco((asset.size / 1048576).toFixed(1) + ' MB')}`);
|
|
132
144
|
|
|
@@ -190,32 +202,59 @@ function erroDeAcesso(tipo) {
|
|
|
190
202
|
}
|
|
191
203
|
|
|
192
204
|
/**
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
205
|
+
* Existem dois pacotes, porque são dois sistemas de verdade.
|
|
206
|
+
*
|
|
207
|
+
* O de Linux/WSL invoca os hooks com `bash pyrun.sh`; o de Windows usa
|
|
208
|
+
* `python pyrun.py` e resolve o ambiente virtual em `Scripts\` em vez de
|
|
209
|
+
* `bin/`. Instalar o pacote errado produz um sistema que copia mas não
|
|
210
|
+
* funciona — que é pior que não instalar, porque o dono só descobre depois.
|
|
211
|
+
*
|
|
212
|
+
* O padrão vem do sistema detectado, mas quem decide é o dono: no Windows
|
|
213
|
+
* ele pode legitimamente querer o pacote POSIX, se for rodar dentro do WSL.
|
|
197
214
|
*/
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
215
|
+
const PLATAFORMAS = {
|
|
216
|
+
windows: { rotulo: 'Windows (PowerShell)', sufixo: 'windows' },
|
|
217
|
+
linux: { rotulo: 'Linux, WSL ou macOS', sufixo: 'linux' },
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
async function escolherPlataforma() {
|
|
221
|
+
const provavel = process.platform === 'win32' ? 'windows' : 'linux';
|
|
222
|
+
|
|
223
|
+
console.log(` ${branco(neg('Onde o JARVIS vai rodar?'))}`);
|
|
206
224
|
console.log();
|
|
207
|
-
console.log(`
|
|
208
|
-
|
|
225
|
+
console.log(` ${laranja('[1]')} ${branco(PLATAFORMAS.windows.rotulo)}` +
|
|
226
|
+
`${provavel === 'windows' ? fraco(' ← detectei este') : ''}`);
|
|
227
|
+
console.log(` ${laranja('[2]')} ${branco(PLATAFORMAS.linux.rotulo)}` +
|
|
228
|
+
`${provavel === 'linux' ? fraco(' ← detectei este') : ''}`);
|
|
209
229
|
console.log();
|
|
210
|
-
console.log(` ${fraco('
|
|
230
|
+
console.log(` ${fraco('São pacotes diferentes: o de Windows não usa bash.')}`);
|
|
211
231
|
console.log();
|
|
212
|
-
|
|
232
|
+
|
|
233
|
+
const mapa = { '1': 'windows', '2': 'linux' };
|
|
234
|
+
for (;;) {
|
|
235
|
+
// `perguntar` já desenha o marcador ▸ — repetir aqui produzia "▸ ▸ Escolha"
|
|
236
|
+
const r = (await perguntar(`Escolha ${fraco('(1-2, enter = detectado)')}`))
|
|
237
|
+
.trim().toLowerCase();
|
|
238
|
+
if (!r) return provavel;
|
|
239
|
+
if (mapa[r]) return mapa[r];
|
|
240
|
+
// Ordem importa: "wsl" começa com 'w' e cairia em Windows se a regra
|
|
241
|
+
// genérica viesse antes — mas WSL é justamente o pacote POSIX. As
|
|
242
|
+
// palavras inteiras são testadas primeiro; os prefixos, depois.
|
|
243
|
+
if (/\b(wsl|ubuntu|linux|debian|mac|macos|posix)\b/.test(r)) return 'linux';
|
|
244
|
+
if (/\b(windows|powershell|win|ps)\b/.test(r)) return 'windows';
|
|
245
|
+
if (r.startsWith('l') || r.startsWith('m')) return 'linux';
|
|
246
|
+
if (r.startsWith('w') || r.startsWith('p')) return 'windows';
|
|
247
|
+
console.log(` ${fraco('não entendi — digite 1 ou 2')}`);
|
|
248
|
+
}
|
|
213
249
|
}
|
|
214
250
|
|
|
215
251
|
async function instalar(args) {
|
|
216
252
|
abertura();
|
|
217
253
|
|
|
218
|
-
|
|
254
|
+
const plataforma = await escolherPlataforma();
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(` ${verde('✓')} ${branco('Pacote')} ${cinza(PLATAFORMAS[plataforma].rotulo)}`);
|
|
257
|
+
console.log();
|
|
219
258
|
|
|
220
259
|
const py = acharPython();
|
|
221
260
|
if (!py) {
|
|
@@ -223,8 +262,14 @@ async function instalar(args) {
|
|
|
223
262
|
console.log();
|
|
224
263
|
console.log(` ${cinza('O JARVIS roda em Python. O Node serve só para este baixador.')}`);
|
|
225
264
|
console.log();
|
|
226
|
-
|
|
227
|
-
|
|
265
|
+
if (plataforma === 'windows') {
|
|
266
|
+
console.log(` ${branco('Baixe em:')} ${fraco('https://python.org/downloads')}`);
|
|
267
|
+
console.log(` ${fraco('Marque "Add python.exe to PATH" durante a instalação.')}`);
|
|
268
|
+
console.log(` ${fraco('O Python da Microsoft Store não serve — ele é um atalho para a loja.')}`);
|
|
269
|
+
} else {
|
|
270
|
+
console.log(` ${branco('No Ubuntu/WSL:')} ${fraco('sudo apt install python3 python3-venv')}`);
|
|
271
|
+
console.log(` ${branco('No macOS:')} ${fraco('brew install python@3.12')}`);
|
|
272
|
+
}
|
|
228
273
|
console.log();
|
|
229
274
|
return 1;
|
|
230
275
|
}
|
|
@@ -259,7 +304,7 @@ async function instalar(args) {
|
|
|
259
304
|
|
|
260
305
|
console.log();
|
|
261
306
|
try {
|
|
262
|
-
await baixar(token, destino);
|
|
307
|
+
await baixar(token, destino, plataforma);
|
|
263
308
|
} catch (e) {
|
|
264
309
|
if (e.message === 'TOKEN_INVALIDO' || e.message === 'SEM_ACESSO') {
|
|
265
310
|
erroDeAcesso(e.message);
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* JARVIS — baixador.
|
|
4
|
+
*
|
|
5
|
+
* Este pacote npm é SÓ o transporte (~20 KB). O sistema em si (108 MB, com
|
|
6
|
+
* conhecimento destilado de material de terceiros) vive num Release PRIVADO
|
|
7
|
+
* do GitHub e exige token de acesso — a licença proíbe distribuição pública.
|
|
8
|
+
*
|
|
9
|
+
* npx @fefsbenson/jarvis install
|
|
10
|
+
*
|
|
11
|
+
* Só Node built-in: precisa rodar antes de qualquer dependência existir.
|
|
12
|
+
*
|
|
13
|
+
* JARVIS · PRAGMA · by Felipe Brandão
|
|
14
|
+
*/
|
|
15
|
+
import { createWriteStream, existsSync, mkdirSync, readdirSync, statSync } from 'node:fs';
|
|
16
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
17
|
+
import { createInterface } from 'node:readline';
|
|
18
|
+
import { tmpdir } from 'node:os';
|
|
19
|
+
import { join, resolve } from 'node:path';
|
|
20
|
+
import { pipeline } from 'node:stream/promises';
|
|
21
|
+
import { Readable } from 'node:stream';
|
|
22
|
+
|
|
23
|
+
const REPO = 'fefsbenson/jarvis-entrega';
|
|
24
|
+
const PASTA_PADRAO = 'jarvis';
|
|
25
|
+
|
|
26
|
+
// ── cores (somem se o terminal não suportar) ─────────────────────────
|
|
27
|
+
const tty = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
28
|
+
const c = (t, k) => (tty ? `\x1b[${k}m${t}\x1b[0m` : t);
|
|
29
|
+
const laranja = t => c(t, '38;5;208');
|
|
30
|
+
const branco = t => c(t, '38;5;255');
|
|
31
|
+
const cinza = t => c(t, '38;5;250');
|
|
32
|
+
const fraco = t => c(t, '38;5;240');
|
|
33
|
+
const verde = t => c(t, '38;5;71');
|
|
34
|
+
const vermelho = t => c(t, '38;5;167');
|
|
35
|
+
const neg = t => c(t, '1');
|
|
36
|
+
|
|
37
|
+
const LOGO = [
|
|
38
|
+
' ██ █████ ██████ ██ ██ ██ ███████',
|
|
39
|
+
' ██ ██ ██ ██ ██ ██ ██ ██ ██',
|
|
40
|
+
' ██ ███████ ██████ ██ ██ ██ ███████',
|
|
41
|
+
'██ ██ ██ ██ ██ ██ ██ ██ ██ ██',
|
|
42
|
+
' █████ ██ ██ ██ ██ ████ ██ ███████',
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
function abertura() {
|
|
46
|
+
console.log();
|
|
47
|
+
for (const l of LOGO) console.log(' ' + laranja(neg(l)));
|
|
48
|
+
console.log();
|
|
49
|
+
console.log(` ${cinza('Sistema operacional de conhecimento e agentes')}`);
|
|
50
|
+
console.log(` ${fraco('PRAGMA · by Felipe Brandão')}`);
|
|
51
|
+
console.log();
|
|
52
|
+
console.log(' ' + fraco('─'.repeat(66)));
|
|
53
|
+
console.log();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function perguntar(texto, oculto = false) {
|
|
57
|
+
return new Promise(res => {
|
|
58
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
59
|
+
if (oculto && process.stdin.isTTY) {
|
|
60
|
+
// não ecoa o token na tela nem deixa no scrollback
|
|
61
|
+
const escrever = rl._writeToOutput.bind(rl);
|
|
62
|
+
rl._writeToOutput = function (s) {
|
|
63
|
+
if (s.includes(texto)) escrever(s);
|
|
64
|
+
else escrever('*');
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
rl.question(` ${laranja('▸')} ${texto} `, r => { rl.close(); if (oculto) console.log(); res(r.trim()); });
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Precisa de Python — o instalador de verdade é ele.
|
|
73
|
+
*
|
|
74
|
+
* ARMADILHA DO WINDOWS: `python3.exe` em WindowsApps é um STUB da Microsoft
|
|
75
|
+
* Store. Ele imprime "Python não foi encontrado" e sai com código 0 — passa
|
|
76
|
+
* por qualquer teste ingênuo de status. O jeito confiável é validar a SAÍDA,
|
|
77
|
+
* e tentar o `py` launcher, que é o padrão no Windows.
|
|
78
|
+
* (o pyrun.sh do harness já sabia disso; eu não tinha reusado a lição)
|
|
79
|
+
*/
|
|
80
|
+
function acharPython() {
|
|
81
|
+
const tentativas = [
|
|
82
|
+
['py', ['-3']], // launcher oficial do Windows — o mais confiável lá
|
|
83
|
+
['python3', []],
|
|
84
|
+
['python', []],
|
|
85
|
+
];
|
|
86
|
+
for (const [cmd, pre] of tentativas) {
|
|
87
|
+
const r = spawnSync(cmd, [...pre, '-c', 'import sys;print(sys.version_info[:2])'],
|
|
88
|
+
{ encoding: 'utf8' });
|
|
89
|
+
const saida = (r.stdout || '') + (r.stderr || '');
|
|
90
|
+
// o stub da Store não imprime tupla nenhuma — só o texto da propaganda
|
|
91
|
+
if (/n.o foi encontrado|not found|Microsoft Store/i.test(saida)) continue;
|
|
92
|
+
const m = saida.match(/\((\d+),\s*(\d+)\)/);
|
|
93
|
+
if (r.status === 0 && m && (+m[1] > 3 || (+m[1] === 3 && +m[2] >= 10))) {
|
|
94
|
+
return { cmd, args: pre, versao: `${m[1]}.${m[2]}` };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function api(caminho, token, aceitar = 'application/vnd.github+json') {
|
|
101
|
+
const r = await fetch(`https://api.github.com${caminho}`, {
|
|
102
|
+
headers: {
|
|
103
|
+
Authorization: `Bearer ${token}`,
|
|
104
|
+
Accept: aceitar,
|
|
105
|
+
'User-Agent': 'jarvis-installer',
|
|
106
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
107
|
+
},
|
|
108
|
+
redirect: 'follow',
|
|
109
|
+
});
|
|
110
|
+
return r;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function barra(feito, total) {
|
|
114
|
+
const largura = 28;
|
|
115
|
+
const pct = total ? feito / total : 0;
|
|
116
|
+
const cheio = Math.round(pct * largura);
|
|
117
|
+
return ` ${laranja('█'.repeat(cheio))}${fraco('░'.repeat(largura - cheio))} ${cinza(`${Math.round(pct * 100)}%`)}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function baixar(token, destino) {
|
|
121
|
+
// 1. qual é a versão mais recente
|
|
122
|
+
const rel = await api(`/repos/${REPO}/releases/latest`, token);
|
|
123
|
+
if (rel.status === 401) throw new Error('TOKEN_INVALIDO');
|
|
124
|
+
if (rel.status === 404) throw new Error('SEM_ACESSO');
|
|
125
|
+
if (!rel.ok) throw new Error(`GitHub respondeu ${rel.status}`);
|
|
126
|
+
const dados = await rel.json();
|
|
127
|
+
|
|
128
|
+
const asset = (dados.assets || []).find(a => a.name.endsWith('.tar.gz'));
|
|
129
|
+
if (!asset) throw new Error('Release sem pacote .tar.gz');
|
|
130
|
+
|
|
131
|
+
console.log(` ${verde('✓')} ${branco('Versão')} ${cinza(dados.tag_name)} ${fraco((asset.size / 1048576).toFixed(1) + ' MB')}`);
|
|
132
|
+
|
|
133
|
+
// 2. baixa o tarball (asset privado exige Accept: octet-stream)
|
|
134
|
+
const bin = await api(`/repos/${REPO}/releases/assets/${asset.id}`, token,
|
|
135
|
+
'application/octet-stream');
|
|
136
|
+
if (!bin.ok) throw new Error(`download falhou (${bin.status})`);
|
|
137
|
+
|
|
138
|
+
const tmp = join(tmpdir(), `jarvis-${Date.now()}.tar.gz`);
|
|
139
|
+
const total = Number(bin.headers.get('content-length')) || asset.size;
|
|
140
|
+
let feito = 0;
|
|
141
|
+
let ultimo = 0;
|
|
142
|
+
|
|
143
|
+
const origem = Readable.fromWeb(bin.body);
|
|
144
|
+
origem.on('data', pedaco => {
|
|
145
|
+
feito += pedaco.length;
|
|
146
|
+
const agora = Date.now();
|
|
147
|
+
// A barra so redesenha em TTY: com o output capturado (pipe, log, CI) o
|
|
148
|
+
// \r nao apaga a linha e o progresso vira uma parede de barras.
|
|
149
|
+
if (tty && agora - ultimo > 200) {
|
|
150
|
+
ultimo = agora;
|
|
151
|
+
process.stdout.write('\r' + barra(feito, total));
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
await pipeline(origem, createWriteStream(tmp));
|
|
155
|
+
if (tty) process.stdout.write('\r' + barra(total, total) + '\n');
|
|
156
|
+
else console.log(` ${verde('✓')} ${branco('Baixado')} ${fraco((total / 1048576).toFixed(1) + ' MB')}`);
|
|
157
|
+
|
|
158
|
+
// 3. extrai
|
|
159
|
+
mkdirSync(destino, { recursive: true });
|
|
160
|
+
const tar = spawnSync('tar', ['xzf', tmp, '-C', destino, '--strip-components=1'],
|
|
161
|
+
{ encoding: 'utf8' });
|
|
162
|
+
if (tar.status !== 0) throw new Error(`tar falhou: ${(tar.stderr || '').slice(0, 120)}`);
|
|
163
|
+
|
|
164
|
+
const n = contar(destino);
|
|
165
|
+
console.log(` ${verde('✓')} ${branco('Extraído')} ${fraco(n.toLocaleString('pt-BR') + ' arquivos')}`);
|
|
166
|
+
return destino;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function contar(dir) {
|
|
170
|
+
let n = 0;
|
|
171
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
172
|
+
if (e.name === 'node_modules' || e.name === '.git') continue;
|
|
173
|
+
n += e.isDirectory() ? contar(join(dir, e.name)) : 1;
|
|
174
|
+
}
|
|
175
|
+
return n;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function erroDeAcesso(tipo) {
|
|
179
|
+
console.log();
|
|
180
|
+
if (tipo === 'TOKEN_INVALIDO') {
|
|
181
|
+
console.log(` ${vermelho(neg('Token inválido.'))}`);
|
|
182
|
+
console.log(` ${cinza('O token expirou ou foi digitado errado.')}`);
|
|
183
|
+
} else {
|
|
184
|
+
console.log(` ${vermelho(neg('Este token não tem acesso ao JARVIS.'))}`);
|
|
185
|
+
console.log(` ${cinza('A distribuição é privada — o acesso é liberado por quem entregou o sistema.')}`);
|
|
186
|
+
}
|
|
187
|
+
console.log();
|
|
188
|
+
console.log(` ${fraco('Fale com quem forneceu o JARVIS para receber um token válido.')}`);
|
|
189
|
+
console.log();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* O harness roda em POSIX, não em Windows nativo: os 104 hooks do
|
|
194
|
+
* settings.json são invocados com `bash .../pyrun.sh` e 153 arquivos usam
|
|
195
|
+
* caminho POSIX. Instalar no PowerShell criaria um sistema que copia mas
|
|
196
|
+
* não funciona — pior que não instalar.
|
|
197
|
+
*/
|
|
198
|
+
function avisarWindows() {
|
|
199
|
+
if (process.platform !== 'win32') return true;
|
|
200
|
+
console.log(` ${vermelho(neg('O JARVIS precisa do WSL — não roda no Windows direto.'))}`);
|
|
201
|
+
console.log();
|
|
202
|
+
console.log(` ${cinza('O sistema usa bash para executar seus 104 hooks. No PowerShell')}`);
|
|
203
|
+
console.log(` ${cinza('ele até instalaria, mas não funcionaria.')}`);
|
|
204
|
+
console.log();
|
|
205
|
+
console.log(` ${branco('Abra o Ubuntu (WSL) e rode lá o mesmo comando:')}`);
|
|
206
|
+
console.log();
|
|
207
|
+
console.log(` ${fraco('wsl')}`);
|
|
208
|
+
console.log(` ${fraco('npx @fefsbenson/jarvis install')}`);
|
|
209
|
+
console.log();
|
|
210
|
+
console.log(` ${fraco('Não tem WSL? No PowerShell como administrador:')} ${cinza('wsl --install')}`);
|
|
211
|
+
console.log();
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function instalar(args) {
|
|
216
|
+
abertura();
|
|
217
|
+
|
|
218
|
+
if (!avisarWindows()) return 1;
|
|
219
|
+
|
|
220
|
+
const py = acharPython();
|
|
221
|
+
if (!py) {
|
|
222
|
+
console.log(` ${vermelho(neg('Falta Python 3.10 ou superior.'))}`);
|
|
223
|
+
console.log();
|
|
224
|
+
console.log(` ${cinza('O JARVIS roda em Python. O Node serve só para este baixador.')}`);
|
|
225
|
+
console.log();
|
|
226
|
+
console.log(` ${branco('No Ubuntu/WSL:')} ${fraco('sudo apt install python3 python3-venv')}`);
|
|
227
|
+
console.log(` ${branco('No macOS:')} ${fraco('brew install python@3.12')}`);
|
|
228
|
+
console.log();
|
|
229
|
+
return 1;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const destino = resolve(process.cwd(), args[0] || PASTA_PADRAO);
|
|
233
|
+
if (existsSync(destino) && readdirSync(destino).length) {
|
|
234
|
+
console.log(` ${vermelho(neg('A pasta ' + destino + ' já existe e não está vazia.'))}`);
|
|
235
|
+
console.log(` ${cinza('Escolha outro nome: ')}${fraco('npx @fefsbenson/jarvis install minha-pasta')}`);
|
|
236
|
+
console.log();
|
|
237
|
+
return 1;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log(` ${branco('Vou baixar o JARVIS e instalar aqui.')}`);
|
|
241
|
+
console.log(` ${fraco('Destino:')} ${branco(destino)}`);
|
|
242
|
+
console.log(` ${fraco('Python:')} ${branco(py.cmd + ' ' + py.versao)}`);
|
|
243
|
+
console.log();
|
|
244
|
+
console.log(` ${cinza('O JARVIS não é público: ele carrega conhecimento licenciado, então')}`);
|
|
245
|
+
console.log(` ${cinza('mora num repositório privado. Preciso de um token para baixá-lo.')}`);
|
|
246
|
+
console.log();
|
|
247
|
+
console.log(` ${fraco('Quem te entregou o sistema forneceu esse token junto.')}`);
|
|
248
|
+
console.log(` ${fraco('Se você mesmo publicou e tem o GitHub CLI aqui, use:')}`);
|
|
249
|
+
console.log(` ${cinza('JARVIS_TOKEN=$(gh auth token) npx @fefsbenson/jarvis install')}`);
|
|
250
|
+
console.log();
|
|
251
|
+
console.log(` ${fraco('(o token não aparece na tela enquanto você digita)')}`);
|
|
252
|
+
console.log();
|
|
253
|
+
|
|
254
|
+
const token = process.env.JARVIS_TOKEN || await perguntar('Token:', true);
|
|
255
|
+
if (!token) {
|
|
256
|
+
console.log(`\n ${fraco('Sem token, não há o que baixar. Cancelado.')}\n`);
|
|
257
|
+
return 130;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
console.log();
|
|
261
|
+
try {
|
|
262
|
+
await baixar(token, destino);
|
|
263
|
+
} catch (e) {
|
|
264
|
+
if (e.message === 'TOKEN_INVALIDO' || e.message === 'SEM_ACESSO') {
|
|
265
|
+
erroDeAcesso(e.message);
|
|
266
|
+
} else {
|
|
267
|
+
console.log(`\n ${vermelho(neg('Não consegui baixar.'))}`);
|
|
268
|
+
console.log(` ${cinza(e.message)}`);
|
|
269
|
+
console.log(`\n ${fraco('Verifique sua conexão e tente de novo.')}\n`);
|
|
270
|
+
}
|
|
271
|
+
return 1;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// entrega o comando ao instalador de verdade, que é Python
|
|
275
|
+
console.log();
|
|
276
|
+
const r = spawnSync(py.cmd, [...(py.args || []), join(destino, 'install.py'), ...args.slice(1)],
|
|
277
|
+
{ stdio: 'inherit', cwd: destino });
|
|
278
|
+
return r.status ?? 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function ajuda() {
|
|
282
|
+
abertura();
|
|
283
|
+
console.log(` ${branco('npx @fefsbenson/jarvis install')} ${fraco('baixa e instala em ./jarvis')}`);
|
|
284
|
+
console.log(` ${branco('npx @fefsbenson/jarvis install PASTA')} ${fraco('instala na pasta que você escolher')}`);
|
|
285
|
+
console.log();
|
|
286
|
+
console.log(` ${fraco('Precisa de: Node 18+, Python 3.10+ e o token de acesso.')}`);
|
|
287
|
+
console.log(` ${fraco('O token também pode vir da variável JARVIS_TOKEN.')}`);
|
|
288
|
+
console.log();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const [, , comando, ...resto] = process.argv;
|
|
292
|
+
if (comando === 'install') {
|
|
293
|
+
instalar(resto).then(cod => process.exit(cod));
|
|
294
|
+
} else {
|
|
295
|
+
ajuda();
|
|
296
|
+
process.exit(comando ? 1 : 0);
|
|
297
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fefsbenson/jarvis",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "JARVIS — sistema operacional de conhecimento e agentes para Claude Code",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "JARVIS — sistema operacional de conhecimento e agentes para Claude Code (Windows e Linux)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"jarvis": "bin/cli.js"
|
|
7
7
|
},
|
|
@@ -27,4 +27,4 @@
|
|
|
27
27
|
"knowledge-management",
|
|
28
28
|
"pragma"
|
|
29
29
|
]
|
|
30
|
-
}
|
|
30
|
+
}
|