primocode 8.9.1 → 8.10.1

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/studio.js CHANGED
@@ -84,12 +84,12 @@ function copiar(de, para) {
84
84
  for (const item of fs.readdirSync(de)) copiar(path.join(de, item), path.join(para, item));
85
85
  return;
86
86
  }
87
- let precisa = true;
88
- try {
89
- const alvo = fs.statSync(para);
90
- precisa = alvo.size !== st.size || alvo.mtimeMs < st.mtimeMs;
91
- } catch {}
92
- if (precisa) fs.copyFileSync(de, para);
87
+ // Copia SEMPRE. A comparação esperta (tamanho + data) deixava passar
88
+ // arquivo alterado de mesmo tamanho: o npm instala com data antiga
89
+ // (1985, de propósito, por reprodutibilidade) e o teste de mtime nunca
90
+ // disparava. O que o usuário criou não corre risco — arquivos/ e midia/
91
+ // não estão em COPIAVEIS.
92
+ fs.copyFileSync(de, para);
93
93
  }
94
94
 
95
95
  function prepararCasa() {
@@ -139,10 +139,64 @@ async function estaNoAr() {
139
139
  // Uma subida por vez: sem esta trava, duas tools chamadas no mesmo turno
140
140
  // disparariam dois servidores na mesma porta e o segundo morreria com
141
141
  // "address in use" — barulho por nada.
142
+ /** A assinatura do server.py que está NO DISCO — a versão que deveria rodar. */
143
+ function assinaturaDoDisco() {
144
+ try {
145
+ const corpo = fs.readFileSync(path.join(CASA, 'server.py'));
146
+ return require('crypto').createHash('sha1').update(corpo).digest('hex').slice(0, 12);
147
+ } catch { return null; }
148
+ }
149
+
150
+ /** A assinatura do processo que está NO AR — a versão que roda de fato. */
151
+ async function assinaturaNoAr() {
152
+ try { return (await pedir('GET', '/api/versao', null, 1500)).assinatura || null; }
153
+ catch { return null; } // servidor antigo não tem a rota — também é "desatualizado"
154
+ }
155
+
156
+ /**
157
+ * Derruba o Studio que está no ar. Primeiro pelo caminho limpo (/api/sair);
158
+ * se for um servidor antigo, que não tem a rota, pelo sistema.
159
+ */
160
+ async function derrubar() {
161
+ try { await pedir('POST', '/api/sair', {}, 1500); } catch {}
162
+ for (let i = 0; i < 10; i++) {
163
+ await new Promise((r) => setTimeout(r, 300));
164
+ if (!(await estaNoAr())) return true;
165
+ }
166
+ // Servidor antigo: sem /api/sair. Mata pelo padrão da linha de comando.
167
+ try {
168
+ const { execSync } = require('child_process');
169
+ if (os.platform() === 'win32') {
170
+ execSync('powershell -NoProfile -Command "Get-CimInstance Win32_Process | ' +
171
+ "Where-Object {$_.CommandLine -like '*primocode*studio*server.py*'} | " +
172
+ 'ForEach-Object { Stop-Process -Id $_.ProcessId -Force }"', { stdio: 'ignore' });
173
+ } else {
174
+ execSync("pkill -f '[.]primocode/studio/server.py'", { stdio: 'ignore' });
175
+ }
176
+ } catch {}
177
+ for (let i = 0; i < 10; i++) {
178
+ await new Promise((r) => setTimeout(r, 300));
179
+ if (!(await estaNoAr())) return true;
180
+ }
181
+ return !(await estaNoAr());
182
+ }
183
+
142
184
  let subindo = null;
143
185
 
144
186
  async function garantirNoAr() {
145
- if (await estaNoAr()) return { ok: true, url: BASE, jaEstava: true };
187
+ if (await estaNoAr()) {
188
+ // O npm pode ter trocado o código no disco DEPOIS de este processo
189
+ // subir — e aí o Studio no ar é o antigo, servindo o bug que o
190
+ // update corrigiu. Atualiza o disco e compara as assinaturas; se
191
+ // divergirem, reinicia. Na véspera de uma apresentação, "atualizei
192
+ // mas continua igual" é o pior modo de falha que existe.
193
+ prepararCasa();
194
+ const doDisco = assinaturaDoDisco();
195
+ const noAr = await assinaturaNoAr();
196
+ if (!doDisco || (noAr && noAr === doDisco)) return { ok: true, url: BASE, jaEstava: true };
197
+ await derrubar();
198
+ // cai para o caminho de subida normal, já com o código novo
199
+ }
146
200
  if (subindo) return subindo;
147
201
 
148
202
  subindo = (async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primocode",
3
- "version": "8.9.1",
3
+ "version": "8.10.1",
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
+ }