primocode 11.3.2 → 11.3.3
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/LICENSES/mp4-muxer-MIT.txt +21 -0
- package/lib/cli/sessao.js +39 -98
- package/lib/cli-nova.js +2 -3
- package/lib/nomes.js +2 -2
- package/lib/plugin/entregaveis/nucleo.js +2 -2
- package/lib/session/runner/act.js +1 -1
- package/lib/tui/ui.js +6 -3
- package/package.json +2 -2
- package/voz/primo_voz/chat.html +11 -49
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Vanilagy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/lib/cli/sessao.js
CHANGED
|
@@ -143,6 +143,27 @@ function linhasDosGrupos() {
|
|
|
143
143
|
return saida;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/* O `--help` de fora: só o essencial. Os grupos completos moram no /help (e no "/") dentro da sessão. */
|
|
147
|
+
const HELP_ENXUTO = ['new', 'projects', 'undo', 'check', 'open', 'studio', 'help', 'exit'];
|
|
148
|
+
/* PRIMO_DEBUG=1: o que os catch silenciosos engolem vai pro stderr. Sem a variável, nada muda. */
|
|
149
|
+
function depurar(onde, e) {
|
|
150
|
+
if (process.env.PRIMO_DEBUG !== '1') return;
|
|
151
|
+
try { process.stderr.write(`[PRIMO_DEBUG] ${onde}: ${e && e.stack ? e.stack : e}\n`); } catch { /* stderr fechado */ }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function montarHelpEnxuto() {
|
|
155
|
+
const desc = new Map(comandosDoMenu().map(([n, d]) => [n.slice(1), d]));
|
|
156
|
+
const linhas = HELP_ENXUTO.map((n) => { const d = desc.get(n); return d ? ` ${c.brand(ui.padRight('/' + n, 16))}${c.muted(d)}` : ` ${c.brand('/' + n)}`; });
|
|
157
|
+
return `
|
|
158
|
+
${c.bold('Comandos')}
|
|
159
|
+
|
|
160
|
+
${linhas.join('\n')}
|
|
161
|
+
${c.brand('-p')} "pedido" modo script: sem tela, aceita stdin e --output-format json
|
|
162
|
+
|
|
163
|
+
${c.dim('digite / pra ver todos')}
|
|
164
|
+
`;
|
|
165
|
+
}
|
|
166
|
+
|
|
146
167
|
function montarHelp() {
|
|
147
168
|
return `
|
|
148
169
|
${c.bold('Comandos')} ${c.dim('· os nomes em português continuam valendo (/desfazer = /undo)')}
|
|
@@ -218,10 +239,6 @@ const SLASH_COMANDOS = [
|
|
|
218
239
|
['/chats', 'suas conversas salvas, as mesmas do app e do celular'],
|
|
219
240
|
['/logout', 'desconecta este computador da conta'],
|
|
220
241
|
['!comando', 'roda direto no shell, sem passar pelo agente (o campo fica âmbar)'],
|
|
221
|
-
['/voice', 'liga o Primo: clique nele e fale; ele faz e responde em voz alta, com a tela dele (robô, agenda, clima, música)'],
|
|
222
|
-
['/voice painel', 'só o painel do Primo (ESC esconde)'],
|
|
223
|
-
['/voice nome <Nome>', 'dá outro nome ao assistente (só o nome; o modo voz abre no clique)'],
|
|
224
|
-
['/voice parar', 'desliga o modo voz e fecha o microfone'],
|
|
225
242
|
['/skills', 'o que ele sabe fazer bem · /skills store: a loja · /skills add <arquivo>: instala'],
|
|
226
243
|
['/commands', 'seus comandos: um .md vira /nome · /commands novo <nome>'],
|
|
227
244
|
['/styles', 'os estilos de motion (kits): a lista e a galeria · /styles <estilo>: o preview dele'],
|
|
@@ -234,6 +251,7 @@ const SLASH_COMANDOS = [
|
|
|
234
251
|
['/keys', 'as teclas que ajudam'],
|
|
235
252
|
['/connectors', 'quem está atendendo os seus pedidos'],
|
|
236
253
|
['/name', 'como ele te chama · /name voz <Nome>: o nome do assistente de voz'],
|
|
254
|
+
['/studio', 'escolhe o que criar: slides, vídeo, motion, anúncio, abertura'],
|
|
237
255
|
['/brand', 'kit de marca: cores, fontes e logo'],
|
|
238
256
|
['/mascot', 'galeria dos mascotes · escolha por nome ou número'],
|
|
239
257
|
['/config', 'suas preferências'],
|
|
@@ -243,7 +261,7 @@ const SLASH_COMANDOS = [
|
|
|
243
261
|
['/version', 'versão'],
|
|
244
262
|
['/exit', 'sair'],
|
|
245
263
|
];
|
|
246
|
-
// A CLI nova (lib/cli-nova.js): /
|
|
264
|
+
// A CLI nova (lib/cli-nova.js): /studio /agentes /piloto /avisos /buscar entram no menu e no autopreenchimento.
|
|
247
265
|
SLASH_COMANDOS.splice(Math.max(0, SLASH_COMANDOS.findIndex(([n]) => n === '/marca')), 0, ...require('../cli-nova.js').SLASH_NOVOS);
|
|
248
266
|
|
|
249
267
|
/* /api: a chave da própria pessoa — lib/cli/comando-api.js. */
|
|
@@ -540,7 +558,7 @@ function barraLateral() {
|
|
|
540
558
|
* O desenho é do OpenCode: uma lista com busca no meio da tela. O conteúdo é
|
|
541
559
|
* o que já existe aqui: os comandos de barra, os modos, os agentes da pessoa,
|
|
542
560
|
* as conversas salvas e os temas. Escolher um item roda o comando de sempre. */
|
|
543
|
-
const ATALHOS_DO_LIDER = { '/clear': 'ctrl+x n', '/projects': 'ctrl+x p', '/
|
|
561
|
+
const ATALHOS_DO_LIDER = { '/clear': 'ctrl+x n', '/projects': 'ctrl+x p', '/studio': 'ctrl+x s' };
|
|
544
562
|
|
|
545
563
|
function paletaDeComandos() {
|
|
546
564
|
const itens = [
|
|
@@ -552,7 +570,7 @@ function paletaDeComandos() {
|
|
|
552
570
|
{ secao: 'Sugeridos', nome: 'Mostrar ou esconder a barra da direita', tecla: 'ctrl+x b', acao: (r) => { r.lateralOculta = !r.lateralOculta; r._quadroAnterior = null; r._pintar(); } },
|
|
553
571
|
];
|
|
554
572
|
for (const [nome, desc] of comandosDoMenu()) {
|
|
555
|
-
if (/^(\/uninstall|!comando
|
|
573
|
+
if (/^(\/uninstall|!comando)/.test(nome) || nome.includes(' ') || nome === '/clear') continue;
|
|
556
574
|
itens.push({ secao: 'Comandos', nome, desc, cmd: nome, tecla: ATALHOS_DO_LIDER[nome] || '', preencher: /\s<|<.*>/.test(desc) && /^\/(dir|worktree|rule|lock|attach|read|run|open|history|howto)$/.test(nome) });
|
|
557
575
|
}
|
|
558
576
|
return itens;
|
|
@@ -1747,7 +1765,8 @@ async function baixarCriacaoDireto(texto) {
|
|
|
1747
1765
|
console.log(c.muted(' ') + c.white(ultimo.arquivo));
|
|
1748
1766
|
console.log(c.dim(` ${(ultimo.bytes / 1048576).toFixed(1)} MB · o arquivo já estava pronto, é só copiar daí.`));
|
|
1749
1767
|
return true;
|
|
1750
|
-
} catch {
|
|
1768
|
+
} catch (e) {
|
|
1769
|
+
depurar('projeto renderizado', e);
|
|
1751
1770
|
return false; // sem projeto renderizado: segue o caminho normal
|
|
1752
1771
|
}
|
|
1753
1772
|
}
|
|
@@ -1790,7 +1809,8 @@ async function dividirTarefa(pedido) {
|
|
|
1790
1809
|
const passos = (r && Array.isArray(r.passos) && r.passos.length) ? r.passos : inteiro;
|
|
1791
1810
|
if (passos.length > 1) console.log(c.dim(` ⎿ ${passos[0].titulo}`));
|
|
1792
1811
|
return passos;
|
|
1793
|
-
} catch {
|
|
1812
|
+
} catch (e) {
|
|
1813
|
+
depurar('preparar o pedido', e);
|
|
1794
1814
|
sp.stop(); // preparar o pedido é melhoria, não requisito
|
|
1795
1815
|
return inteiro;
|
|
1796
1816
|
}
|
|
@@ -1832,7 +1852,8 @@ async function comprimirConversa(forcado = false, { silencioso = false } = {}) {
|
|
|
1832
1852
|
gravarMemoriaDaPasta(dir);
|
|
1833
1853
|
const e = memoria.economia(state.memoria, state.history);
|
|
1834
1854
|
if (!silencioso && e.poupado > 0) console.log(c.dim(` ⎿ conversa resumida · ${e.cheio} → ${e.enxuto} tokens por pedido`));
|
|
1835
|
-
} catch {
|
|
1855
|
+
} catch (e) {
|
|
1856
|
+
depurar('resumo da conversa', e);
|
|
1836
1857
|
sp.stop(); // resumo é economia, não requisito: falhou, segue a vida
|
|
1837
1858
|
}
|
|
1838
1859
|
}
|
|
@@ -2269,8 +2290,8 @@ async function handleSlash(text) {
|
|
|
2269
2290
|
listava os nomes, em ordem alfabética, e quem procurava "o de ontem"
|
|
2270
2291
|
tinha de abrir pasta por pasta. Agora vem do mais recente, com
|
|
2271
2292
|
quando mexeu e o tamanho, e um número para entrar. */
|
|
2272
|
-
case 'estudio': case 'agentes': case 'piloto': case 'avisos': case 'buscar': {
|
|
2273
|
-
const r = require('../cli-nova.js').COMANDOS[nome](rest, { c, dir: process.env.PRIMOCODE_AGENTES });
|
|
2293
|
+
case 'studio': case 'estudio': case 'agentes': case 'piloto': case 'avisos': case 'buscar': {
|
|
2294
|
+
const r = require('../cli-nova.js').COMANDOS[nome === 'studio' ? 'estudio' : nome](rest, { c, dir: process.env.PRIMOCODE_AGENTES });
|
|
2274
2295
|
for (const l of r.linhas) console.log(l);
|
|
2275
2296
|
if (r.pedido) await sendPrompt(`${r.instrucao}\n\nPEDIDO: ${r.pedido}`);
|
|
2276
2297
|
break;
|
|
@@ -3063,7 +3084,7 @@ async function handleSlash(text) {
|
|
|
3063
3084
|
const nomeVoz = rest.match(/^(?:voz|voice|assistente)\s+(.{2,20})$/i);
|
|
3064
3085
|
if (nomeVoz) {
|
|
3065
3086
|
const salvo = vozModo.definirNome(nomeVoz[1]);
|
|
3066
|
-
console.log(salvo ? c.ok(` Fechado: o assistente agora se chama ${salvo}. Vale na próxima vez que
|
|
3087
|
+
console.log(salvo ? c.ok(` Fechado: o assistente agora se chama ${salvo}. Vale na próxima vez que o modo voz abrir.`) : c.err(' Nome inválido (1 ou 2 palavras, até 20 letras).'));
|
|
3067
3088
|
break;
|
|
3068
3089
|
}
|
|
3069
3090
|
if (!rest) { console.log(c.muted(` Nome atual: ${state.config.userName || '(nenhum)'}`)); break; }
|
|
@@ -3344,86 +3365,6 @@ async function handleSlash(text) {
|
|
|
3344
3365
|
}
|
|
3345
3366
|
|
|
3346
3367
|
|
|
3347
|
-
/* ── /voice ──────────────────────────────────────────────────────
|
|
3348
|
-
* O ouvido e a boca são Python (voz/primo_voz); o cérebro é este
|
|
3349
|
-
* terminal. Ver entradaDeVoz no main() e lib/plugin/voz.js.
|
|
3350
|
-
*/
|
|
3351
|
-
case 'voice': {
|
|
3352
|
-
/* ── O MODO VOZ É UMA FORMA DE DIGITAR ─────────────────────────
|
|
3353
|
-
Você fala; o que foi dito entra aqui como se tivesse sido
|
|
3354
|
-
digitado — a mesma fila, o mesmo recado no meio da tarefa, o
|
|
3355
|
-
mesmo roteador de conversa — e a resposta final sai em voz alta.
|
|
3356
|
-
O terminal continua seu: dá para falar e digitar ao mesmo tempo.
|
|
3357
|
-
|
|
3358
|
-
Desligar é o primeiro caso de propósito: quem quer fechar o
|
|
3359
|
-
microfone quer AGORA, sem esbarrar em checagem de dependência. */
|
|
3360
|
-
const argVoz = (rest || '').trim();
|
|
3361
|
-
// Só o painel (HUD em tela cheia no Mac; quadro no terminal fora dele).
|
|
3362
|
-
if (/^painel$/i.test(argVoz)) {
|
|
3363
|
-
const py = vozModo.python();
|
|
3364
|
-
if (!py) { console.log(c.err(' O painel precisa do Python 3.')); break; }
|
|
3365
|
-
if (vozPainel) { try { vozPainel.processo.kill(); } catch {} vozPainel = null; }
|
|
3366
|
-
vozPainel = vozModo.abrirPainel({ python: py });
|
|
3367
|
-
console.log(c.muted(vozPainel.tela ? ' Tela do Primo aberta — ESC esconde.' : ' Sem o painel gráfico aqui: rode `primocode voz painel` num terminal separado.'));
|
|
3368
|
-
break;
|
|
3369
|
-
}
|
|
3370
|
-
// /voice nome <Nome>: a pessoa dá o nome ao assistente (o nome não ativa nada: o modo voz só abre no clique).
|
|
3371
|
-
const mNome = argVoz.match(/^nome\s+(.{2,20})$/i);
|
|
3372
|
-
if (mNome) {
|
|
3373
|
-
const salvo = vozModo.definirNome(mNome[1]);
|
|
3374
|
-
console.log(salvo ? c.ok(` Fechado: o assistente agora se chama ${salvo}. Vale na próxima vez que ligar o /voice.`) : c.err(' Nome inválido (1 ou 2 palavras, até 20 letras).'));
|
|
3375
|
-
break;
|
|
3376
|
-
}
|
|
3377
|
-
if (/^(parar|stop|off|sair)$/i.test(argVoz)) {
|
|
3378
|
-
if (vozPainel) { try { vozPainel.processo.kill(); } catch {} vozPainel = null; }
|
|
3379
|
-
if (!vozEmEspera) { console.log(c.muted(vozPainel === null ? ' Modo voz e painel fechados.' : ' O modo voz não está ligado.')); break; }
|
|
3380
|
-
try { vozEmEspera.processo.kill(); } catch {}
|
|
3381
|
-
vozEmEspera = null;
|
|
3382
|
-
console.log(c.muted(' Modo voz desligado. O microfone fechou.'));
|
|
3383
|
-
break;
|
|
3384
|
-
}
|
|
3385
|
-
if (vozEmEspera) {
|
|
3386
|
-
console.log(c.muted(' O modo voz já está ouvindo — é só falar.') + c.dim(' /voice parar desliga.'));
|
|
3387
|
-
break;
|
|
3388
|
-
}
|
|
3389
|
-
|
|
3390
|
-
// "Instale tudo que precisa, rode tudo que precisa." Da segunda vez
|
|
3391
|
-
// em diante tudo já está lá, e isto leva um segundo.
|
|
3392
|
-
const sp = new Spinner('preparando o modo voz').start();
|
|
3393
|
-
const prep = await vozModo.preparar((msg) => { sp.text = msg; });
|
|
3394
|
-
sp.stop();
|
|
3395
|
-
if (!prep.ok) {
|
|
3396
|
-
console.log(c.err(` ${prep.error}`));
|
|
3397
|
-
if (prep.comoResolver) console.log(c.muted(` ${prep.comoResolver}`));
|
|
3398
|
-
for (const a of prep.avisos) console.log(c.dim(` ${a}`));
|
|
3399
|
-
break;
|
|
3400
|
-
}
|
|
3401
|
-
for (const a of prep.avisos) console.log(c.dim(` ${a}`));
|
|
3402
|
-
if (process.platform === 'darwin') { try { vozModo.instalarApp({ python: prep.python }); } catch { /* o app é bônus */ } }
|
|
3403
|
-
|
|
3404
|
-
const sessao = vozModo.abrir({
|
|
3405
|
-
python: prep.python,
|
|
3406
|
-
servidor: state.config.server,
|
|
3407
|
-
token: state.config.token,
|
|
3408
|
-
voz: state.config.voz || 'antonio',
|
|
3409
|
-
aoPronto: () => {
|
|
3410
|
-
console.log(' ' + c.bold(c.brand('🎙 Modo voz ligado')) + c.muted(' — é só falar. A resposta sai em voz alta.'));
|
|
3411
|
-
console.log(' ' + c.dim('Falar por cima corta a voz · digitar continua valendo · /voice parar desliga'));
|
|
3412
|
-
},
|
|
3413
|
-
aoParar: () => { try { require('../session/runner/act.js').interromper(); } catch { /* nada rodando */ } },
|
|
3414
|
-
aoOuvir: (texto) => { if (entradaDeVoz) entradaDeVoz(texto); },
|
|
3415
|
-
mostrar: (texto) => console.log(' ' + c.dim(texto)),
|
|
3416
|
-
});
|
|
3417
|
-
vozEmEspera = sessao;
|
|
3418
|
-
require('../plugin/voz-ponte').escutar((nome, args) => sessao.ferramenta(nome, args));
|
|
3419
|
-
sessao.pronto.then((r) => {
|
|
3420
|
-
if (vozEmEspera === sessao) vozEmEspera = null;
|
|
3421
|
-
if (r && !r.ok) console.log(c.err(` o modo voz fechou: ${r.error}`));
|
|
3422
|
-
});
|
|
3423
|
-
break;
|
|
3424
|
-
}
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
3368
|
/* ── /connectors ─────────────────────────────────────────────────
|
|
3428
3369
|
* Só mostra. Não há o que configurar — os conectores vivem no
|
|
3429
3370
|
* servidor, com as chaves dele, e é assim de propósito: a promessa do
|
|
@@ -3923,12 +3864,12 @@ async function main() {
|
|
|
3923
3864
|
}
|
|
3924
3865
|
if (sub === 'instalar-app') {
|
|
3925
3866
|
const py = vz.python();
|
|
3926
|
-
if (!py) { console.log('O app precisa do Python 3 (
|
|
3867
|
+
if (!py) { console.log('O app precisa do Python 3 (instale o Python 3).'); process.exit(1); }
|
|
3927
3868
|
const r = vz.instalarApp({ python: py, dock: resto.includes('--dock') });
|
|
3928
3869
|
console.log(r.ok ? `Primo.app instalado em ${r.app}. Abra pelo Launchpad, Spotlight ou Finder.` : `Não deu: ${r.erro || 'veja o log'}`);
|
|
3929
3870
|
process.exit(r.ok ? 0 : 1);
|
|
3930
3871
|
}
|
|
3931
|
-
console.log('Uso: primocode voz nome <Nome> | primocode voz painel | primocode voz instalar-app [--dock]
|
|
3872
|
+
console.log('Uso: primocode voz nome <Nome> | primocode voz painel | primocode voz instalar-app [--dock]');
|
|
3932
3873
|
process.exit(0);
|
|
3933
3874
|
}
|
|
3934
3875
|
if (['doutor', 'doctor', 'preparar'].includes(process.argv[2])) {
|
|
@@ -4003,8 +3944,8 @@ async function main() {
|
|
|
4003
3944
|
process.exit(0);
|
|
4004
3945
|
}
|
|
4005
3946
|
if (args[0] === '--help' || args[0] === '-h') {
|
|
4006
|
-
console.log(welcomeBox(VERSION, null, { mascot: state.config.mascot, userName: state.config.userName, modo: state.mode }));
|
|
4007
|
-
console.log(
|
|
3947
|
+
if (process.stdout.isTTY && !(process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== '')) console.log(welcomeBox(VERSION, null, { mascot: state.config.mascot, userName: state.config.userName, modo: state.mode }));
|
|
3948
|
+
console.log(montarHelpEnxuto());
|
|
4008
3949
|
process.exit(0);
|
|
4009
3950
|
}
|
|
4010
3951
|
|
|
@@ -4150,7 +4091,7 @@ async function main() {
|
|
|
4150
4091
|
if (agora - ultimoEsc < 2000) {
|
|
4151
4092
|
ultimoEsc = 0;
|
|
4152
4093
|
interromper();
|
|
4153
|
-
if (chatEmVoo) { try { chatEmVoo.abort(); } catch {} }
|
|
4094
|
+
if (chatEmVoo) { try { chatEmVoo.abort(); } catch (e) { depurar('abortar o chat', e); } }
|
|
4154
4095
|
console.log(c.warn(' ⏹ parando o agente…'));
|
|
4155
4096
|
} else {
|
|
4156
4097
|
ultimoEsc = agora;
|
package/lib/cli-nova.js
CHANGED
|
@@ -98,13 +98,13 @@ function estudio(rest, { c } = {}) {
|
|
|
98
98
|
if (!t0) {
|
|
99
99
|
linhas.push(cor(c, 'white')('O que vamos criar?'));
|
|
100
100
|
for (const [n, d] of TIPOS_ESTUDIO) linhas.push(` ${cor(c, 'brand')(n.padEnd(10))}${cor(c, 'muted')(d)}`);
|
|
101
|
-
linhas.push(cor(c, 'dim')(' /
|
|
101
|
+
linhas.push(cor(c, 'dim')(' /studio <tipo> [o que criar]'));
|
|
102
102
|
return { linhas };
|
|
103
103
|
}
|
|
104
104
|
if (!TIPOS_ESTUDIO.some(([n]) => n === tipo) && !QUADRADOS[tipo]) return { linhas: [cor(c, 'err')(`Tipo "${t0}" não existe. Use: ${TIPOS_ESTUDIO.map(([n]) => n).join(', ')}.`)], erro: true };
|
|
105
105
|
if (tipo === 'carrossel') return { linhas: [cor(c, 'warn')('Carrossel ainda não tem receita no Estúdio. Descreva como slides ou peça direto na conversa.')], erro: true };
|
|
106
106
|
const briefing = r.join(' ');
|
|
107
|
-
if (!briefing) return { linhas: [cor(c, 'white')(`O que vamos criar em ${tipo}?`), cor(c, 'dim')(` /
|
|
107
|
+
if (!briefing) return { linhas: [cor(c, 'white')(`O que vamos criar em ${tipo}?`), cor(c, 'dim')(` /studio ${tipo} <descrição do que criar>`)], tipo };
|
|
108
108
|
return { linhas: [], tipo, pedido: briefing, instrucao: instrucaoDoTipo(tipo) };
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -205,7 +205,6 @@ function buscar(rest, { c, dir } = {}) {
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
const SLASH_NOVOS = [
|
|
208
|
-
['/estudio', 'escolhe o que criar: slides, vídeo, motion, anúncio, abertura'],
|
|
209
208
|
['/agentes', 'seus agentes: lista · ligar · desligar · criar · apagar'],
|
|
210
209
|
['/piloto', 'piloto automático: on | off [grupo]'],
|
|
211
210
|
['/avisos', 'fila de aprovação e avisos · a <n> aprova · r <n> recusa'],
|
package/lib/nomes.js
CHANGED
|
@@ -91,7 +91,7 @@ const COMANDOS = {
|
|
|
91
91
|
taste: { grupo: 'video', antigos: ['gosto', 'referencias'] },
|
|
92
92
|
brand: { grupo: 'video', antigos: ['marca'] },
|
|
93
93
|
mascot: { grupo: 'video', antigos: ['mascote'] },
|
|
94
|
-
|
|
94
|
+
studio: { grupo: 'video', antigos: ['estudio', 'estúdio'] },
|
|
95
95
|
styles: { grupo: 'video', antigos: ['estilos', 'kits'] },
|
|
96
96
|
// 9. Conta e sistema
|
|
97
97
|
login: { grupo: 'conta', antigos: ['entrar', 'conectar'] },
|
|
@@ -167,7 +167,7 @@ const QUANDO = {
|
|
|
167
167
|
taste: 'quer ver, refazer ou ensinar o gosto de motion (`/taste referencias` com vídeos que curtiu)',
|
|
168
168
|
brand: 'quer cores, fontes e logo da marca em todo vídeo',
|
|
169
169
|
mascot: 'quer escolher ou ver os mascotes',
|
|
170
|
-
|
|
170
|
+
studio: 'quer criar um vídeo, slides, motion, anúncio ou abertura (o Estúdio)',
|
|
171
171
|
styles: 'quer ver os estilos de motion prontos (galeria com capa e preview; `/styles <estilo>`: um)',
|
|
172
172
|
login: 'quer entrar na conta',
|
|
173
173
|
logout: 'quer sair da conta neste computador',
|
|
@@ -103,7 +103,7 @@ function acharNavegador(env = process.env, existe = require('fs').existsSync) {
|
|
|
103
103
|
function htmlParaPdf(htmlPath, pdfPath, { navegador = acharNavegador() } = {}) {
|
|
104
104
|
if (!navegador) return { ok: false, erro: 'Chrome/Chromium não encontrado (defina PRIMO_CHROME)' };
|
|
105
105
|
const { spawnSync } = require('child_process');
|
|
106
|
-
const r = spawnSync(navegador, ['--headless=new', '--use-mock-keychain', '--password-store=basic', '--disable-gpu', '--no-pdf-header-footer',
|
|
106
|
+
const r = spawnSync(navegador, ['--headless=new', '--use-mock-keychain', '--password-store=basic', '--use-mock-keychain', '--password-store=basic', '--use-mock-keychain', '--password-store=basic', '--use-mock-keychain', '--password-store=basic', '--use-mock-keychain', '--password-store=basic', '--disable-gpu', '--no-pdf-header-footer',
|
|
107
107
|
`--print-to-pdf=${pdfPath}`, 'file://' + htmlPath], { encoding: 'utf8', timeout: 90000 });
|
|
108
108
|
return require('fs').existsSync(pdfPath) ? { ok: true } : { ok: false, erro: (r.stderr || '').slice(-300) || 'PDF não saiu' };
|
|
109
109
|
}
|
|
@@ -180,7 +180,7 @@ function htmlParaPngs(htmlPath, baseSemExt, n, w, h, { escala = 1, navegador = a
|
|
|
180
180
|
const tmp = `${baseSemExt}.tmp-${i}.html`;
|
|
181
181
|
const alvo = `${baseSemExt}-${String(i).padStart(2, '0')}.png`;
|
|
182
182
|
fs.writeFileSync(tmp, html.replace('</head>', `<style>section:not(:nth-of-type(${i})){display:none!important}html,body{height:${h}px;overflow:hidden}</style></head>`));
|
|
183
|
-
spawnSync(navegador, ['--headless=new', '--use-mock-keychain', '--password-store=basic', '--disable-gpu', '--hide-scrollbars', `--force-device-scale-factor=${escala}`,
|
|
183
|
+
spawnSync(navegador, ['--headless=new', '--use-mock-keychain', '--password-store=basic', '--use-mock-keychain', '--password-store=basic', '--use-mock-keychain', '--password-store=basic', '--use-mock-keychain', '--password-store=basic', '--use-mock-keychain', '--password-store=basic', '--disable-gpu', '--hide-scrollbars', `--force-device-scale-factor=${escala}`,
|
|
184
184
|
`--window-size=${w},${h}`, `--screenshot=${alvo}`, 'file://' + tmp], { encoding: 'utf8', timeout: 90000 });
|
|
185
185
|
try { fs.unlinkSync(tmp); } catch {}
|
|
186
186
|
if (fs.existsSync(alvo)) arquivos.push(alvo); else erro = `PNG ${i} não saiu`;
|
|
@@ -1489,7 +1489,7 @@ async function runActInterno(userPrompt, opts) {
|
|
|
1489
1489
|
emVoo = null;
|
|
1490
1490
|
if (!subagent && !avisouReserva && modeloDaVolta && modeloDaVolta.reserva) {
|
|
1491
1491
|
avisouReserva = true;
|
|
1492
|
-
ev('linha', { texto: ` ⎿ ${linhaDaReserva(modeloDaVolta.modelo)}`, nivel: '
|
|
1492
|
+
ev('linha', { texto: ` ⎿ ${linhaDaReserva(modeloDaVolta.modelo)}`, nivel: 'aviso' });
|
|
1493
1493
|
}
|
|
1494
1494
|
traco(`volta ${voltas} voltou em ${Math.round((Date.now() - tRodada) / 1000)}s · ${toolCalls.map((t) => t.name).join(', ') || 'texto'}${streamError ? ' · erro: ' + String(streamError).slice(0, 160) : ''}`);
|
|
1495
1495
|
tempos.somar(subagent ? 'rodada do subagente' : 'rodada do modelo', Date.now() - tRodada);
|
package/lib/tui/ui.js
CHANGED
|
@@ -36,9 +36,11 @@ const PALETTE = {
|
|
|
36
36
|
reset: '\x1b[0m',
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
/* NO_COLOR (https://no-color.org)
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
/* Sem cor: NO_COLOR (https://no-color.org) ou a saída não é um terminal (pipe, arquivo, CI), salvo FORCE_COLOR.
|
|
40
|
+
Nenhum código ANSI sai, nem negrito. */
|
|
41
|
+
const SEM_COR = (process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== '') || (!process.stdout.isTTY && !process.env.FORCE_COLOR);
|
|
42
|
+
if (SEM_COR) {
|
|
43
|
+
for (const k of Object.keys(PALETTE)) PALETTE[k] = '';
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
/* O que a barra da direita da tela cheia mostra e que vem do trabalho do agente:
|
|
@@ -418,6 +420,7 @@ let temaAtual = 'marca';
|
|
|
418
420
|
function definirTema(id) {
|
|
419
421
|
const t = TEMAS[id];
|
|
420
422
|
if (!t) return false;
|
|
423
|
+
if (SEM_COR) { temaAtual = id; return true; }
|
|
421
424
|
PALETTE.brand = `\x1b[38;5;${t.brand}m`; PALETTE.brandDim = `\x1b[38;5;${t.brandDim}m`;
|
|
422
425
|
PALETTE.ok = PALETTE.brand; PALETTE.cyan = PALETTE.brand;
|
|
423
426
|
temaAtual = id;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primocode",
|
|
3
|
-
"version": "11.3.
|
|
3
|
+
"version": "11.3.3",
|
|
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": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"postinstall": "node lib/preparar.js || true",
|
|
12
12
|
"test:server": "cd server && npm test",
|
|
13
13
|
"test": "node scripts/testes.js",
|
|
14
|
-
"test:app": "node test/app-fluxo.test.mjs && node test/app-primeira.test.mjs && node test/app-entrar.test.mjs && node test/app-tela-estudio.test.mjs && node test/app-celular-telas.test.mjs && node test/app-compositor-voz.test.mjs",
|
|
14
|
+
"test:app": "node test/app-fluxo.test.mjs && node test/app-primeira.test.mjs && node test/app-entrar.test.mjs && node test/app-tela-estudio.test.mjs && node test/app-celular-telas.test.mjs && node test/app-compositor-voz.test.mjs && node test/app-render-celular.test.mjs && node test/app-nuvem-estudio.test.mjs",
|
|
15
15
|
"app:build": "cd app && npm run dist",
|
|
16
16
|
"app:dev": "cd app && npm start",
|
|
17
17
|
"mobile:build": "cd mobile && npm run build"
|
package/voz/primo_voz/chat.html
CHANGED
|
@@ -117,11 +117,10 @@ a{color:#67e8f9}a:hover{color:#22d3ee}
|
|
|
117
117
|
.enviar:hover{transform:scale(1.08);background:#4a7de0}
|
|
118
118
|
.enviar:active{transform:scale(.92)}
|
|
119
119
|
.enviar svg{position:absolute;transition:opacity .22s,transform .45s cubic-bezier(.3,1.7,.5,1)}
|
|
120
|
-
.enviar .i-
|
|
121
|
-
.enviar.vazio .i-voz{opacity:1;transform:none}
|
|
120
|
+
.enviar .i-seta,.enviar .i-stop{opacity:0;transform:scale(.3) rotate(-90deg)}
|
|
122
121
|
.enviar.cheio .i-seta{opacity:1;transform:none}
|
|
123
122
|
.enviar.parar .i-stop{opacity:1;transform:none}
|
|
124
|
-
.enviar.
|
|
123
|
+
.enviar.vazio{visibility:hidden;pointer-events:none}
|
|
125
124
|
/* mascote e título */
|
|
126
125
|
.mascote{transition:transform .35s cubic-bezier(.3,1.5,.5,1);filter:drop-shadow(0 0 26px rgba(34,211,238,.35))}
|
|
127
126
|
.pula-entra{animation:cai .9s cubic-bezier(.3,1.6,.5,1) both}
|
|
@@ -354,8 +353,7 @@ a{color:#67e8f9}a:hover{color:#22d3ee}
|
|
|
354
353
|
<button class="chip" id="chipModo" data-a="menuModo"></button>
|
|
355
354
|
<button class="chip" id="chipEf" data-a="menuEf" hidden></button>
|
|
356
355
|
</div>
|
|
357
|
-
<button class="enviar vazio" id="enviar" data-a="enviar" aria-label="
|
|
358
|
-
<svg class="i-voz" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><path d="M5 10v4M9.5 7v10M14 4.5v15M18.5 8v8"></path></svg>
|
|
356
|
+
<button class="enviar vazio" id="enviar" data-a="enviar" aria-label="Enviar">
|
|
359
357
|
<svg class="i-seta" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"></path></svg>
|
|
360
358
|
<svg class="i-stop" width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2.5"></rect></svg>
|
|
361
359
|
</button>
|
|
@@ -413,7 +411,6 @@ var ICO={
|
|
|
413
411
|
var ABAS=[
|
|
414
412
|
{id:'geral',t:'Geral',cor:'#6b6b66',ico:'<path d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM12 2v3M12 19v3M2 12h3M19 12h3M4.9 4.9l2.1 2.1M17 17l2.1 2.1M4.9 19.1 7 17M17 7l2.1-2.1"></path>'},
|
|
415
413
|
{id:'modelos',t:'Modelos',cor:'#7c5cff',ico:'<path d="M12 3l2.2 5.8L20 11l-5.8 2.2L12 19l-2.2-5.8L4 11l5.8-2.2Z"></path>'},
|
|
416
|
-
{id:'voz',t:'Voz',cor:'#f0597a',ico:'<path d="M5 10v4M9.5 7v10M14 4.5v15M18.5 8v8"></path>'},
|
|
417
414
|
{id:'conta',t:'Conta',cor:'#0ea5b7',ico:'<path d="M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8ZM4 21a8 8 0 0 1 16 0"></path>'}
|
|
418
415
|
];
|
|
419
416
|
var MODOS=[
|
|
@@ -667,7 +664,7 @@ var estado={
|
|
|
667
664
|
anexos:[],menu:false,aviso:null,
|
|
668
665
|
skills:null,ajustes:null,busca:'',
|
|
669
666
|
comandos:[],pal:{aberta:false,itens:[],sel:0,q:null},abertas:{},confirma:null,provSel:'',chaveDraft:'',chaveSalva:false,
|
|
670
|
-
|
|
667
|
+
arqBase:'' /* o app desktop manda arqBase (o protocolo que serve os arquivos); no Mac fica vazio */
|
|
671
668
|
};
|
|
672
669
|
var animar=false;
|
|
673
670
|
var mx=0,my=0;
|
|
@@ -841,11 +838,10 @@ function htmlSkills(anim){
|
|
|
841
838
|
/* ajustes */
|
|
842
839
|
function tg(a,on,rot,extra){return '<button class="tg'+(on?' on':'')+'" data-a="'+a+'" aria-label="'+esc(rot)+'"'+(extra||'')+'></button>';}
|
|
843
840
|
function htmlConfig(anim){
|
|
844
|
-
var abas=ABAS.
|
|
841
|
+
var abas=ABAS.map(function(a){
|
|
845
842
|
return '<button class="lado-cfg'+(estado.aba===a.id?' on':'')+'" data-a="aba" data-id="'+a.id+'"><span class="tile" style="background:'+a.cor+'">'+ic(a.ico,14,2.2)+'</span>'+a.t+'</button>';
|
|
846
843
|
}).join('');
|
|
847
|
-
|
|
848
|
-
var corpo={geral:cfgGeral,modelos:cfgModelos,voz:cfgVoz,conta:cfgConta}[estado.aba]();
|
|
844
|
+
var corpo={geral:cfgGeral,modelos:cfgModelos,conta:cfgConta}[estado.aba]();
|
|
849
845
|
return '<div class="'+(anim?'tela-entra':'')+'" style="width:100%;max-width:860px;align-self:center;margin-bottom:auto;display:flex;flex-wrap:wrap;gap:32px">'+
|
|
850
846
|
'<nav style="flex:1 1 170px;max-width:210px;display:flex;flex-direction:column;gap:2px"><h2 style="margin:0 0 14px 8px;font-family:\'Instrument Serif\',serif;font-weight:400;font-size:34px">Ajustes</h2>'+abas+'</nav>'+
|
|
851
847
|
'<div style="flex:999 1 440px;min-width:0">'+corpo+'</div></div>';
|
|
@@ -882,12 +878,6 @@ function cfgModelos(){
|
|
|
882
878
|
}
|
|
883
879
|
return h;
|
|
884
880
|
}
|
|
885
|
-
function cfgVoz(){
|
|
886
|
-
var A=estado.ajustes;
|
|
887
|
-
if(!A||!A.voz)return h3('Voz')+'<p style="color:#8a8983;font-size:13px;margin:16px 4px">Carregando os ajustes.</p>';
|
|
888
|
-
return h3('Voz')+'<div class="grupo"><div class="lin"><label for="vozNome" style="min-width:0">Nome do assistente<small>é a palavra que chama o Primo na voz</small></label><input id="vozNome" class="campo campo-s" data-in="voz_nome" autocomplete="off" value="'+esc(A.voz.nome||'')+'"></div>'+
|
|
889
|
-
'<div class="lin"><span>Sons</span>'+tg('sons',!!A.voz.sons,'Sons')+'</div></div>';
|
|
890
|
-
}
|
|
891
881
|
function cfgConta(){
|
|
892
882
|
if(!estado.logado)return h3('Conta')+'<div class="grupo"><div class="lin"><span>Entre pra salvar as conversas e usar o Primo.</span><button class="entrar" data-a="entrar">Entrar</button></div></div>';
|
|
893
883
|
var ini=(String(estado.email||'?').trim().charAt(0)||'?').toUpperCase();
|
|
@@ -1161,14 +1151,13 @@ function renderAvisos(){
|
|
|
1161
1151
|
var a=estado.aviso,el=$('avisos');
|
|
1162
1152
|
if(!a){el.innerHTML='';return;}
|
|
1163
1153
|
if(a.tipo==='login')el.innerHTML='<div class="cartao-av"><span>Entre na sua conta do PrimoCode pra conversar.</span><span style="display:flex;align-items:center;gap:6px"><button class="entrar" data-a="entrar">Entrar</button><button class="x" data-a="fechaAviso" aria-label="Fechar">'+ic(ICO.x,12,2.4)+'</button></span></div>';
|
|
1164
|
-
else if(a.tipo==='voz')el.innerHTML='<div class="cartao-av"><span style="min-width:0;overflow-wrap:anywhere">'+esc(a.texto)+'</span><span style="display:flex;align-items:center;gap:6px">'+(a.instalar?'<button class="entrar" data-a="vozInstalar">Instalar a voz</button>':'')+(a.instalando?'':'<button class="x" data-a="fechaAviso" aria-label="Fechar">'+ic(ICO.x,12,2.4)+'</button>')+'</span></div>';
|
|
1165
1154
|
else if(a.tipo==='sair')el.innerHTML='<div class="cartao-av"><span>Sair da conta?</span><span style="display:flex;align-items:center;gap:6px"><button class="mc-b" data-a="fechaAviso">Cancelar</button><button class="entrar" style="background:#b8473d" data-a="sairConfirma">Sair</button></span></div>';
|
|
1166
1155
|
else el.innerHTML='<div class="cartao-av erro"><span style="min-width:0;overflow-wrap:anywhere">'+esc(a.texto)+'</span><button class="x" data-a="fechaAviso" aria-label="Fechar">'+ic(ICO.x,12,2.4)+'</button></div>';
|
|
1167
1156
|
}
|
|
1168
1157
|
function atualizaBotao(){
|
|
1169
1158
|
var b=$('enviar'),vazio=!ta().value.trim()&&!estado.anexos.length;
|
|
1170
1159
|
if(estado.esperando){b.className='enviar parar';b.setAttribute('aria-label','Parar');}
|
|
1171
|
-
else if(vazio){b.className='enviar vazio'
|
|
1160
|
+
else if(vazio){b.className='enviar vazio';b.setAttribute('aria-label','Enviar');}
|
|
1172
1161
|
else{b.className='enviar cheio';b.setAttribute('aria-label','Enviar');}
|
|
1173
1162
|
}
|
|
1174
1163
|
function cresce(){var t=ta();t.style.height='auto';t.style.height=Math.min(t.scrollHeight,160)+'px';}
|
|
@@ -1307,13 +1296,6 @@ function appCmd(c,args){
|
|
|
1307
1296
|
var u=ultimaResposta();
|
|
1308
1297
|
if(u){copiarTexto(u,{textContent:'Copiar'});toast('Copiado');}else toast('Nada pra copiar');
|
|
1309
1298
|
break;
|
|
1310
|
-
case 'voz':if(!estado.semVoz)post({acao:'voz'});break;
|
|
1311
|
-
case 'voz_nome':
|
|
1312
|
-
estado.aba='voz';post({acao:'ajustes'});
|
|
1313
|
-
if(args){post({acao:'ajuste',chave:'voz_nome',valor:String(args)});if(estado.ajustes&&estado.ajustes.voz)estado.ajustes.voz.nome=String(args);}
|
|
1314
|
-
navegar('config');
|
|
1315
|
-
setTimeout(function(){var e=$('vozNome');if(e)e.focus();},80);
|
|
1316
|
-
break;
|
|
1317
1299
|
case 'effort':
|
|
1318
1300
|
var efc=estado.ajustes&&estado.ajustes.effort,nvs=efc?efNiveis().map(function(x){return x.nome;}):['low','medium','high','xhigh','max','ultracode'];
|
|
1319
1301
|
if(al){
|
|
@@ -1351,7 +1333,7 @@ function enviar(pular){
|
|
|
1351
1333
|
}
|
|
1352
1334
|
function apertar(){
|
|
1353
1335
|
if(estado.esperando){post({acao:'parar'});estado.esperando=false;estado.passos=[];renderEspera();atualizaBotao();return;}
|
|
1354
|
-
if(!ta().value.trim()&&!estado.anexos.length)
|
|
1336
|
+
if(!ta().value.trim()&&!estado.anexos.length)return;
|
|
1355
1337
|
enviar();
|
|
1356
1338
|
}
|
|
1357
1339
|
function setModo(v){
|
|
@@ -1453,7 +1435,6 @@ document.addEventListener('click',function(e){
|
|
|
1453
1435
|
case 'entrar':post({acao:'entrar'});break;
|
|
1454
1436
|
case 'sair':post({acao:'sair_conta'});break;
|
|
1455
1437
|
case 'fechaAviso':estado.aviso=null;renderAvisos();break;
|
|
1456
|
-
case 'vozInstalar':estado.aviso={tipo:'voz',texto:'Preparando a voz…',instalando:true};renderAvisos();post({acao:'voz_instalar'});break;
|
|
1457
1438
|
case 'link':e.preventDefault();post({acao:'abrir_link',url:d.url});break;
|
|
1458
1439
|
case 'skill':
|
|
1459
1440
|
var k=estado.skills&&estado.skills[+d.i];
|
|
@@ -1480,13 +1461,6 @@ document.addEventListener('click',function(e){
|
|
|
1480
1461
|
estado.chaveDraft='';estado.chaveSalva=true;renderPrincipal();
|
|
1481
1462
|
break;
|
|
1482
1463
|
case 'pasta':post({acao:'escolher_pasta'});break;
|
|
1483
|
-
case 'sons':
|
|
1484
|
-
if(estado.ajustes&&estado.ajustes.voz){
|
|
1485
|
-
estado.ajustes.voz.sons=!estado.ajustes.voz.sons;
|
|
1486
|
-
post({acao:'ajuste',chave:'voz_sons',valor:!!estado.ajustes.voz.sons});
|
|
1487
|
-
renderPrincipal();
|
|
1488
|
-
}
|
|
1489
|
-
break;
|
|
1490
1464
|
}
|
|
1491
1465
|
});
|
|
1492
1466
|
$('lb').addEventListener('click',function(){$('lb').hidden=true;});
|
|
@@ -1526,13 +1500,6 @@ document.addEventListener('input',function(e){
|
|
|
1526
1500
|
document.addEventListener('change',function(e){
|
|
1527
1501
|
var t=e.target;
|
|
1528
1502
|
if(t.id==='provSel'){estado.provSel=t.value;estado.chaveSalva=false;renderPrincipal();}
|
|
1529
|
-
else if(t.getAttribute&&t.getAttribute('data-in')==='voz_nome'){
|
|
1530
|
-
var v=t.value.trim();
|
|
1531
|
-
if(estado.ajustes&&estado.ajustes.voz&&v!==estado.ajustes.voz.nome){
|
|
1532
|
-
estado.ajustes.voz.nome=v;
|
|
1533
|
-
post({acao:'ajuste',chave:'voz_nome',valor:v});
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
1503
|
});
|
|
1537
1504
|
document.addEventListener('keydown',function(e){
|
|
1538
1505
|
if(e.key==='Escape'&&!$('lb').hidden){$('lb').hidden=true;return;}
|
|
@@ -1553,7 +1520,6 @@ document.addEventListener('keydown',function(e){
|
|
|
1553
1520
|
if(e.key==='Escape'&&estado.menu){estado.menu=false;renderMenu();}
|
|
1554
1521
|
if(e.target.id==='pergunta'&&e.key==='Enter'&&!e.shiftKey&&!e.isComposing){e.preventDefault();enviar();}
|
|
1555
1522
|
if(e.target.id==='chaveApi'&&e.key==='Enter'){e.preventDefault();var b=$('chaveBtn');if(b)b.click();}
|
|
1556
|
-
if(e.target.id==='vozNome'&&e.key==='Enter'){e.preventDefault();e.target.blur();}
|
|
1557
1523
|
});
|
|
1558
1524
|
|
|
1559
1525
|
/* arrastar e soltar */
|
|
@@ -1604,7 +1570,7 @@ var tratar={
|
|
|
1604
1570
|
sincConta(v);
|
|
1605
1571
|
if(v.pasta!=null)estado.pasta=v.pasta;
|
|
1606
1572
|
if(v.modo==='chat'||v.modo==='agent')estado.modo=v.modo;
|
|
1607
|
-
estado.
|
|
1573
|
+
estado.arqBase=String(v.arqBase||'');atualizaBotao();
|
|
1608
1574
|
renderConta();renderMenu();renderAvisos();
|
|
1609
1575
|
if(estado.tela==='config')renderPrincipal();
|
|
1610
1576
|
if(estado.logado)pedirConversas();
|
|
@@ -1662,10 +1628,6 @@ var tratar={
|
|
|
1662
1628
|
else{estado.aviso={tipo:'erro',texto:txt};renderAvisos();}
|
|
1663
1629
|
}else{estado.aviso={tipo:'erro',texto:txt};renderAvisos();}
|
|
1664
1630
|
},
|
|
1665
|
-
vozAviso:function(v){ /* o app desktop: a voz não está instalada, está instalando ou terminou */
|
|
1666
|
-
if(!v)return;
|
|
1667
|
-
estado.aviso={tipo:'voz',texto:String(v.texto||''),instalar:!!v.instalar,instalando:!!v.instalando};renderAvisos();
|
|
1668
|
-
},
|
|
1669
1631
|
anexo:function(v){
|
|
1670
1632
|
if(!v||!v.caminho)return;
|
|
1671
1633
|
if(estado.anexos.some(function(a){return a.caminho===v.caminho;}))return;
|
|
@@ -1730,7 +1692,7 @@ if(location.search.indexOf('demo')>=0&&!(window.webkit&&window.webkit.messageHan
|
|
|
1730
1692
|
d1:{id:'d1',titulo:'Botão do WhatsApp no topo',mensagens:[{papel:'voce',texto:'Põe um botão do WhatsApp fixo no topo'},{papel:'primo',texto:'Pronto: o botão fica **fixo no topo**.\n\n- abre a conversa\n- mensagem já escrita\n\nVeja `index.html`:\n```html\n<a class="zap">Fale comigo</a>\n```\nMais em [o site](https://example.com).'}]},
|
|
1731
1693
|
d2:{id:'d2',titulo:'Cardápio com fotos',mensagens:[{papel:'voce',texto:'Monta o cardápio'},{papel:'primo',texto:'Montei o cardápio em 3 seções.'}]}
|
|
1732
1694
|
};
|
|
1733
|
-
var aj={effort:{atual:'medium',niveis:[{nome:'low',resumo:'rápido — tarefa simples, resposta curta'},{nome:'medium',resumo:'equilibrado — o padrão'},{nome:'high',resumo:'pensa mais antes de agir'},{nome:'xhigh',resumo:'bem fundo — tarefas difíceis'},{nome:'max',resumo:'o máximo de raciocínio'},{nome:'ultracode',resumo:'esforço total em código, sem pressa'}]},permissoes:{atual:'auto',opcoes:[{nome:'auto',resumo:'o Primo decide quando pedir licença'},{nome:'livre',resumo:'faz tudo sem perguntar'},{nome:'plano',resumo:'só planeja, não mexe em nada'}]},modo:'agent',provedor:{id:'primo',nome:'Primo',chave_mascarada:''},provedores_chave:[{id:'anthropic',nome:'Anthropic'},{id:'openai',nome:'OpenAI'},{id:'openrouter',nome:'OpenRouter'}],pasta:'~/Primo',
|
|
1695
|
+
var aj={effort:{atual:'medium',niveis:[{nome:'low',resumo:'rápido — tarefa simples, resposta curta'},{nome:'medium',resumo:'equilibrado — o padrão'},{nome:'high',resumo:'pensa mais antes de agir'},{nome:'xhigh',resumo:'bem fundo — tarefas difíceis'},{nome:'max',resumo:'o máximo de raciocínio'},{nome:'ultracode',resumo:'esforço total em código, sem pressa'}]},permissoes:{atual:'auto',opcoes:[{nome:'auto',resumo:'o Primo decide quando pedir licença'},{nome:'livre',resumo:'faz tudo sem perguntar'},{nome:'plano',resumo:'só planeja, não mexe em nada'}]},modo:'agent',provedor:{id:'primo',nome:'Primo',chave_mascarada:''},provedores_chave:[{id:'anthropic',nome:'Anthropic'},{id:'openai',nome:'OpenAI'},{id:'openrouter',nome:'OpenRouter'}],pasta:'~/Primo',conta:{logado:!fora,email:'joel@exemplo.com',plano:'Pro',planoAte:'2026-12-31'}};
|
|
1734
1696
|
function r(m,t){setTimeout(function(){window.chat(m);},t||120);}
|
|
1735
1697
|
window.__demo=function(o){
|
|
1736
1698
|
console.log('post',o);
|
|
@@ -1739,7 +1701,7 @@ if(location.search.indexOf('demo')>=0&&!(window.webkit&&window.webkit.messageHan
|
|
|
1739
1701
|
r({passo:'Lendo a pasta do projeto'},400);
|
|
1740
1702
|
r({saida:{comando:o.texto.split(' ')[0],texto:'projeto/\n├── src/\n│ ├── app.js 12 KB\n│ └── util.js 3 KB\n├── public/\n│ └── capa.png 80 KB\n└── package.json\n\n✓ 3 pastas, 4 arquivos em /demo/projeto\n✗ falta o README.md\n'+Array.apply(null,Array(24)).map(function(_,i){return 'linha extra '+(i+1);}).join('\n'),conversa:null,midias:[{achado:'/demo/projeto',caminho:'/demo/projeto',nome:'projeto',tipo:'pasta',url:'',tamanho:0}]}},1200);
|
|
1741
1703
|
break;
|
|
1742
|
-
case 'pronto':r({comandos:[{nome:'/tree',descricao:'árvore do projeto',tipo:'terminal'},{nome:'/read',descricao:'lê um arquivo',tipo:'terminal'},{nome:'/
|
|
1704
|
+
case 'pronto':r({comandos:[{nome:'/tree',descricao:'árvore do projeto',tipo:'terminal'},{nome:'/read',descricao:'lê um arquivo',tipo:'terminal'},{nome:'/nova',descricao:'começa uma conversa nova',tipo:'app',acao:'nova'},{nome:'/modo',descricao:'chat ou agent',tipo:'app',acao:'modo'},{nome:'/copiar',descricao:'copia a última resposta',tipo:'app',acao:'copiar'},{nome:'/sair',descricao:'sai da conta',tipo:'app',acao:'sair_conta'},{nome:'/ajuda',descricao:'mostra todos os comandos',tipo:'app',acao:'ajuda'},{nome:'/effort',descricao:'nível de esforço do Primo',tipo:'app',acao:'effort'},{nome:'/permissoes',descricao:'o que o Primo pode fazer sozinho',tipo:'app',acao:'permissoes'},{nome:'/revisar',descricao:'revisa o código do projeto',tipo:'pedido'},{nome:'/explicar',descricao:'explica o que o projeto faz',tipo:'pedido'}]},300);
|
|
1743
1705
|
r({inicio:{logado:!fora,email:fora?'':'joel@exemplo.com',plano:'Pro',planoAte:'2026-12-31',pasta:'~/Primo',modo:'agent'}});break;
|
|
1744
1706
|
case 'conversas':r({conversas:[{id:'d2',titulo:'Cardápio com fotos',atualizada:'2026-10-18T10:00:00Z'},{id:'d1',titulo:'Botão do WhatsApp no topo',atualizada:'2026-10-19T09:00:00Z'}]});break;
|
|
1745
1707
|
case 'abrir':if(convs[o.id])r({conversa:convs[o.id]});break;
|