primocode 8.0.1 → 8.0.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/bin/primocode.js CHANGED
@@ -24,6 +24,18 @@ const pasta = require('../lib/pasta');
24
24
  const catalogo = require('../lib/catalogo');
25
25
  const effort = require('../lib/effort');
26
26
 
27
+ // Rede de segurança de último recurso: sem isto, uma exceção fora de um
28
+ // try/catch (ex.: dentro de um callback de socket, como o parser de SSE) não
29
+ // era pega por ninguém e derrubava o processo INTEIRO em silêncio — o usuário
30
+ // via a resposta parar no meio e cair de volta pro shell, sem mensagem
31
+ // nenhuma. Agora vira um erro visível, e o processo continua de pé.
32
+ process.on('uncaughtException', (e) => {
33
+ console.log('\n' + c.err(ui.friendlyError(e)));
34
+ });
35
+ process.on('unhandledRejection', (e) => {
36
+ console.log('\n' + c.err(ui.friendlyError(e instanceof Error ? e : new Error(String(e)))));
37
+ });
38
+
27
39
  // A pasta de onde o comando foi dado. Não é mais onde ele trabalha (o padrão é
28
40
  // ~/primocode), mas continua servindo de ponto de partida para achar pasta que
29
41
  // o usuário mencionar por nome relativo.
package/lib/act.js CHANGED
@@ -165,7 +165,7 @@ function buildMemoryContext(projectDir, projectName) {
165
165
  const geral = cfg.readGeneralMemory();
166
166
  if (geral.trim()) parts.push(`[memory-geral.md]\n${geral}`);
167
167
  const projeto = cfg.readProjectMemory(projectDir);
168
- if (projeto.trim()) parts.push(`[${projectName}/memory.md]\n${projeto}`);
168
+ if (projeto.trim()) parts.push(`[${projectName || 'projeto'}/memory.md]\n${projeto}`);
169
169
  return parts.join('\n\n');
170
170
  }
171
171
 
@@ -342,7 +342,12 @@ async function runAct(userPrompt, opts) {
342
342
  // Nada de arquivo mexido = nada para lembrar. E grava em `pastaAtual`, não em
343
343
  // `projectDir`: quando a pasta do projeto nasceu no meio do caminho, a memória
344
344
  // precisa ir para ela, não para a raiz onde a sessão começou.
345
- if (!subagent && projectName && temPasta) {
345
+ //
346
+ // `projectName` NÃO entra na condição: ele só rotula a memória no prompt
347
+ // (buildMemoryContext), e sessão sem projeto nomeado (ex.: primeiro pedido
348
+ // antes de /project) tem `projectName` undefined mesmo já tendo mexido em
349
+ // arquivo de verdade — a memória era descartada nesse caso, sempre.
350
+ if (!subagent && temPasta) {
346
351
  cfg.appendProjectMemory(pastaAtual, `**Pedido:** ${userPrompt.slice(0, 300)}\n**Resultado:** ${finalText.slice(0, 500)}`);
347
352
  }
348
353
 
package/lib/api.js CHANGED
@@ -90,7 +90,19 @@ function requestStream(serverUrl, endpoint, payload, onEvent, token) {
90
90
  if (!line.startsWith('data: ')) continue;
91
91
  let evt;
92
92
  try { evt = JSON.parse(line.slice(6)); } catch { continue; }
93
- onEvent(evt);
93
+ // onEvent roda dentro de um callback de socket, fora de
94
+ // qualquer try/catch de quem chamou requestStream. Uma
95
+ // exceção aqui não seria pega por ninguém — sem process.on
96
+ // ('uncaughtException') no CLI, isso derrubava o processo
97
+ // inteiro em silêncio (era o "cai fora" sem mensagem
98
+ // nenhuma). Agora vira rejeição normal da Promise.
99
+ try {
100
+ onEvent(evt);
101
+ } catch (e) {
102
+ settled = true;
103
+ reject(e);
104
+ return;
105
+ }
94
106
  if (evt.done) finish();
95
107
  }
96
108
  });
package/lib/catalogo.js CHANGED
@@ -91,6 +91,11 @@ const GRUPOS = [
91
91
  itens: [
92
92
  { tool: 'write_todos', escreve: false, faz: 'monta o plano e vai marcando o que terminou' },
93
93
  { tool: 'pesquisar_referencia', escreve: false, faz: 'lê docs e exemplos antes de escrever — sobe a qualidade' },
94
+ // Vai para memory-geral.md, FORA da pasta do projeto — por isso não
95
+ // é write_file/edit_file (a sandbox de resolveInProject bloqueia
96
+ // qualquer caminho fora do projeto, e é assim mesmo que tem que
97
+ // ser para os outros casos). Esta tool é a única porta pra lá.
98
+ { tool: 'remember_general', escreve: false, faz: 'grava algo sobre o usuário que vale para todo projeto (memory-geral.md)' },
94
99
  // Estas duas o loop do agente atende (lib/act.js), não o tools.execute.
95
100
  { tool: 'spawn_agent', escreve: false, faz: 'chama um subagente para uma parte da tarefa', noLoop: true },
96
101
  { tool: 'finish', escreve: false, faz: 'encerra dizendo o que fez', noLoop: true },
package/lib/config.js CHANGED
@@ -151,6 +151,18 @@ function appendProjectMemory(dir, entry) {
151
151
  } catch {}
152
152
  }
153
153
 
154
+ // A contraparte de appendProjectMemory, para o que vale em TODOS os projetos
155
+ // (nome do usuário, preferência, decisão de longo prazo). Existia a promessa
156
+ // no prompt — "escreve aqui o que descobrir sobre você" — mas nenhuma função
157
+ // gravava de fato: só ensureStructure() criava o template uma vez.
158
+ function appendGeneralMemory(entry) {
159
+ if (!entry) return;
160
+ try {
161
+ ensureStructure();
162
+ fs.appendFileSync(GENERAL_MEMORY, `\n### ${today()}\n${entry}\n`, 'utf-8');
163
+ } catch {}
164
+ }
165
+
154
166
  function loadConfig() {
155
167
  ensureStructure();
156
168
  let file = {};
@@ -198,5 +210,5 @@ module.exports = {
198
210
  CONFIG_DIR, CONFIG_FILE, HISTORY_FILE, ROOT_DIR, GENERAL_MEMORY,
199
211
  ensureStructure, slugify,
200
212
  createProjectDir, getProjectDir, listProjects, findSimilarProject,
201
- readGeneralMemory, readProjectMemory, appendProjectMemory,
213
+ readGeneralMemory, readProjectMemory, appendProjectMemory, appendGeneralMemory,
202
214
  };
package/lib/modo.js CHANGED
@@ -37,6 +37,13 @@ const VERBOS = [
37
37
  ];
38
38
  const RE_VERBO = new RegExp(`(^|\\s)(${VERBOS.join('|')})\\b`, 'i');
39
39
 
40
+ // Pedido sem verbo de comando, só desejo: "quero um jogo da velha", "preciso
41
+ // de uma landing page". Muito comum em português — e sem isto caía direto no
42
+ // "sem pista de tarefa" porque não tem 'criar'/'fazer' escrito. A diferença
43
+ // para RE_CONCEITUAL é que aqui não vem pergunta ("como", "por que", "o que
44
+ // é") — só o pedido do que a pessoa quer que exista.
45
+ const RE_DESEJO = /\b(quero|queria|querendo|gostaria de|necessito de|precis[ao] de|precisava de)\b/i;
46
+
40
47
  // Coisas que só existem quando há trabalho de arquivo/máquina envolvido.
41
48
  const RE_ARTEFATO = /\.(js|ts|tsx|jsx|html|css|json|md|py|sh|yml|yaml|txt|csv|env)\b|[\w-]+\/[\w-]/i;
42
49
  const RE_FERRAMENTA = /\b(navegador|browser|desktop|terminal|shell|git|npm|node|deploy|servidor|localhost|porta \d+|screenshot|print da tela|mouse|teclado|janela|[áa]rea de trabalho|aplicativo|[íi]cone)\b/i;
@@ -65,6 +72,7 @@ function escolherModo(texto) {
65
72
 
66
73
  if (RE_ARTEFATO.test(t)) return { modo: 'primocode', motivo: 'cita arquivo ou caminho' };
67
74
  if (RE_VERBO.test(t)) return { modo: 'primocode', motivo: 'pede uma ação' };
75
+ if (RE_DESEJO.test(t)) return { modo: 'primocode', motivo: 'expressa o que quer que exista' };
68
76
  if (RE_FERRAMENTA.test(t)) return { modo: 'primocode', motivo: 'menciona ferramenta ou máquina' };
69
77
  if (RE_PASTA.test(t)) return { modo: 'primocode', motivo: 'fala de arquivo ou projeto' };
70
78
 
package/lib/tools.js CHANGED
@@ -15,6 +15,7 @@ const browser = require('./browser');
15
15
  const desktop = require('./desktop');
16
16
  const referencia = require('./referencia');
17
17
  const studio = require('./studio');
18
+ const cfg = require('./config');
18
19
 
19
20
  const IGNORAR = new Set(['node_modules', '.git', 'dist', 'build', '.next', 'coverage', '.cache', 'vendor']);
20
21
  const MAX_ARQUIVOS_VARREDURA = 5000;
@@ -399,6 +400,16 @@ async function despachar(name, args, ctx) {
399
400
  paginas: Math.max(1, Math.min(5, Number(args.paginas) || 3)),
400
401
  });
401
402
 
403
+ // memory-geral.md fica FORA da pasta do projeto — write_file/edit_file
404
+ // não alcançam por design (resolveInProject bloqueia ../ de propósito).
405
+ // Esta é a única porta para lá, sem reabrir a sandbox.
406
+ case 'remember_general': {
407
+ const entry = String(args.fato || args.entry || '').trim();
408
+ if (!entry) return { ok: false, error: 'Diga o que lembrar (fato).' };
409
+ cfg.appendGeneralMemory(entry);
410
+ return { ok: true, gravado: entry };
411
+ }
412
+
402
413
  // ── Navegador controlado (CDP) — o agente age numa página real ──
403
414
  case 'browser_open': {
404
415
  const alvo = /^https?:\/\//i.test(args.url || '')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primocode",
3
- "version": "8.0.1",
3
+ "version": "8.0.2",
4
4
  "description": "PrimoCode — agente de engenharia com IA e cursor próprio. Modelos grátis. Cria arquivos, roda comandos, controla navegador e desktop: abre apps, clica em botões e ícones pelo nome, digita e usa atalhos.",
5
5
  "main": "bin/primocode.js",
6
6
  "bin": {