primocode 10.3.0-beta.0 → 10.4.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/lib/ui.js CHANGED
@@ -298,103 +298,85 @@ function truncate(s, max) {
298
298
 
299
299
  const padRight = (s, w) => s + ' '.repeat(Math.max(0, w - visibleWidth(s)));
300
300
 
301
- // ── Conteúdo do cabeçalho ────────────────────────────────────────────────
302
- // Editar aqui é o suficiente para mudar o que aparece na abertura.
301
+ // ── O convite da caixa ───────────────────────────────────────────────────
302
+ // Como no OpenCode ("Ask anything… \"Fix a TODO\""): a caixa vazia mostra um
303
+ // exemplo de pedido. Um por abertura, sorteado, para quem chega aprender o
304
+ // que dá para pedir sem ler lista nenhuma.
305
+ const EXEMPLOS = [
306
+ 'um vídeo 3D de dois personagens conversando',
307
+ 'um site de portfólio com animação no scroll',
308
+ 'um motion de 20 segundos explicando o que é API',
309
+ 'clona github.com/vercel/next.js e me explica a pasta app',
310
+ 'tira o logo do site x.com com o fundo transparente',
311
+ ];
312
+ function convite() {
313
+ return `Peça qualquer coisa… "${EXEMPLOS[Math.floor(Math.random() * EXEMPLOS.length)]}"`;
314
+ }
303
315
 
304
- const NOME = 'Primo Code';
316
+ // ── Cabeçalho ────────────────────────────────────────────────────────────
317
+ // O desenho do OpenCode, que é a referência pedida: o nome grande no meio da
318
+ // tela, em letra de pixel, com a primeira metade apagada e a segunda acesa —
319
+ // e nada mais. Dicas, novidades e o mascote saíram da abertura: ao lado da
320
+ // caixa de digitar no centro, qualquer texto a mais é o que o olho lê
321
+ // primeiro, e o que se quer que ele leia é a caixa.
322
+ //
323
+ // A letra é um bitmap de 8 linhas de pixel, juntadas de duas em duas com os
324
+ // meios-blocos ▀ ▄ █: 4 linhas de terminal, largura 1 garantida em qualquer
325
+ // fonte. Linha 0 é a haste de cima (d, pingo do i), 1–5 o corpo, 6 a perna
326
+ // do p.
327
+ const LETRAS = {
328
+ p: [' ', '####', '# #', '# #', '####', '# ', '# ', ' '],
329
+ r: [' ', '####', '# ', '# ', '# ', '# ', ' ', ' '],
330
+ i: ['#', ' ', '#', '#', '#', '#', ' ', ' '],
331
+ m: [' ', '#####', '# # #', '# # #', '# # #', '# # #', ' ', ' '],
332
+ o: [' ', '####', '# #', '# #', '# #', '####', ' ', ' '],
333
+ c: [' ', '####', '# ', '# ', '# ', '####', ' ', ' '],
334
+ d: [' #', '####', '# #', '# #', '# #', '####', ' ', ' '],
335
+ e: [' ', '####', '# #', '####', '# ', '####', ' ', ' '],
336
+ };
305
337
 
306
- const TIPS = [
307
- 'Peça um app novo, ou aponte para um repositório e mande clonar',
308
- '/dir <pasta> para ele trabalhar numa pasta que já é sua',
309
- '/help lista tudo · /effort ajusta o esforço · /status confere a API',
310
- ];
338
+ /** Uma palavra em letra de pixel: 4 linhas de texto, sem cor. */
339
+ function letreiro(palavra) {
340
+ const px = [];
341
+ for (let y = 0; y < 8; y++) px.push([...palavra].map((ch) => LETRAS[ch][y]).join(' '));
342
+ const out = [];
343
+ for (let y = 0; y < 8; y += 2) {
344
+ let l = '';
345
+ for (let x = 0; x < px[y].length; x++) {
346
+ const a = px[y][x] === '#', b = px[y + 1][x] === '#';
347
+ l += a && b ? '█' : a ? '▀' : b ? '▄' : ' ';
348
+ }
349
+ out.push(l);
350
+ }
351
+ return out;
352
+ }
311
353
 
312
- const NEWS = [
313
- 'A IA decide o caminho: skills e equipe num cardápio, ela escolhe o que usa',
314
- 'Até 8 agentes em paralelo, cada um volta com uma entrega — e passa a vez',
315
- 'Edite falando no vídeo: primocode video auto aplica o que você diz, na hora',
316
- 'Colou texto grande? Vira etiqueta [Colado #1 · N linhas] na caixa',
317
- 'Escopo fechado de verdade: "só do site x.com" filtra a pesquisa',
318
- ];
354
+ /** O logo: "primo" apagado e "code" aceso, lado a lado. */
355
+ function logo() {
356
+ const a = letreiro('primo'), b = letreiro('code');
357
+ return a.map((l, i) => `\x1b[38;5;244m${l}${PALETTE.reset} ${PALETTE.bold}\x1b[38;5;255m${b[i]}${PALETTE.reset}`);
358
+ }
359
+ const LOGO_W = visibleWidth(logo()[0]);
319
360
 
320
- // ── Cabeçalho ────────────────────────────────────────────────────────────
321
- // Duas faixas: identidade (mascote + 3 linhas) e orientação (dicas,
322
- // novidades, modos). Sem caixa — moldura em terminal estreito quebra, e o
323
- // alinhamento do desenho já dá a borda esquerda de graça.
361
+ /** Centraliza uma linha (com cor) em `cols` colunas. */
362
+ function centro(s, cols) {
363
+ return ' '.repeat(Math.max(0, Math.floor((cols - visibleWidth(s)) / 2))) + s;
364
+ }
324
365
 
325
366
  function welcomeBox(version, contexto, opts = {}) {
326
- const { mascot: style, userName, modo, pastaPadrao } = opts;
327
- const art = mascot(style);
328
- const cols = Math.max(32, Math.min(process.stdout.columns || 100, 120));
329
-
330
- // O bordão do mascote vem na mesma linha da saudação: é ele quem cumprimenta.
331
- // Em terminal estreito o truncate corta o bordão antes do nome.
332
- const info = mascoteInfo(style);
333
- const saudacao = (userName
334
- ? `${c.muted('Bem-vindo de volta, ')}${c.bold(c.white(userName))}`
335
- : c.muted('Bem-vindo de volta'))
336
- + c.dim(` · ${info.nome}: "${info.frase}"`);
337
-
338
- // As três linhas de identidade — uma por linha do mascote, na ordem em que
339
- // se lê: quem é, quem chegou, onde estamos.
340
- // A pasta é o que mais confundia quem usa, então ela avisa de si mesma — na
341
- // MESMA linha de sempre, sem mudar o desenho do cabeçalho. Amber quando é a
342
- // pasta padrão (é um aviso, não uma falha: dá para trabalhar em outra), e a
343
- // primária quando foi você que escolheu — aí não há nada a avisar.
344
- const linhaPasta = !contexto
345
- ? c.dim('nenhuma pasta ativa')
346
- : pastaPadrao
347
- ? `${c.warn(contexto)}${c.dim(' · /dir <pasta> muda')}`
348
- : c.brandDim(contexto);
349
-
350
- const ident = [
351
- `${c.bold(c.brand(NOME))} ${c.dim('v' + version)}`,
352
- saudacao,
353
- linhaPasta,
354
- ];
355
-
367
+ const { pastaPadrao } = opts;
368
+ const cols = Math.max(32, Math.min(process.stdout.columns || 100, 200));
356
369
  const out = [''];
357
370
 
358
- // Terminal estreito: o texto ao lado não caberia, então empilha embaixo.
359
- const largo = cols >= ART_W + 2 + 28;
360
- if (largo) {
361
- const textW = cols - ART_W - 2;
362
- for (let i = 0; i < ART_H; i++) {
363
- out.push(art[i] + ' ' + truncate(ident[i] || '', textW));
364
- }
365
- } else {
366
- out.push(...art);
367
- out.push('');
368
- out.push(...ident.map((l) => truncate(l, cols)));
369
- }
371
+ if (cols >= LOGO_W + 2) out.push(...logo().map((l) => centro(l, cols)));
372
+ else out.push(centro(`${c.dim('primo')}${c.bold(c.white('code'))}`, cols));
370
373
 
371
- // Cada item ocupa 5 colunas de prefixo (" 1. "), então o texto tem cols-5.
372
- // Estourar por uma coluna quebra a linha e o cabeçalho parece defeito.
373
- const secao = (titulo, itens, marca) => {
374
- out.push('');
375
- out.push(' ' + c.bold(c.white(titulo)));
376
- itens.forEach((t, i) => {
377
- out.push(` ${c.dim(marca(i))} ${truncate(c.muted(t), cols - 5)}`);
378
- });
379
- };
380
-
381
- secao('Dicas para começar', TIPS, (i) => `${i + 1}.`);
382
- secao('Novidades', NEWS, () => ' ·');
383
-
384
- // Rodapé: em que modo você está agora, não a lista dos que existem. Em
385
- // terminal apertado a dica do /help sai antes de empurrar a linha para
386
- // baixo — cabeçalho que quebra parece defeito.
387
- // Primária para o modo ativo, secundária quando ele tem poder de escrever:
388
- // é a mesma leitura de "apurado" × "aviso que não é falha" do sistema.
389
- const rotulos = {
390
- auto: `${c.brand('●')} ${c.muted('Auto')}${c.dim(' — conversa vai pro chat, tarefa vai pro agente')}`,
391
- primocode: `${c.warn('●')} ${c.muted('Primo Code')}${c.dim(' — agente completo, com ferramentas')}`,
392
- chat: `${c.brandDim('●')} ${c.muted('Chat')}${c.dim(' — conversa pura, sem ferramentas')}`,
393
- };
394
- const linhaModo = ' ' + (rotulos[modo] || rotulos.auto);
374
+ /* A pasta só fala quando é a padrão. Era o que mais confundia quem usa
375
+ ("onde ele salvou?"), e é aviso, não falha: âmbar, uma linha. Quando foi
376
+ a pessoa que escolheu, a pasta já está no rodapé da caixa. */
395
377
  out.push('');
396
- out.push(visibleWidth(linhaModo) <= cols ? linhaModo : ` ${c.ok('●')} ${c.muted(modo || 'auto')}`);
397
- if (cols >= 44) out.push(` ${c.dim('/help para tudo · /mode troca o modo')}`);
378
+ if (contexto && pastaPadrao) out.push(centro(`${c.warn(contexto)}${c.dim(' · /dir <pasta> muda')}`, cols));
379
+ out.push(centro(c.dim('v' + version), cols));
398
380
  out.push('');
399
381
  return out.join('\n');
400
382
  }
@@ -651,4 +633,4 @@ function friendlyError(raw) {
651
633
 
652
634
 
653
635
  module.exports = {
654
- titulo, c, mascot, MASCOTES, resolverMascote, mascoteInfo, galeriaMascotes, reacao, welcomeBox, Spinner, PENSANDO, actionHeader, friendlyError, visibleWidth, stripAnsi, truncate, padRight };
636
+ titulo, c, logo, letreiro, convite, EXEMPLOS, mascot, MASCOTES, resolverMascote, mascoteInfo, galeriaMascotes, reacao, welcomeBox, Spinner, PENSANDO, actionHeader, friendlyError, visibleWidth, stripAnsi, truncate, padRight };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primocode",
3
- "version": "10.3.0-beta.0",
3
+ "version": "10.4.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/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/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"
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/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/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/margem.test.js"
12
12
  },
13
13
  "engines": {
14
14
  "node": ">=18.17.0"