primocode 10.7.1 → 10.8.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/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# PrimoCode v10.
|
|
1
|
+
# PrimoCode v10.8.0
|
|
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 v10.
|
|
12
|
+
▐▛███▜▌ Primo Code v10.8.0
|
|
13
13
|
▝▜█████▛▘ Bem-vindo de volta, Joel
|
|
14
14
|
▘▘ ▝▝ ~/primocode · /dir <pasta> muda
|
|
15
15
|
```
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* conferencia.js — a conferência do vídeo PRONTO: o arquivo, medido, e não
|
|
3
|
+
* o plano.
|
|
4
|
+
*
|
|
5
|
+
* "gostei, ficou bom. mas ainda não. tá quase lá" (Joel, 11/10)
|
|
6
|
+
*
|
|
7
|
+
* O revisor.js olha o plano antes do render. Este olha o .mp4 que saiu, e
|
|
8
|
+
* troca o "quase lá" no olho por número que se confere sem abrir o vídeo
|
|
9
|
+
* (a ideia veio do review.mjs do cth9191/animate, MIT):
|
|
10
|
+
*
|
|
11
|
+
* som volume integrado (LUFS), variação (LRA) e pico verdadeiro, pelo
|
|
12
|
+
* ebur128 do ffmpeg. Alvo: -14 LUFS (±2) e pico até -1 dBTP.
|
|
13
|
+
* parado trecho em que a imagem não muda por 2 s ou mais, pelo
|
|
14
|
+
* freezedetect, com o quadro reduzido a 320 px. Calibrado em 13/10
|
|
15
|
+
* em 5 vídeos: na resolução cheia o ruído do fundo esconde a tela
|
|
16
|
+
* parada; a 160 px o texto fica pequeno demais e a palavra que
|
|
17
|
+
* entra não conta como mudança. A 320 px o teste-10-5-motion-com-
|
|
18
|
+
* imagem dá 6,5 s a 8,3 s ("torrado" parado, a pílula vazia, e
|
|
19
|
+
* para quando "café" entra), e os vídeos 3D não dão nada.
|
|
20
|
+
*
|
|
21
|
+
* Só mede e avisa. Não conserta nada: quem decide se refaz é o agente.
|
|
22
|
+
* As duas leituras (lerSom, lerParados) são puras e testáveis sem vídeo.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
const video = require('./video.js');
|
|
28
|
+
|
|
29
|
+
const ALVO = { lufs: -14, folgaLufs: 2, picoMax: -1, paradoMin: 2 };
|
|
30
|
+
const r1 = (n) => Math.round(n * 10) / 10;
|
|
31
|
+
|
|
32
|
+
/* O ebur128 escreve uma linha a cada 100 ms e um resumo no fim. Só o resumo
|
|
33
|
+
vale: a última linha "I:" de antes dele é a média até ali, não do vídeo. */
|
|
34
|
+
function lerSom(texto) {
|
|
35
|
+
const t = String(texto || '');
|
|
36
|
+
const i = t.lastIndexOf('Summary:');
|
|
37
|
+
if (i < 0) return null;
|
|
38
|
+
const resumo = t.slice(i);
|
|
39
|
+
const num = (re) => { const m = resumo.match(re); return m ? Number(m[1]) : null; };
|
|
40
|
+
const lufs = num(/I:\s*(-?[\d.]+|-inf)\s*LUFS/);
|
|
41
|
+
if (lufs == null) return null;
|
|
42
|
+
return { lufs, lra: num(/LRA:\s*(-?[\d.]+)\s*LU\b/), pico: num(/Peak:\s*(-?[\d.]+)\s*dBFS/) };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* O freezedetect marca o começo e o fim de cada trecho parado. Um começo
|
|
46
|
+
sem fim é tela parada até o último quadro. Dois trechos colados (o texto
|
|
47
|
+
some e o fundo fica) são, na tela, uma parada só. */
|
|
48
|
+
function lerParados(texto, duracao) {
|
|
49
|
+
const trechos = [];
|
|
50
|
+
const juntar = (de, ate) => {
|
|
51
|
+
const ultimo = trechos[trechos.length - 1];
|
|
52
|
+
if (ultimo && de - ultimo.ate < 0.2) ultimo.ate = r1(ate);
|
|
53
|
+
else trechos.push({ de: r1(de), ate: r1(ate) });
|
|
54
|
+
};
|
|
55
|
+
let de = null;
|
|
56
|
+
for (const linha of String(texto || '').split('\n')) {
|
|
57
|
+
const i = linha.match(/freeze_start:\s*([\d.]+)/);
|
|
58
|
+
if (i) { de = Number(i[1]); continue; }
|
|
59
|
+
const f = linha.match(/freeze_end:\s*([\d.]+)/);
|
|
60
|
+
if (f && de != null) { juntar(de, Number(f[1])); de = null; }
|
|
61
|
+
}
|
|
62
|
+
if (de != null && duracao > de) juntar(de, duracao);
|
|
63
|
+
return trechos;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** As medidas viram avisos. Puro. */
|
|
67
|
+
function julgar({ som, parados = [] }, alvo = ALVO) {
|
|
68
|
+
const avisos = [];
|
|
69
|
+
if (som && Number.isFinite(som.lufs)) {
|
|
70
|
+
if (Math.abs(som.lufs - alvo.lufs) > alvo.folgaLufs) {
|
|
71
|
+
avisos.push(`volume em ${som.lufs} LUFS, longe do alvo de ${alvo.lufs} (${som.lufs < alvo.lufs ? 'baixo demais' : 'alto demais'})`);
|
|
72
|
+
}
|
|
73
|
+
if (som.pico != null && som.pico > alvo.picoMax) avisos.push(`pico de ${som.pico} dBTP: estoura no celular (o máximo é ${alvo.picoMax})`);
|
|
74
|
+
}
|
|
75
|
+
for (const p of parados) {
|
|
76
|
+
const dura = r1(p.ate - p.de);
|
|
77
|
+
if (dura >= alvo.paradoMin) avisos.push(`imagem parada por ${dura} s (de ${p.de} s a ${p.ate} s)`);
|
|
78
|
+
}
|
|
79
|
+
return avisos;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Mede o arquivo numa passada só do ffmpeg e devolve medidas e avisos. */
|
|
83
|
+
async function conferir(arquivo, { duracao = 0 } = {}) {
|
|
84
|
+
const c = video.conferir();
|
|
85
|
+
if (!c.ok) return c;
|
|
86
|
+
const r = await video.rodar(video.ffmpeg(), [
|
|
87
|
+
'-hide_banner', '-nostats', '-i', arquivo,
|
|
88
|
+
'-vf', 'scale=320:-2,freezedetect=n=0.002:d=1.5',
|
|
89
|
+
'-af', 'ebur128=peak=true',
|
|
90
|
+
'-f', 'null', '-',
|
|
91
|
+
], { timeout: 10 * 60000 });
|
|
92
|
+
if (!r.ok) return { ok: false, error: `a conferência não leu o vídeo: ${r.erro.slice(-200)}` };
|
|
93
|
+
const som = lerSom(r.erro);
|
|
94
|
+
const parados = lerParados(r.erro, duracao);
|
|
95
|
+
return { ok: true, som, parados, avisos: julgar({ som, parados }) };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = { ALVO, lerSom, lerParados, julgar, conferir };
|
package/lib/estudio/index.js
CHANGED
|
@@ -47,6 +47,7 @@ const assets = require('./assets.js');
|
|
|
47
47
|
const video = require('./video.js');
|
|
48
48
|
const batida = require('./batida.js');
|
|
49
49
|
const revisor = require('./revisor.js');
|
|
50
|
+
const conferencia = require('./conferencia.js');
|
|
50
51
|
const margem = require('./margem.js');
|
|
51
52
|
const assinatura = require('./assinatura.js');
|
|
52
53
|
const identidade = require('./identidade.js');
|
|
@@ -2106,6 +2107,12 @@ async function ferramentaRender(args, ctx = {}) {
|
|
|
2106
2107
|
projeto.salvar(args.id, { renders: [...(p.renders || []), { quando: new Date().toISOString(), arquivo: saida, bytes }] });
|
|
2107
2108
|
projeto.anotar(args.id, 'render', `${(bytes / 1048576).toFixed(1)} MB, ${conferida.duracao}s`);
|
|
2108
2109
|
|
|
2110
|
+
/* A CONFERÊNCIA (conferencia.js): o arquivo que saiu, medido. Som fora do
|
|
2111
|
+
alvo e imagem parada viram aviso; quem decide se refaz é o agente. */
|
|
2112
|
+
const conf = fs.existsSync(saida) ? await conferencia.conferir(saida, { duracao: conferida.duracao }) : { ok: false };
|
|
2113
|
+
const avisosDoArquivo = conf.ok ? conf.avisos : [];
|
|
2114
|
+
if (avisosDoArquivo.length) projeto.anotar(args.id, 'conferencia', avisosDoArquivo.join('; '));
|
|
2115
|
+
|
|
2109
2116
|
// O vídeo pronto abre. É a única coisa que abre — a interface morreu, e
|
|
2110
2117
|
// o que a pessoa pediu foi o vídeo.
|
|
2111
2118
|
if (ctx.abrir) { try { ctx.abrir(saida); } catch { /* o caminho está na resposta */ } }
|
|
@@ -2114,8 +2121,9 @@ async function ferramentaRender(args, ctx = {}) {
|
|
|
2114
2121
|
ok: true, arquivo: saida, bytes, segundos: conferida.duracao,
|
|
2115
2122
|
faltaram: faltaram.length ? faltaram : undefined,
|
|
2116
2123
|
revisao: revisao.consertos.length || revisao.avisos.length ? { consertado: revisao.consertos, avisos: revisao.avisos } : undefined,
|
|
2124
|
+
conferencia: conf.ok ? { som: conf.som, parados: conf.parados, avisos: conf.avisos } : undefined,
|
|
2117
2125
|
aviso: 'ABERTO para o usuário assistir. Chame finish dizendo o que foi feito'
|
|
2118
|
-
+ (revisao.avisos.length ? ' — e cite os avisos da revisão que valem um novo plano.' : '.'),
|
|
2126
|
+
+ (revisao.avisos.length || avisosDoArquivo.length ? ' — e cite os avisos da revisão e da conferência que valem um novo plano.' : '.'),
|
|
2119
2127
|
};
|
|
2120
2128
|
}
|
|
2121
2129
|
|
|
@@ -281,6 +281,11 @@ function leiaute(P) {
|
|
|
281
281
|
ela ficava VAZIA até a voz chegar na frase (teste de 08/10). */
|
|
282
282
|
const p0 = pr ? pr.palavras[0].em : b.de;
|
|
283
283
|
const entT = [Math.max(ent[0], p0 - 0.4), Math.max(ent[1], p0 + 0.1)];
|
|
284
|
+
/* Mas a pílula de ANTES ficava: o texto dela saía e a forma esperava
|
|
285
|
+
vazia até a voz (0,6 s no café de 11/10, de 7,2 s a 7,9 s). Quando
|
|
286
|
+
a voz demora, a forma encolhe num ponto e cresce já com a frase. */
|
|
287
|
+
// Começa em b.de, quando o texto de antes já saiu (antes disso a forma laranja ficava atrás dele).
|
|
288
|
+
if (entT[0] >= b.de + 0.4) vai(b.de, b.de + 0.4, forma(tx, ty, 16 * u, 16 * u, { solid: 1, ac: 1 }));
|
|
284
289
|
if (umaLinha) vai(entT[0], entT[1], forma(tx, ty, (t ? t.w : 200 * u) + 110 * u, h, { fill: 1, stroke: 0.35 }));
|
|
285
290
|
else vai(entT[0], entT[1], forma(t.left - 40 * u, ty, 6 * u, t.h * 0.92, { solid: 1, ac: 1, r: 3 }));
|
|
286
291
|
}
|
|
@@ -831,6 +831,15 @@ const ESP = {
|
|
|
831
831
|
macaco: { forma: 4, corpo: [0.36, 0.42, 0.42], perna: 0.36, cab: 0.36, foc: [0.22, 0.14, 0.08], orelha: 'redonda', rabo: 'longo', cor: '#7a5232', cor2: '#e6c9a0', focCor: '#e6c9a0' },
|
|
832
832
|
};
|
|
833
833
|
|
|
834
|
+
/** Onde a cabeça do quatro-patas fica no chão, a partir do centro do bicho:
|
|
835
|
+
* o corpo vira 0,55 de lado e a cabeça vai na frente dele (o Quadrupede).
|
|
836
|
+
* A câmera mirava o meio do corpo e o rosto saía cortado na borda (13/10). */
|
|
837
|
+
export function frenteDoBicho(especie) {
|
|
838
|
+
const e = ESP[especie] || ESP.cachorro;
|
|
839
|
+
if (e.forma === 'ave' || e.forma === 'pinguim' || e.forma === 'peixe' || e.forma === 'dino') return { giro: 0, dist: 0 };
|
|
840
|
+
return { giro: 0.55, dist: e.corpo[2] / 2 + e.cab * 0.25 + (e.pescoco || 0) * 0.25 };
|
|
841
|
+
}
|
|
842
|
+
|
|
834
843
|
/** A altura da cabeça (para a câmera mirar no rosto do bicho). */
|
|
835
844
|
export function alturaDoBicho(especie) {
|
|
836
845
|
const e = ESP[especie] || ESP.cachorro;
|
|
@@ -30,7 +30,7 @@ import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPa
|
|
|
30
30
|
import { BokehPass } from 'three/examples/jsm/postprocessing/BokehPass.js';
|
|
31
31
|
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js';
|
|
32
32
|
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
|
|
33
|
-
import { Mundo, Animal, Coisa, alturaDoBicho, useIcones } from './mundo.jsx';
|
|
33
|
+
import { Mundo, Animal, Coisa, alturaDoBicho, frenteDoBicho, useIcones } from './mundo.jsx';
|
|
34
34
|
|
|
35
35
|
const clamp = (x, a = 0, b = 1) => Math.max(a, Math.min(b, x));
|
|
36
36
|
const lerp = (a, b, k) => a + (b - a) * k;
|
|
@@ -267,7 +267,8 @@ function RostoPixel({ p, est }) {
|
|
|
267
267
|
"olha como quero o 3D": o rosto da referência é LOW-POLY — uma esfera de
|
|
268
268
|
poucas faces com sombreado chapado, nariz de pirâmide, sobrancelha grossa,
|
|
269
269
|
o cabelo cacheado feito de dezenas de pedrinhas facetadas. O corpo segue
|
|
270
|
-
de blocos. `cabeca: '
|
|
270
|
+
de blocos. Desde 13/10 só sai com `cabeca: 'facetada'`: o padrão voltou a
|
|
271
|
+
ser o cubo com rosto de pixel da 10.5 (partitura sem o campo também). */
|
|
271
272
|
const GEO_FACETA = new Map();
|
|
272
273
|
function faceta(det) {
|
|
273
274
|
if (!GEO_FACETA.has(det)) GEO_FACETA.set(det, new THREE.IcosahedronGeometry(1, det));
|
|
@@ -432,7 +433,7 @@ function PessoaBloco({ p, est }) {
|
|
|
432
433
|
<BracoBloco lado={-1} g={est.gesto[0]} cor={p.roupa} pele={p.pele} t={est.t} acao={a} k={ka} />
|
|
433
434
|
<BracoBloco lado={1} g={est.gesto[1]} cor={p.roupa} pele={p.pele} t={est.t} acao={a} k={ka} />
|
|
434
435
|
<group position={[0, 1.8 + resp, 0]} rotation={[cp, cy, cr]}>
|
|
435
|
-
{p.cabeca
|
|
436
|
+
{p.cabeca !== 'facetada' ? (
|
|
436
437
|
<>
|
|
437
438
|
<Bloco s={[CAB, CAB, CAB]} c={p.pele} r={0.04} rough={0.6} />
|
|
438
439
|
<RostoPixel p={p} est={est} />
|
|
@@ -623,13 +624,34 @@ function lugarDoFigurante(el, fig, j, vert = false) {
|
|
|
623
624
|
return [lado * (borda + Math.floor(j / 2) * 0.9), 0, baixo ? 0.45 : -0.5];
|
|
624
625
|
}
|
|
625
626
|
|
|
627
|
+
/* A CÂMERA NÃO ATRAVESSA NINGUÉM (13/10): no close de quem fala, outro do
|
|
628
|
+
elenco ficava entre a lente e o rosto, ou com a lente dentro dele (o close
|
|
629
|
+
do cachorro com o braço do outro cortando o quadro). `bate` diz se alguém
|
|
630
|
+
do elenco, um cilindro do chão até acima da cabeça, corta o caminho. */
|
|
631
|
+
function bate(el, quem, pos, alvo) {
|
|
632
|
+
const dx = alvo[0] - pos[0], dz = alvo[2] - pos[2], L2 = dx * dx + dz * dz || 1;
|
|
633
|
+
for (let j = 0; j < el.length; j++) {
|
|
634
|
+
if (j === quem) continue;
|
|
635
|
+
const [x, , z] = lugarDe(el, j);
|
|
636
|
+
const u = clamp(((x - pos[0]) * dx + (z - pos[2]) * dz) / L2);
|
|
637
|
+
const py = pos[1] + (alvo[1] - pos[1]) * u;
|
|
638
|
+
if (Math.hypot(pos[0] + dx * u - x, pos[2] + dz * u - z) < 0.55 && py < alturaDaCabeca(el[j]) + 0.3) return true;
|
|
639
|
+
}
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
|
|
626
643
|
function cameraDe(pl, t, part, aspecto) {
|
|
627
644
|
const vert = aspecto < 1;
|
|
628
645
|
const el = part.elenco;
|
|
629
646
|
const dois = el.length > 1;
|
|
630
647
|
const quem = el[pl.alvo] ? pl.alvo : 0;
|
|
631
|
-
|
|
632
|
-
const
|
|
648
|
+
// O bicho de quatro patas tem a cabeça NA FRENTE do corpo, e o rosto virado para onde o corpo vira.
|
|
649
|
+
const doBicho = (i) => (el[i] && el[i].tipo === 'animal' ? frenteDoBicho(el[i].especie) : { giro: 0, dist: 0 });
|
|
650
|
+
const cabeca = (i) => {
|
|
651
|
+
const p = lugarDe(el, i), b = doBicho(i), g = giroDe(el, i) + b.giro;
|
|
652
|
+
return [p[0] + Math.sin(g) * b.dist, alturaDaCabeca(el[i]), p[2] + Math.cos(g) * b.dist];
|
|
653
|
+
};
|
|
654
|
+
const frente = (i) => { const g = giroDe(el, i) + doBicho(i).giro * 0.7; return [Math.sin(g), 0, Math.cos(g)]; };
|
|
633
655
|
const k = clamp((t - pl.de) / Math.max(0.5, pl.ate - pl.de));
|
|
634
656
|
const fovK = vert ? 1.45 : 1;
|
|
635
657
|
let pos, alvo, fov;
|
|
@@ -658,11 +680,16 @@ function cameraDe(pl, t, part, aspecto) {
|
|
|
658
680
|
const dist = (pl.tipo === 'detalhe' ? 1.25 : pl.tipo === 'close' ? 1.7 : 2.7) * (vert ? 1.25 : 1);
|
|
659
681
|
fov = (pl.tipo === 'detalhe' ? 30 : pl.tipo === 'close' ? 32 : 34) * fovK;
|
|
660
682
|
const h = cabeca(quem), f = frente(quem);
|
|
661
|
-
const lado = pl.lado * 0.42;
|
|
662
|
-
const dir = [f[0] * Math.cos(lado) - f[2] * Math.sin(lado), 0, f[0] * Math.sin(lado) + f[2] * Math.cos(lado)];
|
|
663
683
|
const baixo = pl.tipo === 'medio' ? 0.05 : -0.32;
|
|
664
|
-
pos = [h[0] + dir[0] * dist, h[1] + baixo, h[2] + dir[2] * dist];
|
|
665
684
|
alvo = [h[0], h[1] + (pl.tipo === 'medio' ? -0.35 : -0.02), h[2]];
|
|
685
|
+
const de = (ld) => {
|
|
686
|
+
const lado = ld * 0.42;
|
|
687
|
+
const dir = [f[0] * Math.cos(lado) - f[2] * Math.sin(lado), 0, f[0] * Math.sin(lado) + f[2] * Math.cos(lado)];
|
|
688
|
+
return [h[0] + dir[0] * dist, h[1] + baixo, h[2] + dir[2] * dist];
|
|
689
|
+
};
|
|
690
|
+
// O lado pedido; se alguém corta, o outro lado, de frente, mais aberto; senão, a câmera sobe por cima.
|
|
691
|
+
pos = [pl.lado, -pl.lado, 0, 1.6, -1.6].map(de).find((q) => !bate(el, quem, q, alvo));
|
|
692
|
+
if (!pos) { const q = de(pl.lado); pos = [q[0], q[1] + 0.9, q[2]]; }
|
|
666
693
|
}
|
|
667
694
|
// No vertical a legenda está no alto: a câmera mira acima, e o rosto desce no quadro.
|
|
668
695
|
if (vert) alvo = [alvo[0], alvo[1] + (pl.tipo === 'aberto' || pl.tipo === 'largo' ? 0.45 : pl.tipo === 'medio' ? 0.3 : pl.tipo === 'ombro' ? 0.22 : 0.17), alvo[2]];
|
|
@@ -154,8 +154,10 @@ function aparencia(nome, pedido = {}) {
|
|
|
154
154
|
barba: !!pedido.barba && pedido.genero !== 'f', // só quando pedida: sorteada, ficava estranha em quem tem cabelo longo
|
|
155
155
|
bigode: !!pedido.bigode && pedido.genero !== 'f',
|
|
156
156
|
...(pedido.genero ? { genero: pedido.genero } : {}),
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
/* O cubo com rosto de pixel (o da 10.5) é o padrão de novo: o low-poly
|
|
158
|
+
da 10.6 ficou "feito com polígonos, bugado e horrível" (Joel, 13/10).
|
|
159
|
+
A facetada só sai pedida. */
|
|
160
|
+
cabeca: pedido.cabeca === 'facetada' ? 'facetada' : 'cubo',
|
|
159
161
|
};
|
|
160
162
|
}
|
|
161
163
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primocode",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.8.0",
|
|
4
4
|
"description": "PrimoCode — agente de engenharia com IA e cursor próprio. Requer conta Conecta Primo AI (Premium ou Super). 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/entrada.test.js && node test/transparencia.test.js && node test/permissao.test.js && node test/compatibilidade.test.js && node test/skills.test.js && node test/skills-de-fora.test.js && node test/skills-novas.test.js && node test/comandos.test.js && node test/estudio.test.js && node test/voz.test.js && node test/modo.test.js && node test/pasta.test.js && node test/projeto.test.js && node test/nome-projeto.test.js && node test/api-propria.test.js && node test/claude-engine.test.js && node test/codex.test.js && node test/conferir.test.js && node test/catalogo.test.js && node test/desktop.test.js && node test/seta.test.js && node test/effort.test.js && node test/regressao.test.js && node test/memoria-conversa.test.js && node test/repeticao.test.js && node test/casar.test.js && node test/recado.test.js && node test/releitura.test.js && node test/snapshot.test.js && node test/video.test.js && node test/limpeza.test.js && node test/autonomia.test.js && node test/desfazer.test.js && node test/desfazer-git.test.js && node test/referencia.test.js && node test/parar.test.js && node test/continuar.test.js && node test/pipeline.test.js && node test/conta.test.mjs && node test/planos-tela.test.js && node test/nuvem.test.js && node test/prazo.test.js && node test/primeira-vez.test.js && node test/fala.test.js && node test/especialistas.test.js && node test/empurrao.test.js && node test/terminal-novo.test.js && node test/markdown.test.js && node test/coerencia.test.js && node test/contexto.test.js && node test/perigo.test.js && node test/rapidez.test.js && node test/mascotes.test.js && node test/comandos-extra.test.js && node test/offline.test.js && node test/edicao.test.js && node test/composicao.test.js && node test/acervo-site.test.js && node test/impacto.test.js && node test/cinema.test.js && node test/producao.test.js && node test/ende.test.js && node test/capa.test.js && node test/broll.test.js && node test/morfar.test.js && node test/motion.test.js && node test/motion-roteiro.test.js && node test/kit-motion.test.js && node test/gerativo.test.js && node test/gerativo-identidade.test.js && node test/gerativo-moldura.test.js && node test/gerativo-heroi.test.js && node test/gerativo-ambiente.test.js && node test/gerativo-variedade.test.js && node test/hibrido.test.js && node test/batida.test.js && node test/estudio-acervo.test.js && node test/estudio-diretor.test.js && node test/estudio-marca.test.js && node test/estudio-novo-projeto.test.js && node test/estudio-plano.test.js && node test/estudio-slides.test.js && node test/estudio-video.test.js && node test/revisor.test.js && node test/assinatura.test.js && node test/biblioteca.test.js && node test/mcp.test.js && node test/personas.test.js && node test/efeitos.test.js && node test/auto.test.js && node test/colar.test.js && node test/orquestra.test.js && node test/shell-limpo.test.js && node test/editar-remotion.test.js && node test/variacao3d.test.js && node test/portao-skill.test.js && node test/clones.test.js && node test/kokoro.test.js && node test/fluido.test.js && node test/zoom.test.js && node test/personagem.test.js && node test/tela.test.js && node test/margem.test.js && node test/travado.test.js && node test/leitura.test.js && node test/producao-provedores.test.js && node test/broll-frase.test.js && node test/vazamento.test.js && node test/colecao.test.js && node test/mundo.test.js && node test/mcp-procurar.test.js && node test/selecao.test.js && node test/nome-curto.test.js && node test/agents-md.test.js && node test/outra-pasta.test.js && node test/estudio-sem-id.test.js && node test/estudio-objeto-do-site.test.js && node test/cenarios.test.js && node test/movimentos.test.js && node test/gerativo-so-fala.test.js"
|
|
11
|
+
"test": "node test/tools.test.js && node test/ui.test.js && node test/entrada.test.js && node test/transparencia.test.js && node test/permissao.test.js && node test/compatibilidade.test.js && node test/skills.test.js && node test/skills-de-fora.test.js && node test/skills-novas.test.js && node test/comandos.test.js && node test/estudio.test.js && node test/voz.test.js && node test/modo.test.js && node test/pasta.test.js && node test/projeto.test.js && node test/nome-projeto.test.js && node test/api-propria.test.js && node test/claude-engine.test.js && node test/codex.test.js && node test/conferir.test.js && node test/catalogo.test.js && node test/desktop.test.js && node test/seta.test.js && node test/effort.test.js && node test/regressao.test.js && node test/memoria-conversa.test.js && node test/repeticao.test.js && node test/casar.test.js && node test/recado.test.js && node test/releitura.test.js && node test/snapshot.test.js && node test/video.test.js && node test/limpeza.test.js && node test/autonomia.test.js && node test/desfazer.test.js && node test/desfazer-git.test.js && node test/referencia.test.js && node test/parar.test.js && node test/continuar.test.js && node test/pipeline.test.js && node test/conta.test.mjs && node test/planos-tela.test.js && node test/nuvem.test.js && node test/prazo.test.js && node test/primeira-vez.test.js && node test/fala.test.js && node test/especialistas.test.js && node test/empurrao.test.js && node test/terminal-novo.test.js && node test/markdown.test.js && node test/coerencia.test.js && node test/contexto.test.js && node test/perigo.test.js && node test/rapidez.test.js && node test/mascotes.test.js && node test/comandos-extra.test.js && node test/offline.test.js && node test/edicao.test.js && node test/composicao.test.js && node test/acervo-site.test.js && node test/impacto.test.js && node test/cinema.test.js && node test/producao.test.js && node test/ende.test.js && node test/capa.test.js && node test/broll.test.js && node test/morfar.test.js && node test/motion.test.js && node test/motion-roteiro.test.js && node test/kit-motion.test.js && node test/gerativo.test.js && node test/gerativo-identidade.test.js && node test/gerativo-moldura.test.js && node test/gerativo-heroi.test.js && node test/gerativo-ambiente.test.js && node test/gerativo-variedade.test.js && node test/hibrido.test.js && node test/batida.test.js && node test/estudio-acervo.test.js && node test/estudio-diretor.test.js && node test/estudio-marca.test.js && node test/estudio-novo-projeto.test.js && node test/estudio-plano.test.js && node test/estudio-slides.test.js && node test/estudio-video.test.js && node test/revisor.test.js && node test/conferencia.test.js && node test/assinatura.test.js && node test/biblioteca.test.js && node test/mcp.test.js && node test/personas.test.js && node test/efeitos.test.js && node test/auto.test.js && node test/colar.test.js && node test/orquestra.test.js && node test/shell-limpo.test.js && node test/editar-remotion.test.js && node test/variacao3d.test.js && node test/portao-skill.test.js && node test/clones.test.js && node test/kokoro.test.js && node test/fluido.test.js && node test/zoom.test.js && node test/personagem.test.js && node test/tela.test.js && node test/margem.test.js && node test/travado.test.js && node test/leitura.test.js && node test/producao-provedores.test.js && node test/broll-frase.test.js && node test/vazamento.test.js && node test/colecao.test.js && node test/mundo.test.js && node test/mcp-procurar.test.js && node test/selecao.test.js && node test/nome-curto.test.js && node test/agents-md.test.js && node test/outra-pasta.test.js && node test/estudio-sem-id.test.js && node test/estudio-objeto-do-site.test.js && node test/cenarios.test.js && node test/movimentos.test.js && node test/gerativo-so-fala.test.js"
|
|
12
12
|
},
|
|
13
13
|
"engines": {
|
|
14
14
|
"node": ">=18.17.0"
|