primocode 9.8.0-beta.0 → 9.8.0-beta.2
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 +5 -4
- package/bin/primocode.js +73 -0
- package/lib/api.js +21 -0
- package/lib/claude-engine.js +630 -0
- package/lib/codex-engine.js +207 -0
- package/lib/local/cerebro.json +2116 -0
- package/lib/local/entrada.js +332 -0
- package/lib/local/motor-cli.js +90 -0
- package/lib/local/motor.js +264 -0
- package/lib/local/provedor.js +169 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# PrimoCode v9.
|
|
1
|
+
# PrimoCode v9.8.0-beta.2
|
|
2
2
|
|
|
3
3
|
Agente de engenharia brasileiro para o terminal, no estilo Claude Code.
|
|
4
4
|
Cria arquivos de verdade, roda comandos, **controla o navegador e o desktop** —
|
|
@@ -9,7 +9,7 @@ OpenRouter, e cada apelido (`top`/`main`/`fast`) é uma **corrente**: se um mode
|
|
|
9
9
|
está no limite de pedidos, o próximo atende. Você não vê o erro, e não paga nada.
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
▐▛███▜▌ Primo Code v9.
|
|
12
|
+
▐▛███▜▌ Primo Code v9.8.0-beta.2
|
|
13
13
|
▝▜█████▛▘ Bem-vindo de volta, Joel
|
|
14
14
|
▘▘ ▝▝ ~/primocode · /dir <pasta> muda
|
|
15
15
|
```
|
|
@@ -27,7 +27,7 @@ veja `/mascot` e `/name`.
|
|
|
27
27
|
| **Memória** | Cada projeto lembra o que foi feito, entre sessões | Esquece ao fechar |
|
|
28
28
|
| **Instalação** | Node puro, **zero dependências** — segundos | Pacotes e dependências |
|
|
29
29
|
| **Cara própria** | Mascote, nome e temas que você escolhe | Fixo |
|
|
30
|
-
| **Modelos** | Escolhidos pelo produto
|
|
30
|
+
| **Modelos** | Escolhidos pelo produto (`/effort` regula o esforço), ou a sua própria chave com `/api` | Preso ao provedor do fabricante |
|
|
31
31
|
|
|
32
32
|
Em uma frase: **é o poder de um agente de código no terminal, em português, controlando o seu computador de verdade — sem você precisar configurar chave de API nenhuma.**
|
|
33
33
|
|
|
@@ -287,7 +287,8 @@ primocode -f app.js "onde está o bug?" # com arquivo anexado
|
|
|
287
287
|
| `/voice` | Modo voz: uma orb, você fala, ele faz. O cérebro é o mesmo do terminal |
|
|
288
288
|
| `/skills` · `/marketplace` | O que ele sabe fazer bem. Tela navegável pelas setas, e "New Skill" para escrever a sua |
|
|
289
289
|
| `/connectors` | Quem está atendendo os seus pedidos (só mostra — não há o que configurar) |
|
|
290
|
-
| `/effort` | O esforço do agente, num slider (←/→, Enter confirma): do `low` ao `ultracode`. O modelo sai daí
|
|
290
|
+
| `/effort` | O esforço do agente, num slider (←/→, Enter confirma): do `low` ao `ultracode`. O modelo sai daí |
|
|
291
|
+
| `/api` | Roda com a SUA assinatura (Claude Code, Codex, sem chave) ou a SUA chave (Gemini, ChatGPT, Claude, Groq, OpenRouter, DeepSeek), direto do seu computador, sem o limite do servidor. `/api modelo <nome>` troca o modelo · `/api off` volta ao servidor |
|
|
291
292
|
| `/attach <arquivo>` | Anexa arquivo ao próximo pedido |
|
|
292
293
|
| `/detach` · `/files` | Remove / lista anexos |
|
|
293
294
|
| `/all` | Lista as 46 ferramentas que ele sabe usar, por grupo |
|
package/bin/primocode.js
CHANGED
|
@@ -21,6 +21,7 @@ const api = require('../lib/api');
|
|
|
21
21
|
const tools = require('../lib/tools');
|
|
22
22
|
const cfg = require('../lib/config');
|
|
23
23
|
const nomeProjeto = require('../lib/nome-projeto');
|
|
24
|
+
const provedorLocal = require('../lib/local/provedor');
|
|
24
25
|
const { runAct, interromper, ehTetoDeToken, ehTransitorio, esperaDoErro } = require('../lib/act');
|
|
25
26
|
const fala = require('../lib/fala');
|
|
26
27
|
const boasVindas = require('../lib/boas-vindas');
|
|
@@ -160,6 +161,7 @@ const SLASH_COMANDOS = [
|
|
|
160
161
|
['/skills', 'o que ele sabe fazer bem — ligue e desligue'],
|
|
161
162
|
['/marketplace', 'a tela das skills: navegue, ligue, crie'],
|
|
162
163
|
['/install-skill', 'instala uma skill de um arquivo'],
|
|
164
|
+
['/api', 'usa a SUA chave (Gemini, ChatGPT, Claude…) direto daqui, sem o limite do servidor'],
|
|
163
165
|
['/status', 'checa o servidor'],
|
|
164
166
|
['/connectors', 'quem está atendendo os seus pedidos'],
|
|
165
167
|
['/name', 'como ele te chama'],
|
|
@@ -172,6 +174,69 @@ const SLASH_COMANDOS = [
|
|
|
172
174
|
['/exit', 'sair'],
|
|
173
175
|
];
|
|
174
176
|
|
|
177
|
+
/* ── /api: a chave da própria pessoa ──────────────────────────────
|
|
178
|
+
* "Fica batendo no limite. Coloca um /provider onde você seleciona se é
|
|
179
|
+
* Gemini, ChatGPT etc., cola a key e ela roda local." (23/09/2026)
|
|
180
|
+
* Com provedor, o agente fala direto com a API da pessoa (lib/local/motor.js);
|
|
181
|
+
* sem, tudo segue pelo servidor como sempre. */
|
|
182
|
+
async function comandoApi(rest) {
|
|
183
|
+
const P = provedorLocal.PROVEDORES;
|
|
184
|
+
const ids = Object.keys(P);
|
|
185
|
+
const arg = String(rest || '').trim();
|
|
186
|
+
const atual = provedorLocal.atual();
|
|
187
|
+
|
|
188
|
+
if (/^(off|desliga[r]?|servidor|nenhum|sair)$/i.test(arg)) {
|
|
189
|
+
provedorLocal.desligar();
|
|
190
|
+
console.log(c.ok(' De volta ao servidor do PrimoCode.') + c.muted(' (a chave foi apagada desta máquina)'));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const trocaModelo = arg.match(/^(modelo|model)\s+(\S+)$/i);
|
|
194
|
+
if (trocaModelo) {
|
|
195
|
+
if (!atual) { console.log(c.warn(' Nenhum provedor configurado. Rode /api primeiro.')); return; }
|
|
196
|
+
provedorLocal.trocarModelo(trocaModelo[2]);
|
|
197
|
+
console.log(c.ok(` ${atual.nome} · modelo ${trocaModelo[2]}`));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const apelido = { claude: 'claude-code', gpt: 'chatgpt', openai: 'chatgpt' }[arg.toLowerCase()];
|
|
202
|
+
let id = apelido || ids.find((k) => k === arg.toLowerCase() || P[k].nome.toLowerCase().startsWith(arg.toLowerCase()) && arg);
|
|
203
|
+
if (!id) {
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log(' ' + c.bold('Com qual IA você quer rodar?') + c.muted(' a sua chave ou a sua assinatura, sem o limite do servidor'));
|
|
206
|
+
if (atual) console.log(' ' + c.muted('agora: ') + c.white(atual.cli ? atual.nome : `${atual.nome} · ${atual.modelo} · chave ${provedorLocal.mascarar(atual.chave)}`));
|
|
207
|
+
ids.forEach((k, i) => console.log(` ${c.brand(String(i + 1))} ${c.white(P[k].nome.padEnd(24))}${c.dim(P[k].dica)}`));
|
|
208
|
+
console.log(` ${c.brand('0')} ${c.white('Servidor do PrimoCode'.padEnd(24))}${c.dim('sem chave, com o limite do plano')}`);
|
|
209
|
+
const escolha = String(await ask(` ${c.brand('?')} Número: `)).trim();
|
|
210
|
+
if (escolha === '0') return comandoApi('off');
|
|
211
|
+
id = ids[Number(escolha) - 1];
|
|
212
|
+
if (!id) { console.log(c.muted(' Nada mudou.')); return; }
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const p = P[id];
|
|
216
|
+
// Claude Code e Codex não pedem chave: basta a ferramenta estar instalada
|
|
217
|
+
// e logada. Quem pensa é ela; quem executa é o PrimoCode.
|
|
218
|
+
if (p.cli) {
|
|
219
|
+
if (!require('../lib/local/motor-cli').instalado(id)) {
|
|
220
|
+
console.log(c.warn(` O ${p.nome} não está instalado nesta máquina.`) + c.muted(` Veja ${p.onde}`));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const salvo = provedorLocal.salvar({ provedor: id, modelo: p.modelos[0] });
|
|
224
|
+
console.log(c.ok(` Pronto: ${salvo.nome}`) + c.muted(' · usa a sua assinatura, sem chave'));
|
|
225
|
+
console.log(c.dim(` O ${p.nome} decide, o PrimoCode executa. /api off volta ao servidor`));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
console.log(c.muted(` Pegue a chave em `) + c.white(p.onde));
|
|
229
|
+
const chave = String(await askSecret(` ${c.brand('?')} Cole a chave do ${p.nome} (não aparece na tela): `)).trim();
|
|
230
|
+
if (!chave) { console.log(c.muted(' Nada mudou.')); return; }
|
|
231
|
+
const sp = new Spinner('conferindo a chave').start();
|
|
232
|
+
const r = await provedorLocal.conferir(id, chave);
|
|
233
|
+
sp.stop();
|
|
234
|
+
if (!r.ok) { console.log(c.warn(` ${r.error}`)); return; }
|
|
235
|
+
const salvo = provedorLocal.salvar({ provedor: id, chave, modelo: r.modelo });
|
|
236
|
+
console.log(c.ok(` Pronto: ${salvo.nome} · ${salvo.modelo}`) + c.muted(` · chave ${provedorLocal.mascarar(chave)}`));
|
|
237
|
+
console.log(c.dim(' Agora os pedidos vão direto daqui, com a sua cota. /api modelo <nome> troca o modelo · /api off volta ao servidor'));
|
|
238
|
+
}
|
|
239
|
+
|
|
175
240
|
// ── /effort: o slider de esforço (estilo Claude Code) ──────────────────
|
|
176
241
|
// Régua com os níveis, o marcador ▲ embaixo do escolhido, "Faster" à
|
|
177
242
|
// esquerda e "Smarter" à direita. ←/→ move, Enter confirma, Esc cancela.
|
|
@@ -2084,6 +2149,11 @@ async function handleSlash(text) {
|
|
|
2084
2149
|
* Eles não somem calados. Quem tem o dedo viciado em `/claude` e
|
|
2085
2150
|
* bate num "comando não existe" conclui que a atualização quebrou
|
|
2086
2151
|
* alguma coisa — e não vai procurar no /help, vai desinstalar. */
|
|
2152
|
+
case 'api': {
|
|
2153
|
+
await comandoApi(rest);
|
|
2154
|
+
break;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2087
2157
|
case 'claude': case 'gpt': case 'codex': case 'key': case 'keys': {
|
|
2088
2158
|
console.log(c.muted(' Não existe mais provedor para configurar.'));
|
|
2089
2159
|
console.log(c.muted(' A API já vem com o PrimoCode: entrou na conta, pode usar.'));
|
|
@@ -2141,6 +2211,9 @@ function conferirServidor() {
|
|
|
2141
2211
|
jaConferiu = true;
|
|
2142
2212
|
const minimo = (pkg.primocode && pkg.primocode.servidorMinimo) || '';
|
|
2143
2213
|
if (!minimo) return;
|
|
2214
|
+
// Com a chave própria (/api), quem pensa não é o servidor: a versão dele
|
|
2215
|
+
// não muda nada no que a pessoa pede.
|
|
2216
|
+
if (provedorLocal.atual()) return;
|
|
2144
2217
|
const servidor = state.config.server;
|
|
2145
2218
|
Promise.resolve()
|
|
2146
2219
|
.then(() => api.getHealth(servidor, state.config.token))
|
package/lib/api.js
CHANGED
|
@@ -201,14 +201,31 @@ function requestStream(serverUrl, endpoint, payload, onEvent, token, sinal) {
|
|
|
201
201
|
});
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
/* Com um provedor configurado (/api), estas quatro rotas rodam AQUI,
|
|
205
|
+
com a chave da pessoa, em vez de ir ao servidor — ver lib/local/motor.js.
|
|
206
|
+
O resto (login, transcrição, conectores) continua no servidor. */
|
|
207
|
+
function local() {
|
|
208
|
+
try {
|
|
209
|
+
const atual = require('./local/provedor.js').atual();
|
|
210
|
+
if (!atual) return null;
|
|
211
|
+
// Claude Code e Codex: a ferramenta de fora é o cérebro.
|
|
212
|
+
if (atual.cli) return require('./local/motor-cli.js').criar(atual.id);
|
|
213
|
+
return require('./local/motor.js');
|
|
214
|
+
} catch { return null; }
|
|
215
|
+
}
|
|
216
|
+
|
|
204
217
|
// Agente autônomo. `payload` carrega a conversa completa (messages).
|
|
205
218
|
function requestAct(serverUrl, payload, onEvent) {
|
|
219
|
+
const m = local();
|
|
220
|
+
if (m) return m.requestAct(serverUrl, payload, onEvent);
|
|
206
221
|
const { token, sinal, ...body } = payload;
|
|
207
222
|
return requestStream(serverUrl, '/api/act/stream', body, onEvent, token, sinal);
|
|
208
223
|
}
|
|
209
224
|
|
|
210
225
|
// Chat puro.
|
|
211
226
|
function requestChat(serverUrl, payload, onEvent) {
|
|
227
|
+
const m = local();
|
|
228
|
+
if (m) return m.requestChat(serverUrl, payload, onEvent);
|
|
212
229
|
const { token, sinal, ...body } = payload;
|
|
213
230
|
return requestStream(serverUrl, '/api/chat/stream', body, onEvent, token, sinal);
|
|
214
231
|
}
|
|
@@ -216,6 +233,8 @@ function requestChat(serverUrl, payload, onEvent) {
|
|
|
216
233
|
// Resumo incremental da conversa. Vai e volta pequeno: manda o resumo de
|
|
217
234
|
// antes + o que é novo, recebe o resumo atualizado.
|
|
218
235
|
function requestResumo(serverUrl, payload) {
|
|
236
|
+
const m = local();
|
|
237
|
+
if (m) return m.requestResumo(serverUrl, payload);
|
|
219
238
|
const { token, ...body } = payload;
|
|
220
239
|
return request(serverUrl, '/api/resumir', body, token);
|
|
221
240
|
}
|
|
@@ -236,6 +255,8 @@ function requestRefino(serverUrl, payload) {
|
|
|
236
255
|
|
|
237
256
|
// O plano: a tarefa grande dividida em passos, para uma chamada por pedaço.
|
|
238
257
|
function requestPlano(serverUrl, payload) {
|
|
258
|
+
const m = local();
|
|
259
|
+
if (m) return m.requestPlano(serverUrl, payload);
|
|
239
260
|
const { token, ...body } = payload;
|
|
240
261
|
return request(serverUrl, '/api/plano', body, token);
|
|
241
262
|
}
|