primocode 7.10.1 → 7.12.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
@@ -22,6 +22,7 @@ const cfg = require('../lib/config');
22
22
  const { runAct } = require('../lib/act');
23
23
  const pasta = require('../lib/pasta');
24
24
  const catalogo = require('../lib/catalogo');
25
+ const streaming = require('../lib/streaming');
25
26
 
26
27
  // A pasta de onde o comando foi dado. Não é mais onde ele trabalha (o padrão é
27
28
  // ~/primocode), mas continua servindo de ponto de partida para achar pasta que
@@ -55,6 +56,7 @@ ${c.bold('Comandos')}
55
56
  ${c.brand('/read')} <arquivo> mostra um arquivo
56
57
  ${c.brand('/run')} <comando> executa no shell do projeto
57
58
  ${c.brand('/open')} <arquivo|url> abre no navegador
59
+ ${c.brand('/streaming')} painel ao vivo — veja o agente mexendo no computador
58
60
  ${c.brand('/status')} checa o servidor
59
61
  ${c.brand('/name')} <nome> como o Primo te chama
60
62
  ${c.brand('/mascot')} <estilo> mascote: primo|fox|cat
@@ -465,7 +467,7 @@ async function handleSlash(text) {
465
467
  for (const g of catalogo.GRUPOS) {
466
468
  console.log(' ' + c.bold(c.white(g.nome)) + ' ' + ui.truncate(c.dim('— ' + g.resumo), cols - 4 - ui.visibleWidth(g.nome)));
467
469
  for (const i of g.itens) {
468
- console.log(' ' + c.brand(ui.padRight(i.tool, 21)) + ui.truncate(c.muted(i.faz), cols - 26));
470
+ console.log(' ' + c.brand(ui.padRight(i.tool, 23)) + ui.truncate(c.muted(i.faz), cols - 28));
469
471
  }
470
472
  console.log('');
471
473
  }
@@ -503,6 +505,33 @@ async function handleSlash(text) {
503
505
  break;
504
506
  }
505
507
 
508
+ // Painel ao vivo: um servidorzinho local mostra cada ação do agente na
509
+ // tela + a foto tirada logo depois dela. Liga/desliga; /streaming on|off
510
+ // também funciona.
511
+ case 'streaming': case 'stream': case 'live': {
512
+ const pedido = rest.toLowerCase();
513
+ const ligar = pedido === 'on' ? true : pedido === 'off' ? false : !streaming.isOn();
514
+
515
+ if (!ligar) {
516
+ if (streaming.isOn()) { streaming.stop(); console.log(c.ok('Streaming desligado.')); }
517
+ else console.log(c.muted('O streaming já estava desligado.'));
518
+ break;
519
+ }
520
+ if (streaming.isOn()) {
521
+ console.log(c.muted(`Já está ligado: ${streaming.url()}`));
522
+ break;
523
+ }
524
+ try {
525
+ const url = await streaming.start();
526
+ console.log(c.ok('Streaming ligado: ') + c.white(url));
527
+ console.log(c.muted(' Dê uma instrução e veja cada passo dele aí, ao vivo. /streaming de novo desliga.'));
528
+ await tools.openInBrowser(url);
529
+ } catch (e) {
530
+ console.log(c.err(`Não consegui ligar o streaming: ${e.message}`));
531
+ }
532
+ break;
533
+ }
534
+
506
535
  case 'name': {
507
536
  if (!rest) { console.log(c.muted(` Nome atual: ${state.config.userName || '(nenhum)'}`)); break; }
508
537
  state.config.userName = rest;
package/lib/act.js CHANGED
@@ -15,6 +15,7 @@ const tools = require('./tools');
15
15
  const api = require('./api');
16
16
  const cfg = require('./config');
17
17
  const catalogo = require('./catalogo');
18
+ const streaming = require('./streaming');
18
19
 
19
20
  const MAX_ITERATIONS = 15;
20
21
  const MAX_PROFUNDIDADE = 2; // principal + 1 nível de subagente
@@ -93,6 +94,27 @@ function logResult(kind, result, profundidade) {
93
94
  case 'browser_read':
94
95
  console.log(p + c.muted(`${(result.text || '').length} caracteres lidos da página`));
95
96
  return;
97
+ case 'desktop_windows': {
98
+ console.log(p + c.muted(`${result.total} janela${result.total === 1 ? '' : 's'}`));
99
+ for (const j of (result.janelas || []).slice(0, 5)) console.log(p + c.dim(`${j.app ? j.app + ' · ' : ''}${j.titulo}`.slice(0, 120)));
100
+ if ((result.janelas || []).length > 5) console.log(p + c.dim(`… +${result.janelas.length - 5}`));
101
+ return;
102
+ }
103
+ case 'desktop_elements': {
104
+ console.log(p + c.muted(`${result.total} elemento${result.total === 1 ? '' : 's'} em “${result.janela || 'janela em foco'}”`));
105
+ for (const e of (result.elementos || []).slice(0, 5)) console.log(p + c.dim(`${e.nome} (${e.x},${e.y})`.slice(0, 120)));
106
+ if ((result.elementos || []).length > 5) console.log(p + c.dim(`… +${result.elementos.length - 5}`));
107
+ return;
108
+ }
109
+ case 'desktop_click_element':
110
+ console.log(p + c.ok('ok') + c.muted(` · ${result.duplo ? 'clique duplo' : 'clique'} em “${result.clicado}” (${result.x},${result.y})`));
111
+ return;
112
+ case 'desktop_open_app':
113
+ console.log(p + c.ok('ok') + c.muted(` · ${result.app}`));
114
+ return;
115
+ case 'desktop_focus':
116
+ console.log(p + c.ok('ok') + c.muted(` · ${result.janela || 'em foco'}`));
117
+ return;
96
118
  case 'browser_screenshot':
97
119
  case 'desktop_screenshot':
98
120
  console.log(p + c.muted(`${result.path} · ${tools.fmtBytes(result.bytes || 0)}`));
@@ -104,6 +126,7 @@ function logResult(kind, result, profundidade) {
104
126
  case 'browser_wait':
105
127
  case 'browser_eval':
106
128
  case 'desktop_click':
129
+ case 'desktop_double_click':
107
130
  case 'desktop_move':
108
131
  case 'desktop_drag':
109
132
  case 'desktop_type':
@@ -257,6 +280,10 @@ async function runAct(userPrompt, opts) {
257
280
  const result = await tools.execute(tc.name, tc.arguments, { projectDir: pastaAtual });
258
281
  logResult(tc.name, result, profundidade);
259
282
 
283
+ // Painel ao vivo (/streaming): registra o passo e fotografa a tela.
284
+ // Nunca pode derrubar o loop — falha de foto é problema do painel.
285
+ try { streaming.step(tc.name, tc.arguments, result); } catch {}
286
+
260
287
  // Uma escrita bem-sucedida limpa a dívida: o agente se corrigiu.
261
288
  if (result && result.ok === false) falhasPendentes.push(`${tc.name}(${tc.arguments?.path || ''}): ${result.error}`);
262
289
  else if (['write_file', 'edit_file'].includes(tc.name)) falhasPendentes.length = 0;
package/lib/catalogo.js CHANGED
@@ -55,16 +55,22 @@ const GRUPOS = [
55
55
  },
56
56
  {
57
57
  nome: 'Computador',
58
- resumo: 'mouse, teclado e tela — age em qualquer programa, não só no navegador',
58
+ resumo: 'janelas, botões, mouse e teclado — age em qualquer programa e na área de trabalho',
59
59
  itens: [
60
- { tool: 'desktop_screenshot', escreve: true, faz: 'tira foto da sua tela' },
61
- { tool: 'desktop_click', escreve: false, faz: 'clica na tela' },
62
- { tool: 'desktop_move', escreve: false, faz: 'move o mouse' },
63
- { tool: 'desktop_drag', escreve: false, faz: 'arrasta de um ponto a outro' },
64
- { tool: 'desktop_type', escreve: false, faz: 'digita no programa que está na frente' },
65
- { tool: 'desktop_key', escreve: false, faz: 'aperta tecla ou atalho' },
66
- { tool: 'desktop_scroll', escreve: false, faz: 'rola a tela' },
67
- { tool: 'desktop_size', escreve: false, faz: 'mede a tela, para se orientar antes de clicar' },
60
+ { tool: 'desktop_open_app', escreve: false, faz: 'abre um programa pelo nome (Chrome, Bloco de Notas…)' },
61
+ { tool: 'desktop_windows', escreve: false, faz: 'lista as janelas abertas, com título' },
62
+ { tool: 'desktop_focus', escreve: false, faz: 'traz uma janela para a frente, pelo título' },
63
+ { tool: 'desktop_elements', escreve: false, faz: 'lê os botões, campos e ícones da janela, com posição' },
64
+ { tool: 'desktop_click_element', escreve: false, faz: 'clica num botão ou ícone pelo NOME, sem coordenada' },
65
+ { tool: 'desktop_click', escreve: false, faz: 'clica na tela por coordenada' },
66
+ { tool: 'desktop_double_click', escreve: false, faz: 'clique duplo — abre ícone da área de trabalho' },
67
+ { tool: 'desktop_move', escreve: false, faz: 'move o mouse' },
68
+ { tool: 'desktop_drag', escreve: false, faz: 'arrasta de um ponto a outro' },
69
+ { tool: 'desktop_type', escreve: false, faz: 'digita no programa que está na frente' },
70
+ { tool: 'desktop_key', escreve: false, faz: 'aperta tecla ou atalho (Enter, ctrl+c, alt+tab)' },
71
+ { tool: 'desktop_scroll', escreve: false, faz: 'rola a tela' },
72
+ { tool: 'desktop_size', escreve: false, faz: 'mede a tela, para se orientar antes de clicar' },
73
+ { tool: 'desktop_screenshot', escreve: true, faz: 'tira foto da sua tela' },
68
74
  ],
69
75
  },
70
76
  {