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 +30 -1
- package/lib/act.js +27 -0
- package/lib/catalogo.js +15 -9
- package/lib/desktop.js +578 -47
- package/lib/modo.js +5 -1
- package/lib/streaming.js +410 -0
- package/lib/tools.js +16 -0
- package/lib/ui.js +6 -3
- package/package.json +3 -3
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,
|
|
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: '
|
|
58
|
+
resumo: 'janelas, botões, mouse e teclado — age em qualquer programa e na área de trabalho',
|
|
59
59
|
itens: [
|
|
60
|
-
{ tool: '
|
|
61
|
-
{ tool: '
|
|
62
|
-
{ tool: '
|
|
63
|
-
{ tool: '
|
|
64
|
-
{ tool: '
|
|
65
|
-
{ tool: '
|
|
66
|
-
{ tool: '
|
|
67
|
-
{ tool: '
|
|
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
|
{
|