primocode 8.9.0 → 8.10.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/primocode.js CHANGED
@@ -604,9 +604,19 @@ async function sendPrompt(userText) {
604
604
  *
605
605
  * Falhou? O pedido do usuário, inteiro, como ele escreveu.
606
606
  */
607
+ // A ÚNICA divisão que compensa: DESCOBRIR uma coisa e CRIAR outra com ela.
608
+ // O resto é pedido de uma fase só, e mandar para o planejador era pagar uma
609
+ // chamada de API para ouvir "não divida" — quando o modelo não resolvia
610
+ // inventar passos que ninguém pediu, que era o "faz coisas nada a ver".
611
+ const RE_DESCOBRIR = /\b(pesquis|busca|procur|descubr|investig|analis|leia|estud|olh[ae] (o site|a p[áa]gina)|ver o que)\w*/i;
612
+ const RE_CRIAR_DEPOIS = /\b(cri[ae]|faz|faça|mont[ae]|ger[ae]|escrev[ae]|produz|desenvolv)\w*/i;
613
+
607
614
  async function dividirTarefa(pedido) {
608
615
  const inteiro = [{ titulo: 'tarefa', pedido }];
609
616
  if (!pedido || pedido.trim().length < 12) return inteiro;
617
+ // Sem as duas fases no texto, nem chama o servidor: mais rápido, e sem
618
+ // dar ao modelo a chance de dividir o que não devia.
619
+ if (!(RE_DESCOBRIR.test(pedido) && RE_CRIAR_DEPOIS.test(pedido))) return inteiro;
610
620
  const sp = new Spinner('Primo Code pensando').start();
611
621
  try {
612
622
  const r = await api.requestPlano(state.config.server, {
package/lib/referencia.js CHANGED
@@ -224,13 +224,17 @@ const GENERICAS = new Set(['sobre', 'empresa', 'company', 'overview', 'about', '
224
224
  * "paris" e não tem nada a ver). Consulta de uma palavra só se contenta com
225
225
  * ela mesma.
226
226
  */
227
- function relevante(cand, palavras) {
228
- if (!palavras.length) return true;
227
+ function quantoBate(cand, palavras) {
229
228
  const alvo = `${cand.titulo || ''} ${cand.url || ''}`
230
229
  .normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
231
230
  let batidas = 0;
232
231
  for (const p of palavras) if (alvo.includes(p)) batidas++;
233
- return batidas >= Math.min(2, palavras.length);
232
+ return batidas;
233
+ }
234
+
235
+ function relevante(cand, palavras) {
236
+ if (!palavras.length) return true;
237
+ return quantoBate(cand, palavras) >= Math.min(2, palavras.length);
234
238
  }
235
239
 
236
240
  /**
@@ -482,6 +486,9 @@ async function pesquisar({ consulta, paginas = 3 }) {
482
486
  }
483
487
 
484
488
  const lidas = [];
489
+ // Os chutes de domínio ficam de lado até o fim: só então dá para saber
490
+ // qual deles fala mais do assunto.
491
+ const chutesLidos = [];
485
492
  for (const cand of candidatos) {
486
493
  if (lidas.length >= paginas) break;
487
494
  const html = await pegar(cand.url);
@@ -493,7 +500,16 @@ async function pesquisar({ consulta, paginas = 3 }) {
493
500
  // parisgroup.com (um grupo de varejo no exterior) e parisgroup.ai (a
494
501
  // empresa que o usuário quis). O nome não distingue os dois — o texto
495
502
  // da página, sim. Sem esta prova o agente escreveria sobre a errada.
496
- if (cand.nota === 'site provável da empresa' && !relevante({ titulo: texto.slice(0, 3000), url: cand.url }, palavras)) continue;
503
+ const ehChute = cand.nota === 'site provável da empresa';
504
+ if (ehChute) {
505
+ const nota = quantoBate({ titulo: texto.slice(0, 4000), url: cand.url }, palavras);
506
+ if (nota < Math.min(2, palavras.length)) continue;
507
+ // Passar não basta: entre dois domínios do MESMO nome, fica o que
508
+ // fala mais do assunto. parisgroup.ai e parisgroup.co os dois
509
+ // "batiam", e o agente recebia as duas empresas como se fossem uma.
510
+ chutesLidos.push({ nota, item: { titulo: cand.titulo, url: cand.url, nota: cand.nota, trecho: texto.slice(0, MAX_TEXTO) } });
511
+ continue;
512
+ }
497
513
  lidas.push({
498
514
  titulo: cand.titulo,
499
515
  url: cand.url,
@@ -502,6 +518,14 @@ async function pesquisar({ consulta, paginas = 3 }) {
502
518
  });
503
519
  }
504
520
 
521
+ // O melhor chute entra na frente: quando a empresa tem site, ele é a
522
+ // fonte mais confiável que existe sobre ela.
523
+ if (chutesLidos.length) {
524
+ chutesLidos.sort((a, b) => b.nota - a.nota);
525
+ lidas.unshift(chutesLidos[0].item);
526
+ if (lidas.length > paginas) lidas.length = paginas;
527
+ }
528
+
505
529
  if (!lidas.length) {
506
530
  return {
507
531
  ok: false,
@@ -524,4 +548,4 @@ async function pesquisar({ consulta, paginas = 3 }) {
524
548
  }
525
549
 
526
550
  module.exports = { pesquisar, buscar, stackoverflow, textoDe, buscarWikipedia, buscarRespostaDDG, pegar,
527
- relevante, palavrasDaConsulta, sitesProvaveis, pareceCodigo };
551
+ relevante, quantoBate, palavrasDaConsulta, sitesProvaveis, pareceCodigo };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primocode",
3
- "version": "8.9.0",
3
+ "version": "8.10.0",
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": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "scripts": {
10
10
  "start": "node bin/primocode.js",
11
- "test": "node test/tools.test.js && node test/ui.test.js && node test/modo.test.js && node test/pasta.test.js && node test/catalogo.test.js && node test/desktop.test.js && node test/effort.test.js && node test/claude-engine.test.js && node test/regressao.test.js && node test/memoria-conversa.test.js && node test/repeticao.test.js && node test/referencia.test.js && node test/parar.test.js && node test/continuar.test.js"
11
+ "test": "node test/tools.test.js && node test/ui.test.js && node test/modo.test.js && node test/pasta.test.js && node test/catalogo.test.js && node test/desktop.test.js && node test/effort.test.js && node test/claude-engine.test.js && node test/regressao.test.js && node test/memoria-conversa.test.js && node test/repeticao.test.js && node test/referencia.test.js && node test/parar.test.js && node test/continuar.test.js && node test/studio-spec.test.js"
12
12
  },
13
13
  "engines": {
14
14
  "node": ">=18.17.0"
@@ -0,0 +1,150 @@
1
+ {
2
+ "id": "corte-estatico-corte-a5bab",
3
+ "ferramenta": "corte",
4
+ "titulo": "estatico-corte",
5
+ "doc": {
6
+ "tema": "brasa",
7
+ "largura": 1080,
8
+ "altura": 1920,
9
+ "acabamento": "grao",
10
+ "trilha": {
11
+ "tipo": "gerada",
12
+ "estilo": "pulso",
13
+ "volume": 0.7
14
+ },
15
+ "cenas": [
16
+ {
17
+ "layout": "centro",
18
+ "duracao": 3,
19
+ "fundo": "aurora",
20
+ "transicao": "flash",
21
+ "elementos": [
22
+ {
23
+ "tipo": "texto",
24
+ "papel": "titulo",
25
+ "texto": "Sua conta subiu\nde novo.",
26
+ "tamanho": 124,
27
+ "estilo": "gradiente",
28
+ "anim": "nenhuma"
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "layout": "centro",
34
+ "duracao": 3,
35
+ "fundo": "vinheta",
36
+ "transicao": "limpar",
37
+ "elementos": [
38
+ {
39
+ "tipo": "texto",
40
+ "papel": "titulo",
41
+ "texto": "E não foi o seu chuveiro.",
42
+ "tamanho": 78,
43
+ "estilo": "marcador",
44
+ "anim": "nenhuma"
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ "layout": "centro",
50
+ "duracao": 4,
51
+ "transicao": "zoom",
52
+ "acabamento": "vinheta",
53
+ "fundo": {
54
+ "imagem": "/midia/torre.jpg",
55
+ "escurecer": 0.5
56
+ },
57
+ "elementos": [
58
+ {
59
+ "tipo": "numeros",
60
+ "contar": true,
61
+ "anim": "nenhuma",
62
+ "tamanho": 180,
63
+ "itens": [
64
+ "+38% | bandeira tarifária em 12 meses"
65
+ ]
66
+ }
67
+ ]
68
+ },
69
+ {
70
+ "layout": "livre",
71
+ "duracao": 4,
72
+ "transicao": "deslizar",
73
+ "elementos": [
74
+ {
75
+ "tipo": "imagem",
76
+ "src": "/midia/campo.jpg",
77
+ "x": 0,
78
+ "y": 0,
79
+ "l": 1080,
80
+ "a": 1920,
81
+ "raio": 0,
82
+ "movimento": "aproximar",
83
+ "filtro": "contraste",
84
+ "anim": "nenhuma"
85
+ },
86
+ {
87
+ "tipo": "forma",
88
+ "forma": "retangulo",
89
+ "x": 0,
90
+ "y": 1180,
91
+ "l": 1080,
92
+ "a": 740,
93
+ "preenchimento": "rgba(10,5,6,.72)",
94
+ "anim": "nenhuma"
95
+ },
96
+ {
97
+ "tipo": "texto",
98
+ "x": 90,
99
+ "y": 1320,
100
+ "l": 900,
101
+ "a": 420,
102
+ "texto": "O custo está\nna transmissão",
103
+ "tamanho": 104,
104
+ "peso": 750,
105
+ "estilo": "sombra",
106
+ "anim": "nenhuma"
107
+ }
108
+ ]
109
+ },
110
+ {
111
+ "layout": "centro",
112
+ "duracao": 5,
113
+ "fundo": "raios",
114
+ "transicao": "subir",
115
+ "elementos": [
116
+ {
117
+ "tipo": "lista",
118
+ "revelar": true,
119
+ "tamanho": 52,
120
+ "intervalo": 0.9,
121
+ "itens": [
122
+ "Linhas saturadas no Nordeste",
123
+ "Usina gerando sem escoar",
124
+ "A conta chega em quem consome"
125
+ ],
126
+ "anim": "nenhuma"
127
+ }
128
+ ]
129
+ },
130
+ {
131
+ "layout": "centro",
132
+ "duracao": 3,
133
+ "fundo": "brilho",
134
+ "transicao": "fade",
135
+ "acabamento": "luz",
136
+ "elementos": [
137
+ {
138
+ "tipo": "texto",
139
+ "papel": "titulo",
140
+ "texto": "Segue para\nentender a próxima.",
141
+ "tamanho": 96,
142
+ "estilo": "contorno-tom",
143
+ "anim": "nenhuma"
144
+ }
145
+ ]
146
+ }
147
+ ]
148
+ },
149
+ "atualizado": "2026-08-16T15:08:28+00:00"
150
+ }
@@ -0,0 +1,65 @@
1
+ {
2
+ "id": "corte-founders-ai-teste-do-player-2de1d",
3
+ "ferramenta": "corte",
4
+ "titulo": "Founders AI — teste do player",
5
+ "doc": {
6
+ "tema": "brasa",
7
+ "largura": 1080,
8
+ "altura": 1920,
9
+ "acabamento": "grao",
10
+ "trilha": {
11
+ "tipo": "gerada",
12
+ "estilo": "pulso",
13
+ "volume": 0.7
14
+ },
15
+ "cenas": [
16
+ {
17
+ "layout": "centro",
18
+ "duracao": 3,
19
+ "fundo": "aurora",
20
+ "transicao": "flash",
21
+ "elementos": [
22
+ {
23
+ "tipo": "texto",
24
+ "papel": "titulo",
25
+ "texto": "Imersão\nFounders AI",
26
+ "tamanho": 124,
27
+ "estilo": "gradiente",
28
+ "anim": "desfoque"
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "layout": "centro",
34
+ "duracao": 3,
35
+ "fundo": "vinheta",
36
+ "elementos": [
37
+ {
38
+ "tipo": "texto",
39
+ "papel": "titulo",
40
+ "texto": "Paris Group · Chapecó",
41
+ "tamanho": 78,
42
+ "estilo": "marcador",
43
+ "anim": "palavra"
44
+ }
45
+ ]
46
+ },
47
+ {
48
+ "layout": "centro",
49
+ "duracao": 4,
50
+ "fundo": "raios",
51
+ "elementos": [
52
+ {
53
+ "tipo": "numeros",
54
+ "contar": true,
55
+ "tamanho": 180,
56
+ "itens": [
57
+ "20 | empresários por turma"
58
+ ]
59
+ }
60
+ ]
61
+ }
62
+ ]
63
+ },
64
+ "atualizado": "2026-08-16T14:55:24+00:00"
65
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": "corte-minimo-2a829",
3
+ "ferramenta": "corte",
4
+ "titulo": "minimo",
5
+ "doc": {
6
+ "tema": "claro",
7
+ "largura": 1080,
8
+ "altura": 1920,
9
+ "cenas": [
10
+ {
11
+ "layout": "centro",
12
+ "duracao": 5,
13
+ "elementos": [
14
+ {
15
+ "tipo": "texto",
16
+ "texto": "TESTE VISIVEL",
17
+ "tamanho": 120
18
+ }
19
+ ]
20
+ }
21
+ ]
22
+ },
23
+ "atualizado": "2026-08-16T14:57:24+00:00"
24
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "id": "corte-ok-00a3b",
3
+ "ferramenta": "corte",
4
+ "titulo": "ok",
5
+ "doc": {
6
+ "cenas": [
7
+ {
8
+ "elementos": [
9
+ {
10
+ "tipo": "texto",
11
+ "texto": "oi"
12
+ }
13
+ ]
14
+ }
15
+ ]
16
+ },
17
+ "atualizado": "2026-08-16T15:05:32+00:00"
18
+ }
@@ -0,0 +1,147 @@
1
+ {
2
+ "id": "corte-sweep-corte-cfb29",
3
+ "ferramenta": "corte",
4
+ "titulo": "sweep-corte",
5
+ "doc": {
6
+ "tema": "brasa",
7
+ "largura": 1080,
8
+ "altura": 1920,
9
+ "acabamento": "grao",
10
+ "trilha": {
11
+ "tipo": "gerada",
12
+ "estilo": "pulso",
13
+ "volume": 0.7
14
+ },
15
+ "cenas": [
16
+ {
17
+ "layout": "centro",
18
+ "duracao": 3,
19
+ "fundo": "aurora",
20
+ "transicao": "flash",
21
+ "elementos": [
22
+ {
23
+ "tipo": "texto",
24
+ "papel": "titulo",
25
+ "texto": "Sua conta subiu\nde novo.",
26
+ "tamanho": 124,
27
+ "estilo": "gradiente",
28
+ "anim": "desfoque"
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ "layout": "centro",
34
+ "duracao": 3,
35
+ "fundo": "vinheta",
36
+ "transicao": "limpar",
37
+ "elementos": [
38
+ {
39
+ "tipo": "texto",
40
+ "papel": "titulo",
41
+ "texto": "E não foi o seu chuveiro.",
42
+ "tamanho": 78,
43
+ "estilo": "marcador",
44
+ "anim": "palavra"
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ "layout": "centro",
50
+ "duracao": 4,
51
+ "transicao": "zoom",
52
+ "acabamento": "vinheta",
53
+ "fundo": {
54
+ "imagem": "/midia/torre.jpg",
55
+ "escurecer": 0.5
56
+ },
57
+ "elementos": [
58
+ {
59
+ "tipo": "numeros",
60
+ "contar": true,
61
+ "anim": "saltar",
62
+ "tamanho": 180,
63
+ "itens": [
64
+ "+38% | bandeira tarifária em 12 meses"
65
+ ]
66
+ }
67
+ ]
68
+ },
69
+ {
70
+ "layout": "livre",
71
+ "duracao": 4,
72
+ "transicao": "deslizar",
73
+ "elementos": [
74
+ {
75
+ "tipo": "imagem",
76
+ "src": "/midia/campo.jpg",
77
+ "x": 0,
78
+ "y": 0,
79
+ "l": 1080,
80
+ "a": 1920,
81
+ "raio": 0,
82
+ "movimento": "aproximar",
83
+ "filtro": "contraste"
84
+ },
85
+ {
86
+ "tipo": "forma",
87
+ "forma": "retangulo",
88
+ "x": 0,
89
+ "y": 1180,
90
+ "l": 1080,
91
+ "a": 740,
92
+ "preenchimento": "rgba(10,5,6,.72)"
93
+ },
94
+ {
95
+ "tipo": "texto",
96
+ "x": 90,
97
+ "y": 1320,
98
+ "l": 900,
99
+ "a": 420,
100
+ "texto": "O custo está\nna transmissão",
101
+ "tamanho": 104,
102
+ "peso": 750,
103
+ "estilo": "sombra",
104
+ "anim": "cortina"
105
+ }
106
+ ]
107
+ },
108
+ {
109
+ "layout": "centro",
110
+ "duracao": 5,
111
+ "fundo": "raios",
112
+ "transicao": "subir",
113
+ "elementos": [
114
+ {
115
+ "tipo": "lista",
116
+ "revelar": true,
117
+ "tamanho": 52,
118
+ "intervalo": 0.9,
119
+ "itens": [
120
+ "Linhas saturadas no Nordeste",
121
+ "Usina gerando sem escoar",
122
+ "A conta chega em quem consome"
123
+ ]
124
+ }
125
+ ]
126
+ },
127
+ {
128
+ "layout": "centro",
129
+ "duracao": 3,
130
+ "fundo": "brilho",
131
+ "transicao": "fade",
132
+ "acabamento": "luz",
133
+ "elementos": [
134
+ {
135
+ "tipo": "texto",
136
+ "papel": "titulo",
137
+ "texto": "Segue para\nentender a próxima.",
138
+ "tamanho": 96,
139
+ "estilo": "contorno-tom",
140
+ "anim": "elastico"
141
+ }
142
+ ]
143
+ }
144
+ ]
145
+ },
146
+ "atualizado": "2026-08-16T15:07:33+00:00"
147
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "corte-visual-completo-78f50",
3
+ "ferramenta": "corte",
4
+ "titulo": "visual completo",
5
+ "doc": {
6
+ "tema": "brasa",
7
+ "largura": 1080,
8
+ "altura": 1920,
9
+ "acabamento": "grao",
10
+ "cenas": [
11
+ {
12
+ "layout": "centro",
13
+ "duracao": 4,
14
+ "fundo": "aurora",
15
+ "elementos": [
16
+ {
17
+ "tipo": "texto",
18
+ "papel": "titulo",
19
+ "texto": "Imersão\nFounders AI",
20
+ "tamanho": 124,
21
+ "estilo": "gradiente",
22
+ "anim": "nenhuma"
23
+ },
24
+ {
25
+ "tipo": "texto",
26
+ "texto": "Paris Group · Chapecó",
27
+ "tamanho": 48,
28
+ "anim": "nenhuma"
29
+ }
30
+ ]
31
+ }
32
+ ]
33
+ },
34
+ "atualizado": "2026-08-16T15:02:56+00:00"
35
+ }
@@ -0,0 +1,119 @@
1
+ {
2
+ "id": "grade-sweep-grade-0c2f1",
3
+ "ferramenta": "grade",
4
+ "titulo": "sweep-grade",
5
+ "doc": {
6
+ "tema": "claro",
7
+ "abas": [
8
+ {
9
+ "nome": "Custos",
10
+ "colunas": [
11
+ "Item",
12
+ "Qtd",
13
+ "Unitário",
14
+ "Total"
15
+ ],
16
+ "linhas": [
17
+ [
18
+ "Servidor de aplicação",
19
+ 6,
20
+ 18400,
21
+ "=B1*C1"
22
+ ],
23
+ [
24
+ "Servidor de banco",
25
+ 3,
26
+ 26800,
27
+ "=B2*C2"
28
+ ],
29
+ [
30
+ "Licenças anuais",
31
+ 12,
32
+ 4200,
33
+ "=B3*C3"
34
+ ],
35
+ [
36
+ "Rede e cabeamento",
37
+ 1,
38
+ 38000,
39
+ "=B4*C4"
40
+ ],
41
+ [
42
+ "Total",
43
+ "",
44
+ "",
45
+ "=SOMA(D1:D4)"
46
+ ]
47
+ ],
48
+ "formatos": {
49
+ "Qtd": "inteiro",
50
+ "Unitário": "moeda",
51
+ "Total": "moeda"
52
+ },
53
+ "regras": [
54
+ {
55
+ "coluna": "Total",
56
+ "acima": 100000
57
+ }
58
+ ],
59
+ "grafico": {
60
+ "tipo": "barras",
61
+ "rotulo": "Item",
62
+ "valor": "Total"
63
+ }
64
+ },
65
+ {
66
+ "nome": "Projeção",
67
+ "colunas": [
68
+ "Mês",
69
+ "Receita",
70
+ "Custo",
71
+ "Margem",
72
+ "Margem %"
73
+ ],
74
+ "linhas": [
75
+ [
76
+ "Jan",
77
+ 320000,
78
+ 214000,
79
+ "=B1-C1",
80
+ "=ARRED(D1/B1*100)"
81
+ ],
82
+ [
83
+ "Fev",
84
+ 348000,
85
+ 219000,
86
+ "=B2-C2",
87
+ "=ARRED(D2/B2*100)"
88
+ ],
89
+ [
90
+ "Mar",
91
+ 391000,
92
+ 226000,
93
+ "=B3-C3",
94
+ "=ARRED(D3/B3*100)"
95
+ ],
96
+ [
97
+ "Média",
98
+ "=MEDIA(B1:B3)",
99
+ "=MEDIA(C1:C3)",
100
+ "=MEDIA(D1:D3)",
101
+ ""
102
+ ]
103
+ ],
104
+ "formatos": {
105
+ "Receita": "moeda",
106
+ "Custo": "moeda",
107
+ "Margem": "moeda",
108
+ "Margem %": "percentual"
109
+ },
110
+ "grafico": {
111
+ "tipo": "linha",
112
+ "rotulo": "Mês",
113
+ "valor": "Margem"
114
+ }
115
+ }
116
+ ]
117
+ },
118
+ "atualizado": "2026-08-16T15:07:33+00:00"
119
+ }