@fefsbenson/jarvis 1.0.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/LICENSE +35 -0
- package/README.md +38 -0
- package/bin/cli.js +250 -0
- package/package.json +30 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
JARVIS — Licença de Uso
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Felipe Brandão / PRAGMA
|
|
4
|
+
|
|
5
|
+
CONCESSÃO
|
|
6
|
+
Este software é licenciado, não vendido, para uso interno do licenciado
|
|
7
|
+
identificado no contrato de entrega. É permitido:
|
|
8
|
+
|
|
9
|
+
· instalar e executar em quantas máquinas o licenciado operar;
|
|
10
|
+
· modificar o código, as regras, as skills e os agentes para uso próprio;
|
|
11
|
+
· ingerir e processar material próprio com o sistema.
|
|
12
|
+
|
|
13
|
+
RESTRIÇÕES
|
|
14
|
+
Não é permitido, sem autorização escrita:
|
|
15
|
+
|
|
16
|
+
· redistribuir, revender, sublicenciar ou publicar o sistema, no todo
|
|
17
|
+
ou em parte, a terceiros;
|
|
18
|
+
· oferecer o sistema como serviço a terceiros (SaaS);
|
|
19
|
+
· remover a atribuição de autoria.
|
|
20
|
+
|
|
21
|
+
MATERIAL DE TERCEIROS
|
|
22
|
+
A base de conhecimento em knowledge/external/ contém conhecimento destilado
|
|
23
|
+
de material de autoria de terceiros, mantido com atribuição à fonte original.
|
|
24
|
+
Esse conteúdo permanece propriedade dos respectivos autores e é fornecido
|
|
25
|
+
para uso interno do licenciado — sua redistribuição é vedada.
|
|
26
|
+
|
|
27
|
+
SEM GARANTIA
|
|
28
|
+
O software é fornecido "no estado em que se encontra", sem garantia de
|
|
29
|
+
qualquer natureza. O autor não responde por perda de dados, interrupção de
|
|
30
|
+
operação ou decisões tomadas com apoio do sistema.
|
|
31
|
+
|
|
32
|
+
DEPENDÊNCIAS
|
|
33
|
+
O sistema requer Claude Code (Anthropic), sujeito aos termos de uso da
|
|
34
|
+
Anthropic, e opcionalmente serviços de terceiros cujas credenciais o
|
|
35
|
+
licenciado fornece e cujos termos e custos são de sua responsabilidade.
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# JARVIS
|
|
2
|
+
|
|
3
|
+
Sistema operacional de conhecimento e agentes para Claude Code.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @pragma/jarvis install
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Este pacote é o **instalador**. Ele baixa o sistema de uma distribuição
|
|
10
|
+
privada e conduz a instalação — 5 passos, cerca de 2 minutos.
|
|
11
|
+
|
|
12
|
+
## Requisitos
|
|
13
|
+
|
|
14
|
+
- **[Claude Code](https://claude.ai/claude-code)** (Pro ou Max) — é onde o JARVIS roda
|
|
15
|
+
- **Python 3.10+** — o sistema é Python; o Node serve só para este baixador
|
|
16
|
+
- **Token de acesso** — fornecido por quem entregou o sistema
|
|
17
|
+
|
|
18
|
+
## O que ele faz
|
|
19
|
+
|
|
20
|
+
| Passo | |
|
|
21
|
+
|---|---|
|
|
22
|
+
| 1 | Confere o ambiente e diz o que falta |
|
|
23
|
+
| 2 | Pergunta quem é você (nome, tratamento, empresa) |
|
|
24
|
+
| 3 | Coleta as credenciais que você quiser usar — nenhuma é obrigatória |
|
|
25
|
+
| 4 | Instala num ambiente Python isolado |
|
|
26
|
+
| 5 | **Verifica que funciona** — não só que copiou |
|
|
27
|
+
|
|
28
|
+
## Uso
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx @pragma/jarvis install # instala em ./jarvis
|
|
32
|
+
npx @pragma/jarvis install PASTA # instala onde você quiser
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
O token também pode vir da variável `JARVIS_TOKEN`.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
PRAGMA · by Felipe Brandão
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
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 @pragma/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
|
+
/** Precisa de Python — o instalador de verdade é ele. */
|
|
72
|
+
function acharPython() {
|
|
73
|
+
for (const cmd of ['python3', 'python']) {
|
|
74
|
+
const r = spawnSync(cmd, ['-c', 'import sys;print(sys.version_info[:2])'],
|
|
75
|
+
{ encoding: 'utf8' });
|
|
76
|
+
if (r.status === 0) {
|
|
77
|
+
const m = r.stdout.match(/\((\d+),\s*(\d+)\)/);
|
|
78
|
+
if (m && (+m[1] > 3 || (+m[1] === 3 && +m[2] >= 10))) return { cmd, versao: `${m[1]}.${m[2]}` };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function api(caminho, token, aceitar = 'application/vnd.github+json') {
|
|
85
|
+
const r = await fetch(`https://api.github.com${caminho}`, {
|
|
86
|
+
headers: {
|
|
87
|
+
Authorization: `Bearer ${token}`,
|
|
88
|
+
Accept: aceitar,
|
|
89
|
+
'User-Agent': 'jarvis-installer',
|
|
90
|
+
'X-GitHub-Api-Version': '2022-11-28',
|
|
91
|
+
},
|
|
92
|
+
redirect: 'follow',
|
|
93
|
+
});
|
|
94
|
+
return r;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function barra(feito, total) {
|
|
98
|
+
const largura = 28;
|
|
99
|
+
const pct = total ? feito / total : 0;
|
|
100
|
+
const cheio = Math.round(pct * largura);
|
|
101
|
+
return ` ${laranja('█'.repeat(cheio))}${fraco('░'.repeat(largura - cheio))} ${cinza(`${Math.round(pct * 100)}%`)}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function baixar(token, destino) {
|
|
105
|
+
// 1. qual é a versão mais recente
|
|
106
|
+
const rel = await api(`/repos/${REPO}/releases/latest`, token);
|
|
107
|
+
if (rel.status === 401) throw new Error('TOKEN_INVALIDO');
|
|
108
|
+
if (rel.status === 404) throw new Error('SEM_ACESSO');
|
|
109
|
+
if (!rel.ok) throw new Error(`GitHub respondeu ${rel.status}`);
|
|
110
|
+
const dados = await rel.json();
|
|
111
|
+
|
|
112
|
+
const asset = (dados.assets || []).find(a => a.name.endsWith('.tar.gz'));
|
|
113
|
+
if (!asset) throw new Error('Release sem pacote .tar.gz');
|
|
114
|
+
|
|
115
|
+
console.log(` ${verde('✓')} ${branco('Versão')} ${cinza(dados.tag_name)} ${fraco((asset.size / 1048576).toFixed(1) + ' MB')}`);
|
|
116
|
+
|
|
117
|
+
// 2. baixa o tarball (asset privado exige Accept: octet-stream)
|
|
118
|
+
const bin = await api(`/repos/${REPO}/releases/assets/${asset.id}`, token,
|
|
119
|
+
'application/octet-stream');
|
|
120
|
+
if (!bin.ok) throw new Error(`download falhou (${bin.status})`);
|
|
121
|
+
|
|
122
|
+
const tmp = join(tmpdir(), `jarvis-${Date.now()}.tar.gz`);
|
|
123
|
+
const total = Number(bin.headers.get('content-length')) || asset.size;
|
|
124
|
+
let feito = 0;
|
|
125
|
+
let ultimo = 0;
|
|
126
|
+
|
|
127
|
+
const origem = Readable.fromWeb(bin.body);
|
|
128
|
+
origem.on('data', pedaco => {
|
|
129
|
+
feito += pedaco.length;
|
|
130
|
+
const agora = Date.now();
|
|
131
|
+
// A barra so redesenha em TTY: com o output capturado (pipe, log, CI) o
|
|
132
|
+
// \r nao apaga a linha e o progresso vira uma parede de barras.
|
|
133
|
+
if (tty && agora - ultimo > 200) {
|
|
134
|
+
ultimo = agora;
|
|
135
|
+
process.stdout.write('\r' + barra(feito, total));
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
await pipeline(origem, createWriteStream(tmp));
|
|
139
|
+
if (tty) process.stdout.write('\r' + barra(total, total) + '\n');
|
|
140
|
+
else console.log(` ${verde('✓')} ${branco('Baixado')} ${fraco((total / 1048576).toFixed(1) + ' MB')}`);
|
|
141
|
+
|
|
142
|
+
// 3. extrai
|
|
143
|
+
mkdirSync(destino, { recursive: true });
|
|
144
|
+
const tar = spawnSync('tar', ['xzf', tmp, '-C', destino, '--strip-components=1'],
|
|
145
|
+
{ encoding: 'utf8' });
|
|
146
|
+
if (tar.status !== 0) throw new Error(`tar falhou: ${(tar.stderr || '').slice(0, 120)}`);
|
|
147
|
+
|
|
148
|
+
const n = contar(destino);
|
|
149
|
+
console.log(` ${verde('✓')} ${branco('Extraído')} ${fraco(n.toLocaleString('pt-BR') + ' arquivos')}`);
|
|
150
|
+
return destino;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function contar(dir) {
|
|
154
|
+
let n = 0;
|
|
155
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
156
|
+
if (e.name === 'node_modules' || e.name === '.git') continue;
|
|
157
|
+
n += e.isDirectory() ? contar(join(dir, e.name)) : 1;
|
|
158
|
+
}
|
|
159
|
+
return n;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function erroDeAcesso(tipo) {
|
|
163
|
+
console.log();
|
|
164
|
+
if (tipo === 'TOKEN_INVALIDO') {
|
|
165
|
+
console.log(` ${vermelho(neg('Token inválido.'))}`);
|
|
166
|
+
console.log(` ${cinza('O token expirou ou foi digitado errado.')}`);
|
|
167
|
+
} else {
|
|
168
|
+
console.log(` ${vermelho(neg('Este token não tem acesso ao JARVIS.'))}`);
|
|
169
|
+
console.log(` ${cinza('A distribuição é privada — o acesso é liberado por quem entregou o sistema.')}`);
|
|
170
|
+
}
|
|
171
|
+
console.log();
|
|
172
|
+
console.log(` ${fraco('Fale com quem forneceu o JARVIS para receber um token válido.')}`);
|
|
173
|
+
console.log();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function instalar(args) {
|
|
177
|
+
abertura();
|
|
178
|
+
|
|
179
|
+
const py = acharPython();
|
|
180
|
+
if (!py) {
|
|
181
|
+
console.log(` ${vermelho(neg('Falta Python 3.10 ou superior.'))}`);
|
|
182
|
+
console.log();
|
|
183
|
+
console.log(` ${cinza('O JARVIS roda em Python. O Node serve só para este baixador.')}`);
|
|
184
|
+
console.log();
|
|
185
|
+
console.log(` ${branco('No Ubuntu/WSL:')} ${fraco('sudo apt install python3 python3-venv')}`);
|
|
186
|
+
console.log(` ${branco('No macOS:')} ${fraco('brew install python@3.12')}`);
|
|
187
|
+
console.log();
|
|
188
|
+
return 1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const destino = resolve(process.cwd(), args[0] || PASTA_PADRAO);
|
|
192
|
+
if (existsSync(destino) && readdirSync(destino).length) {
|
|
193
|
+
console.log(` ${vermelho(neg('A pasta ' + destino + ' já existe e não está vazia.'))}`);
|
|
194
|
+
console.log(` ${cinza('Escolha outro nome: ')}${fraco('npx @pragma/jarvis install minha-pasta')}`);
|
|
195
|
+
console.log();
|
|
196
|
+
return 1;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log(` ${branco('Vou baixar o JARVIS e instalar aqui.')}`);
|
|
200
|
+
console.log(` ${fraco('Destino:')} ${branco(destino)}`);
|
|
201
|
+
console.log(` ${fraco('Python:')} ${branco(py.cmd + ' ' + py.versao)}`);
|
|
202
|
+
console.log();
|
|
203
|
+
console.log(` ${cinza('A distribuição é privada. Cole o token de acesso que você recebeu.')}`);
|
|
204
|
+
console.log(` ${fraco('(o token não aparece na tela)')}`);
|
|
205
|
+
console.log();
|
|
206
|
+
|
|
207
|
+
const token = process.env.JARVIS_TOKEN || await perguntar('Token:', true);
|
|
208
|
+
if (!token) {
|
|
209
|
+
console.log(`\n ${fraco('Sem token, não há o que baixar. Cancelado.')}\n`);
|
|
210
|
+
return 130;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log();
|
|
214
|
+
try {
|
|
215
|
+
await baixar(token, destino);
|
|
216
|
+
} catch (e) {
|
|
217
|
+
if (e.message === 'TOKEN_INVALIDO' || e.message === 'SEM_ACESSO') {
|
|
218
|
+
erroDeAcesso(e.message);
|
|
219
|
+
} else {
|
|
220
|
+
console.log(`\n ${vermelho(neg('Não consegui baixar.'))}`);
|
|
221
|
+
console.log(` ${cinza(e.message)}`);
|
|
222
|
+
console.log(`\n ${fraco('Verifique sua conexão e tente de novo.')}\n`);
|
|
223
|
+
}
|
|
224
|
+
return 1;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// entrega o comando ao instalador de verdade, que é Python
|
|
228
|
+
console.log();
|
|
229
|
+
const r = spawnSync(py.cmd, [join(destino, 'install.py'), ...args.slice(1)],
|
|
230
|
+
{ stdio: 'inherit', cwd: destino });
|
|
231
|
+
return r.status ?? 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function ajuda() {
|
|
235
|
+
abertura();
|
|
236
|
+
console.log(` ${branco('npx @pragma/jarvis install')} ${fraco('baixa e instala em ./jarvis')}`);
|
|
237
|
+
console.log(` ${branco('npx @pragma/jarvis install PASTA')} ${fraco('instala na pasta que você escolher')}`);
|
|
238
|
+
console.log();
|
|
239
|
+
console.log(` ${fraco('Precisa de: Node 18+, Python 3.10+ e o token de acesso.')}`);
|
|
240
|
+
console.log(` ${fraco('O token também pode vir da variável JARVIS_TOKEN.')}`);
|
|
241
|
+
console.log();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const [, , comando, ...resto] = process.argv;
|
|
245
|
+
if (comando === 'install') {
|
|
246
|
+
instalar(resto).then(cod => process.exit(cod));
|
|
247
|
+
} else {
|
|
248
|
+
ajuda();
|
|
249
|
+
process.exit(comando ? 1 : 0);
|
|
250
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fefsbenson/jarvis",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "JARVIS — sistema operacional de conhecimento e agentes para Claude Code",
|
|
5
|
+
"bin": {
|
|
6
|
+
"jarvis": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
18
|
+
"author": "Felipe Brandão / PRAGMA",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/fefsbenson/jarvis-entrega.git"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"claude-code",
|
|
25
|
+
"jarvis",
|
|
26
|
+
"agents",
|
|
27
|
+
"knowledge-management",
|
|
28
|
+
"pragma"
|
|
29
|
+
]
|
|
30
|
+
}
|