primocode 9.8.0-beta.7 → 9.8.0-beta.8
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 +5 -5
- package/app/app.css +482 -281
- package/app/app.js +888 -315
- package/app/index.html +176 -101
- package/app/primo-marca.js +58 -1
- package/bin/primocode.js +54 -21
- package/lib/act.js +5 -0
- package/lib/app.js +297 -89
- package/lib/fala.js +95 -1
- package/lib/{ide.js → painel.js} +41 -87
- package/package.json +2 -2
- package/app/ide.css +0 -345
- package/app/ide.html +0 -183
- package/app/ide.js +0 -639
package/app/index.html
CHANGED
|
@@ -8,138 +8,213 @@
|
|
|
8
8
|
<link rel="icon" href="/icone.svg">
|
|
9
9
|
</head>
|
|
10
10
|
<!--
|
|
11
|
-
A janela do PrimoCode
|
|
11
|
+
A janela do PrimoCode — /rc, /ide e `primo ide` abrem esta mesma página.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
O layout é o de um app de mesa de agente: barra lateral com novo chat,
|
|
14
|
+
projetos e recentes; a pergunta no meio da tela vazia; o compositor embaixo
|
|
15
|
+
com projeto, anexo, permissão, esforço e voz; e um painel à direita com a
|
|
16
|
+
prévia do site e os arquivos (a IDE antiga, sem o editor).
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
Os ícones são SVG em linha, de propósito: sem fonte de ícone, sem CDN, sem
|
|
19
|
+
pedir nada fora da máquina (regra do AGENTS.md). Cada um é um <symbol> aqui
|
|
20
|
+
em cima e um <use> onde aparece — o mesmo desenho não é copiado dez vezes.
|
|
21
21
|
-->
|
|
22
22
|
<body>
|
|
23
23
|
|
|
24
|
-
<
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
|
|
25
|
+
<defs>
|
|
26
|
+
<symbol id="i-lado" viewBox="0 0 24 24"><rect x="3.5" y="4.5" width="17" height="15" rx="3"/><path d="M9.5 4.5v15"/></symbol>
|
|
27
|
+
<symbol id="i-painel" viewBox="0 0 24 24"><rect x="3.5" y="4.5" width="17" height="15" rx="3"/><path d="M14.5 4.5v15"/></symbol>
|
|
28
|
+
<symbol id="i-chev" viewBox="0 0 24 24"><path d="m7 10 5 5 5-5"/></symbol>
|
|
29
|
+
<symbol id="i-busca" viewBox="0 0 24 24"><circle cx="11" cy="11" r="6"/><path d="m20 20-4.6-4.6"/></symbol>
|
|
30
|
+
<symbol id="i-sino" viewBox="0 0 24 24"><path d="M6.5 16.5V11a5.5 5.5 0 0 1 11 0v5.5l1.5 1.5H5z"/><path d="M10 20.5a2 2 0 0 0 4 0"/></symbol>
|
|
31
|
+
<symbol id="i-editar" viewBox="0 0 24 24"><path d="M11 4.5H7a2.5 2.5 0 0 0-2.5 2.5v10A2.5 2.5 0 0 0 7 19.5h10a2.5 2.5 0 0 0 2.5-2.5v-4"/><path d="M17.8 3.9a1.8 1.8 0 0 1 2.5 2.5L12 14.7l-3.3.8.8-3.3z"/></symbol>
|
|
32
|
+
<symbol id="i-mais-circ" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8"/><path d="M12 8.5v7M8.5 12h7"/></symbol>
|
|
33
|
+
<symbol id="i-terminal" viewBox="0 0 24 24"><rect x="3.5" y="4.5" width="17" height="15" rx="3"/><path d="m7.5 10 2.5 2-2.5 2M12.5 14.5h4"/></symbol>
|
|
34
|
+
<symbol id="i-olho" viewBox="0 0 24 24"><path d="M2.8 12S6 5.8 12 5.8 21.2 12 21.2 12 18 18.2 12 18.2 2.8 12 2.8 12z"/><circle cx="12" cy="12" r="2.6"/></symbol>
|
|
35
|
+
<symbol id="i-barra" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="m14 7.5-4 9"/></symbol>
|
|
36
|
+
<symbol id="i-ajuda" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M9.7 9.6a2.4 2.4 0 1 1 3.3 2.2c-.6.3-1 .8-1 1.5v.4"/><circle cx="12" cy="16.6" r=".4"/></symbol>
|
|
37
|
+
<symbol id="i-pasta" viewBox="0 0 24 24"><path d="M3.5 7.5A2 2 0 0 1 5.5 5.5h3.8l2 2h7.2a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-13a2 2 0 0 1-2-2z"/></symbol>
|
|
38
|
+
<symbol id="i-mais" viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></symbol>
|
|
39
|
+
<symbol id="i-perigo" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.8v5.2"/><circle cx="12" cy="16.3" r=".5"/></symbol>
|
|
40
|
+
<symbol id="i-escudo" viewBox="0 0 24 24"><path d="M12 3.5 5.5 6v5.2c0 4.3 2.8 7.6 6.5 9.3 3.7-1.7 6.5-5 6.5-9.3V6z"/><path d="m9.2 12 2 2 3.8-4"/></symbol>
|
|
41
|
+
<symbol id="i-mao" viewBox="0 0 24 24"><path d="M12 3.5 5.5 6v5.2c0 4.3 2.8 7.6 6.5 9.3 3.7-1.7 6.5-5 6.5-9.3V6z"/><path d="M12 8.5v4"/><circle cx="12" cy="15.6" r=".5"/></symbol>
|
|
42
|
+
<symbol id="i-mic" viewBox="0 0 24 24"><rect x="9" y="3.5" width="6" height="11" rx="3"/><path d="M5.8 11.5a6.2 6.2 0 0 0 12.4 0M12 17.7v2.8"/></symbol>
|
|
43
|
+
<symbol id="i-seta" viewBox="0 0 24 24"><path d="M12 19V5.5M6.5 11 12 5.5l5.5 5.5"/></symbol>
|
|
44
|
+
<symbol id="i-fechar" viewBox="0 0 24 24"><path d="m6.5 6.5 11 11M17.5 6.5l-11 11"/></symbol>
|
|
45
|
+
<symbol id="i-recarregar" viewBox="0 0 24 24"><path d="M19 12a7 7 0 1 1-2.1-5"/><path d="M19.2 4.5v4h-4"/></symbol>
|
|
46
|
+
<symbol id="i-arquivo" viewBox="0 0 24 24"><path d="M7 3.5h6.5l4.5 4.5v11a1.5 1.5 0 0 1-1.5 1.5h-9.5A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z"/><path d="M13.5 3.5V8H18"/></symbol>
|
|
47
|
+
<symbol id="i-ler" viewBox="0 0 24 24"><path d="M7 3.5h6.5l4.5 4.5v11a1.5 1.5 0 0 1-1.5 1.5h-9.5A1.5 1.5 0 0 1 5.5 19V5A1.5 1.5 0 0 1 7 3.5z"/><path d="M8.5 12.5h7M8.5 16h5"/></symbol>
|
|
48
|
+
<symbol id="i-rodar" viewBox="0 0 24 24"><path d="m6 8.5 4 3.5-4 3.5M12 16h6"/></symbol>
|
|
49
|
+
<symbol id="i-web" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M3.5 12h17M12 3.5c2.4 2.4 3.4 5.3 3.4 8.5s-1 6.1-3.4 8.5c-2.4-2.4-3.4-5.3-3.4-8.5s1-6.1 3.4-8.5z"/></symbol>
|
|
50
|
+
<symbol id="i-computador" viewBox="0 0 24 24"><rect x="3.5" y="4.5" width="17" height="11.5" rx="2"/><path d="M9 20h6M12 16v4"/></symbol>
|
|
51
|
+
<symbol id="i-plano" viewBox="0 0 24 24"><path d="M9.5 7h10M9.5 12h10M9.5 17h10"/><path d="m4 7 1.2 1.2L7 6.3M4 12l1.2 1.2L7 11.3"/><circle cx="5.5" cy="17" r=".8"/></symbol>
|
|
52
|
+
<symbol id="i-agente" viewBox="0 0 24 24"><rect x="5" y="7.5" width="14" height="11" rx="3"/><path d="M12 7.5V4.5"/><circle cx="9.5" cy="12.5" r=".9"/><circle cx="14.5" cy="12.5" r=".9"/></symbol>
|
|
53
|
+
<symbol id="i-pare" viewBox="0 0 24 24"><rect x="7.5" y="7.5" width="9" height="9" rx="1.6" fill="currentColor" stroke="none"/></symbol>
|
|
54
|
+
</defs>
|
|
55
|
+
</svg>
|
|
56
|
+
|
|
57
|
+
<div class="app" id="app">
|
|
58
|
+
<aside class="lado" id="lado" aria-label="Conversas e projetos">
|
|
59
|
+
<div class="lado-barra">
|
|
60
|
+
<button class="icone-btn" id="btnLado" type="button" aria-label="Recolher a barra lateral" title="Barra lateral (Ctrl+B)">
|
|
61
|
+
<svg class="ic"><use href="#i-lado"/></svg>
|
|
37
62
|
</button>
|
|
38
63
|
</div>
|
|
39
64
|
|
|
40
|
-
<div class="
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
65
|
+
<div class="lado-marca">
|
|
66
|
+
<button class="marca-btn" id="btnMarca" type="button" aria-haspopup="menu">
|
|
67
|
+
<span>PrimoCode</span><svg class="ic ic-p"><use href="#i-chev"/></svg>
|
|
68
|
+
</button>
|
|
69
|
+
<div class="lado-acoes">
|
|
70
|
+
<button class="icone-btn" id="btnBusca" type="button" aria-label="Buscar nos recentes" title="Buscar"><svg class="ic"><use href="#i-busca"/></svg></button>
|
|
71
|
+
<button class="icone-btn" id="btnAvisos" type="button" aria-pressed="false" aria-label="Avisar quando terminar" title="Avisar quando o Primo terminar"><svg class="ic"><use href="#i-sino"/></svg></button>
|
|
44
72
|
</div>
|
|
45
73
|
</div>
|
|
46
74
|
|
|
47
|
-
<div class="
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
</button>
|
|
56
|
-
<div class="chips">
|
|
57
|
-
<span class="chip" id="pasta" title="pasta de trabalho"></span>
|
|
58
|
-
<span class="chip" id="modo"></span>
|
|
59
|
-
<span class="chip" id="esforco"></span>
|
|
75
|
+
<div class="busca" id="busca" hidden>
|
|
76
|
+
<input id="campoBusca" type="search" placeholder="Buscar nos recentes" autocomplete="off">
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<nav class="nav" aria-label="Principal">
|
|
80
|
+
<div class="nav-linha">
|
|
81
|
+
<button class="nav-item ativo" id="btnNovo" type="button"><svg class="ic"><use href="#i-editar"/></svg>Novo chat</button>
|
|
82
|
+
<button class="icone-btn" id="btnNovoProjeto" type="button" aria-label="Novo projeto" title="Novo projeto em ~/primocode"><svg class="ic"><use href="#i-mais-circ"/></svg></button>
|
|
60
83
|
</div>
|
|
84
|
+
<button class="nav-item" id="navTerminal" type="button" aria-pressed="false"><svg class="ic"><use href="#i-terminal"/></svg>Terminal</button>
|
|
85
|
+
<button class="nav-item" id="navPrevia" type="button"><svg class="ic"><use href="#i-olho"/></svg>Prévia do site</button>
|
|
86
|
+
<button class="nav-item" id="navComandos" type="button"><svg class="ic"><use href="#i-barra"/></svg>Comandos</button>
|
|
87
|
+
</nav>
|
|
88
|
+
|
|
89
|
+
<div class="rolagem-lado">
|
|
90
|
+
<div class="secao" id="secaoProjetos">Projetos</div>
|
|
91
|
+
<div class="lista" id="listaProjetos"><div class="vazio-lista">Nenhum projeto</div></div>
|
|
92
|
+
|
|
93
|
+
<div class="secao" id="secaoRecentes">Recentes</div>
|
|
94
|
+
<div class="lista" id="listaRecentes"><div class="vazio-lista">Nenhuma conversa ainda</div></div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<div class="lado-pe">
|
|
98
|
+
<div class="usuario"><span class="avatar" id="avatar">PC</span><span class="nome-usuario" id="nomeUsuario">Você</span></div>
|
|
99
|
+
<button class="icone-btn" id="btnAjuda" type="button" aria-label="Atalhos e comandos" title="Atalhos e comandos"><svg class="ic"><use href="#i-ajuda"/></svg></button>
|
|
61
100
|
</div>
|
|
62
101
|
</aside>
|
|
63
102
|
|
|
64
|
-
<main class="
|
|
103
|
+
<main class="centro">
|
|
104
|
+
<header class="topo">
|
|
105
|
+
<button class="icone-btn" id="btnLadoAbrir" type="button" aria-label="Abrir a barra lateral" title="Barra lateral (Ctrl+B)"><svg class="ic"><use href="#i-lado"/></svg></button>
|
|
106
|
+
<div class="topo-titulo" id="topoTitulo"></div>
|
|
107
|
+
<button class="icone-btn" id="btnPainel" type="button" aria-pressed="false" aria-label="Abrir a prévia e os arquivos" title="Prévia e arquivos"><svg class="ic"><use href="#i-painel"/></svg></button>
|
|
108
|
+
</header>
|
|
109
|
+
|
|
65
110
|
<div class="rolo" id="rolo">
|
|
66
|
-
<
|
|
67
|
-
<span id="
|
|
68
|
-
<h1>O que
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
<div class="sugestoes">
|
|
72
|
-
<button class="sugestao" data-manda="/all">o que ele sabe fazer</button>
|
|
73
|
-
<button class="sugestao" data-manda="/project">meus projetos</button>
|
|
74
|
-
<button class="sugestao" data-manda="/effort">esforço</button>
|
|
75
|
-
<button class="sugestao" data-manda="/help">comandos</button>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
<div id="conversa" class="tira" hidden></div>
|
|
111
|
+
<section class="vazio" id="vazio">
|
|
112
|
+
<span class="mascote" id="mascote"></span>
|
|
113
|
+
<h1>O que vamos criar?</h1>
|
|
114
|
+
</section>
|
|
115
|
+
<div class="chat" id="chat" hidden aria-live="polite"></div>
|
|
79
116
|
</div>
|
|
80
117
|
|
|
81
|
-
<
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
118
|
+
<section class="terminal" id="terminal" hidden aria-label="Terminal">
|
|
119
|
+
<header class="terminal-topo">
|
|
120
|
+
<span><b>Terminal</b> <small>o mesmo que aparece no CLI</small></span>
|
|
121
|
+
<button class="icone-btn" id="fecharTerminal" type="button" aria-label="Voltar para o chat"><svg class="ic"><use href="#i-fechar"/></svg></button>
|
|
122
|
+
</header>
|
|
123
|
+
<pre class="terminal-saida" id="terminalSaida"></pre>
|
|
124
|
+
</section>
|
|
125
|
+
|
|
126
|
+
<footer class="rodape">
|
|
127
|
+
<div class="compositor-zona" id="zona">
|
|
128
|
+
<div class="projeto-barra">
|
|
129
|
+
<button class="projeto-btn" id="btnProjeto" type="button" aria-haspopup="menu">
|
|
130
|
+
<svg class="ic"><use href="#i-pasta"/></svg><span id="projetoNome">Escolher projeto</span>
|
|
131
|
+
</button>
|
|
88
132
|
</div>
|
|
89
|
-
<
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
133
|
+
<form class="compositor" id="forma">
|
|
134
|
+
<div class="anexos" id="anexos" hidden></div>
|
|
135
|
+
<textarea id="campo" rows="1" placeholder="Peça qualquer coisa" autocomplete="off" spellcheck="false" aria-label="Pedido"></textarea>
|
|
136
|
+
<div class="controles">
|
|
137
|
+
<button class="icone-btn grande" id="btnAnexar" type="button" aria-label="Anexar arquivo" title="Anexar arquivo"><svg class="ic"><use href="#i-mais"/></svg></button>
|
|
138
|
+
<input id="arquivo" type="file" multiple hidden>
|
|
139
|
+
<button class="chip-perm" id="btnPermissao" type="button" aria-haspopup="menu" data-modo="auto">
|
|
140
|
+
<svg class="ic" id="permIcone"><use href="#i-escudo"/></svg><span id="permRotulo">Pergunta antes do perigoso</span>
|
|
141
|
+
</button>
|
|
142
|
+
<span class="espaco"></span>
|
|
143
|
+
<button class="seletor" id="btnEsforco" type="button" aria-haspopup="menu" title="Esforço do agente (/effort)">
|
|
144
|
+
<b id="esforcoRotulo">Equilíbrio</b><span id="esforcoNome">medium</span><svg class="ic ic-p"><use href="#i-chev"/></svg>
|
|
145
|
+
</button>
|
|
146
|
+
<button class="icone-btn" id="btnMic" type="button" aria-pressed="false" aria-label="Ligar o modo voz" title="Modo voz (/voice)"><svg class="ic"><use href="#i-mic"/></svg></button>
|
|
147
|
+
<button class="enviar" id="btnEnviar" type="submit" disabled aria-label="Enviar" title="Enviar (Enter)"><svg class="ic"><use href="#i-seta"/></svg></button>
|
|
148
|
+
</div>
|
|
149
|
+
</form>
|
|
150
|
+
</div>
|
|
151
|
+
</footer>
|
|
101
152
|
</main>
|
|
102
|
-
</div>
|
|
103
153
|
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
154
|
+
<aside class="painel" id="painel" hidden aria-label="Prévia e arquivos">
|
|
155
|
+
<header class="painel-topo">
|
|
156
|
+
<div class="abas" role="tablist">
|
|
157
|
+
<button class="aba" id="abaPrevia" type="button" role="tab" aria-selected="true">Prévia</button>
|
|
158
|
+
<button class="aba" id="abaArquivos" type="button" role="tab" aria-selected="false">Arquivos</button>
|
|
159
|
+
</div>
|
|
160
|
+
<span class="espaco"></span>
|
|
161
|
+
<button class="icone-btn" id="btnRecarregar" type="button" aria-label="Recarregar" title="Recarregar"><svg class="ic"><use href="#i-recarregar"/></svg></button>
|
|
162
|
+
<button class="icone-btn" id="fecharPainel" type="button" aria-label="Fechar o painel"><svg class="ic"><use href="#i-fechar"/></svg></button>
|
|
163
|
+
</header>
|
|
164
|
+
<div class="painel-corpo" id="corpoPrevia">
|
|
165
|
+
<iframe class="previa" id="previa" title="Prévia do site"
|
|
166
|
+
sandbox="allow-scripts allow-forms allow-modals allow-popups allow-pointer-lock"></iframe>
|
|
167
|
+
<div class="painel-vazio" id="previaVazia" hidden>
|
|
168
|
+
<span class="mascote pequeno" id="mascotePainel"></span>
|
|
169
|
+
<p>Ainda não tem site nesta pasta.</p>
|
|
170
|
+
<p class="fraco">Peça "crie uma página de…" e ele aparece aqui, atualizando sozinho.</p>
|
|
116
171
|
</div>
|
|
117
172
|
</div>
|
|
118
|
-
<div class="
|
|
119
|
-
<
|
|
120
|
-
<div class="
|
|
121
|
-
<
|
|
122
|
-
<
|
|
123
|
-
<button class="cor" data-cor="roxo" style="background:#a78bfa" aria-label="Roxo"></button>
|
|
124
|
-
<button class="cor" data-cor="ambar" style="background:#fbbf24" aria-label="Âmbar"></button>
|
|
125
|
-
<button class="cor" data-cor="rosa" style="background:#fb7185" aria-label="Rosa"></button>
|
|
173
|
+
<div class="painel-corpo arquivos" id="corpoArquivos" hidden>
|
|
174
|
+
<div class="arvore" id="arvore" role="tree"></div>
|
|
175
|
+
<div class="visor">
|
|
176
|
+
<div class="visor-topo" id="visorNome">Escolha um arquivo</div>
|
|
177
|
+
<pre class="visor-texto" id="visor"></pre>
|
|
126
178
|
</div>
|
|
127
179
|
</div>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
180
|
+
</aside>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<div class="menu" id="menu" role="menu" hidden></div>
|
|
184
|
+
|
|
185
|
+
<dialog class="dialogo" id="dlgAjuda" aria-labelledby="tituloAjuda">
|
|
186
|
+
<header class="dlg-topo">
|
|
187
|
+
<h2 id="tituloAjuda">Atalhos e comandos</h2>
|
|
188
|
+
<button class="icone-btn" id="fecharAjuda" type="button" aria-label="Fechar"><svg class="ic"><use href="#i-fechar"/></svg></button>
|
|
189
|
+
</header>
|
|
190
|
+
<div class="dlg-corpo">
|
|
191
|
+
<h3>Teclado</h3>
|
|
192
|
+
<dl class="atalhos">
|
|
193
|
+
<dt><kbd>Enter</kbd></dt><dd>manda o pedido</dd>
|
|
194
|
+
<dt><kbd>Shift</kbd> <kbd>Enter</kbd></dt><dd>quebra a linha</dd>
|
|
195
|
+
<dt><kbd>Esc</kbd> <kbd>Esc</kbd></dt><dd>para o que o Primo está fazendo</dd>
|
|
196
|
+
<dt><kbd>Ctrl</kbd> <kbd>B</kbd></dt><dd>mostra ou esconde a barra lateral</dd>
|
|
197
|
+
<dt><kbd>Ctrl</kbd> <kbd>J</kbd></dt><dd>abre o terminal</dd>
|
|
198
|
+
</dl>
|
|
199
|
+
<h3>Comandos</h3>
|
|
200
|
+
<p class="fraco">Digite no campo, como no terminal. Clique para usar.</p>
|
|
201
|
+
<div class="comandos" id="listaComandos">
|
|
202
|
+
<button type="button" data-cmd="/help">/help <span>todos os comandos</span></button>
|
|
203
|
+
<button type="button" data-cmd="/novo ">/novo <span>projeto novo, do zero</span></button>
|
|
204
|
+
<button type="button" data-cmd="/abrir">/abrir <span>abre o site do projeto</span></button>
|
|
205
|
+
<button type="button" data-cmd="/desfazer">/desfazer <span>volta o que ele mexeu</span></button>
|
|
206
|
+
<button type="button" data-cmd="/status">/status <span>conta e servidor</span></button>
|
|
207
|
+
<button type="button" data-cmd="/mascot">/mascot <span>troca o mascote</span></button>
|
|
208
|
+
<button type="button" data-cmd="/login">/login <span>entra na sua conta</span></button>
|
|
209
|
+
<button type="button" data-cmd="/doctor">/doctor <span>confere o que costuma dar problema</span></button>
|
|
136
210
|
</div>
|
|
137
211
|
</div>
|
|
138
212
|
</dialog>
|
|
139
213
|
|
|
140
|
-
<div
|
|
214
|
+
<div class="alvo-solto" id="alvoSolto"><div><strong>Solte aqui</strong><span>o arquivo entra como anexo do pedido</span></div></div>
|
|
141
215
|
|
|
142
216
|
<script src="/primo-marca.js"></script>
|
|
217
|
+
<script src="/ansi.js"></script>
|
|
143
218
|
<script src="/app.js"></script>
|
|
144
219
|
</body>
|
|
145
220
|
</html>
|
package/app/primo-marca.js
CHANGED
|
@@ -131,5 +131,62 @@
|
|
|
131
131
|
return "data:image/svg+xml," + encodeURIComponent(logo({ tamanho: 32 }));
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
/* ── O MASCOTE EM TRAÇO ────────────────────────────────────────────────
|
|
135
|
+
A tela vazia da janela pede um ícone de LINHA, fino e neutro, no lugar
|
|
136
|
+
do bicho em pixel colorido: a janela é cinza e calma, e um mascote de
|
|
137
|
+
blocos cianos no meio dela gritava mais alto que a pergunta. Um traço
|
|
138
|
+
por mascote de lib/ui.js (MASCOTS), mesmo nome de id — quem escolheu a
|
|
139
|
+
coruja no /mascot vê a coruja aqui também. Os três de orelha (primo,
|
|
140
|
+
raposa, gato) têm o ❯_ do prompt no rosto: é a marca do PrimoCode.
|
|
141
|
+
|
|
142
|
+
Tudo em `currentColor`, então a cor vem do CSS e segue o tema. */
|
|
143
|
+
var CORPO_LINHA = "M14 16h20a5 5 0 0 1 5 5v12a5 5 0 0 1-5 5H14a5 5 0 0 1-5-5V21a5 5 0 0 1 5-5z";
|
|
144
|
+
var ROSTO_PROMPT = "M17 23.5l4 3.5-4 3.5M24 31h7";
|
|
145
|
+
var PES = "M17 38v4M31 38v4";
|
|
146
|
+
var LINHAS = {
|
|
147
|
+
primo: [CORPO_LINHA, ROSTO_PROMPT, PES, "M16 16v-6h4v6M28 16v-6h4v6", "M9 26H5M39 26h4"],
|
|
148
|
+
fox: [CORPO_LINHA, ROSTO_PROMPT, PES, "M12 17 9 6l9 10M36 17l3-11-9 10"],
|
|
149
|
+
cat: [CORPO_LINHA, ROSTO_PROMPT, PES, "M14 16l1-7 6 7M34 16l-1-7-6 7"],
|
|
150
|
+
robo: ["M13 14h22a4 4 0 0 1 4 4v14a4 4 0 0 1-4 4H13a4 4 0 0 1-4-4V18a4 4 0 0 1 4-4z",
|
|
151
|
+
"M24 14V9", "c24 6.5 2", "c18 24 2.5", "c30 24 2.5", "M19 31h10", "M16 36v5M32 36v5"],
|
|
152
|
+
coruja: ["M12 11l6 5h12l6-5v19a12 12 0 0 1-24 0z", "c19 24 4", "c29 24 4", "M24 29l-2 3h4z"],
|
|
153
|
+
dragao: [CORPO_LINHA, PES, "M13 16 9 8M35 16l4-8", "M9 22 3 18v10l6-2M39 22l6-4v10l-6-2",
|
|
154
|
+
"c18.5 25 1.5", "c29.5 25 1.5", "M21 31h6"],
|
|
155
|
+
fantasma: ["M12 40V22a12 12 0 0 1 24 0v18l-4-3-4 3-4-3-4 3-4-3z", "c20 23 2", "c28 23 2"],
|
|
156
|
+
capivara: ["M8 24c0-6 5-9 11-9h13c6 0 9 5 9 11v5a6 6 0 0 1-6 6H14a6 6 0 0 1-6-6z",
|
|
157
|
+
"M14 16l1-4 4 3", "c14.5 22.5 1.5", "M8 27h3", "M15 37v4M33 37v4"],
|
|
158
|
+
polvo: ["M14 27a10 10 0 1 1 20 0v1H14z", "c20 22 1.5", "c28 22 1.5",
|
|
159
|
+
"M15 28c-4 4-6 8-3 12M20 28c-1 5-1 9 1 12M28 28c1 5 1 9-1 12M33 28c4 4 6 8 3 12"],
|
|
160
|
+
pinguim: ["M24 7c-8 0-12 8-12 18s4 15 12 15 12-5 12-15S32 7 24 7z",
|
|
161
|
+
"M24 18c-4 0-6 5-6 11s2 8 6 8 6-2 6-8-2-11-6-11z", "c20.5 14 1.2", "c27.5 14 1.2",
|
|
162
|
+
"M22 17l2 2 2-2", "M18 41h5M25 41h5"],
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* O mascote em traço, para a tela vazia.
|
|
167
|
+
* @param {object} op
|
|
168
|
+
* @param {string} [op.mascote] id de lib/ui.js (primo, fox, cat, robo…); desconhecido = primo
|
|
169
|
+
* @param {number} [op.tamanho] lado em px
|
|
170
|
+
* @param {string} [op.rotulo] texto alternativo; vazio = decorativo
|
|
171
|
+
*/
|
|
172
|
+
function linha(op) {
|
|
173
|
+
op = op || {};
|
|
174
|
+
var lado = op.tamanho || 48;
|
|
175
|
+
var partes = LINHAS[op.mascote] || LINHAS.primo;
|
|
176
|
+
var acessivel = op.rotulo
|
|
177
|
+
? ' role="img" aria-label="' + String(op.rotulo).replace(/"/g, """) + '"'
|
|
178
|
+
: ' aria-hidden="true"';
|
|
179
|
+
var corpo = partes.map(function (d) {
|
|
180
|
+
if (d.charAt(0) === "c") { // "cX Y R" = círculo
|
|
181
|
+
var n = d.slice(1).split(" ");
|
|
182
|
+
return '<circle cx="' + n[0] + '" cy="' + n[1] + '" r="' + n[2] + '"/>';
|
|
183
|
+
}
|
|
184
|
+
return '<path d="' + d + '"/>';
|
|
185
|
+
}).join("");
|
|
186
|
+
return '<svg viewBox="0 0 48 48" width="' + lado + '" height="' + lado + '"' + acessivel
|
|
187
|
+
+ ' fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">'
|
|
188
|
+
+ corpo + "</svg>";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
raiz.PrimoMarca = { svg: svg, logo: logo, linha: linha, LINHAS: LINHAS, favicon: favicon, MATRIZ: MATRIZ, CORPO: CORPO, DETALHE: DETALHE };
|
|
135
192
|
})(typeof window !== "undefined" ? window : globalThis);
|
package/bin/primocode.js
CHANGED
|
@@ -108,10 +108,10 @@ const state = {
|
|
|
108
108
|
// existe para a frente em vez de subir outro servidor ao lado.
|
|
109
109
|
let janelaAberta = null;
|
|
110
110
|
|
|
111
|
-
/* O que
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
/* O que o /rc, o /ide e o `primo --app` passam ao lib/app.js. Uma função
|
|
112
|
+
só porque os três sobem a MESMA janela: se cada um montasse a sua, o /ide
|
|
113
|
+
aberto depois do /rc acharia um servidor sem a pasta do projeto — e o
|
|
114
|
+
painel da prévia nasceria vazio. */
|
|
115
115
|
function opcoesDaJanela(extra) {
|
|
116
116
|
return Object.assign({
|
|
117
117
|
versao: VERSION,
|
|
@@ -123,10 +123,37 @@ function opcoesDaJanela(extra) {
|
|
|
123
123
|
projeto: state.currentProject,
|
|
124
124
|
modo: state.mode,
|
|
125
125
|
esforco: state.config.effort,
|
|
126
|
+
permissoes: perigo.normalizarModo(state.config.permissoes),
|
|
127
|
+
voz: !!vozEmEspera,
|
|
128
|
+
usuario: state.config.userName || null,
|
|
129
|
+
mascote: state.config.mascot || 'primo',
|
|
130
|
+
anexos: state.attachedFiles.map((f) => f.path),
|
|
126
131
|
}),
|
|
127
132
|
// Lida na hora, não guardada: o /dir e o /project trocam a pasta
|
|
128
|
-
// com a
|
|
133
|
+
// com a janela aberta, e o painel tem de acompanhar.
|
|
129
134
|
pastaProjeto: () => projectDir(),
|
|
135
|
+
/* As ações da janela passam pelos MESMOS caminhos dos comandos — o
|
|
136
|
+
/projetos, o /clear, o /permissoes, o /effort, o /attach — para a
|
|
137
|
+
janela e o terminal nunca discordarem sobre onde se está. */
|
|
138
|
+
entrarProjeto: (dir) => {
|
|
139
|
+
entrarNoProjeto(dir, 'projeto');
|
|
140
|
+
console.log(c.ok(` Trabalhando em ${state.currentProject}`) + c.muted(` (${shortPath(dir)})`));
|
|
141
|
+
refreshPrompt();
|
|
142
|
+
},
|
|
143
|
+
novoChat: () => handleSlash('/clear'),
|
|
144
|
+
mudarPermissoes: (m) => handleSlash('/permissoes ' + m),
|
|
145
|
+
mudarEsforco: (n) => aplicarEffort(n),
|
|
146
|
+
anexar: (f) => {
|
|
147
|
+
state.attachedFiles.push(f);
|
|
148
|
+
console.log(c.ok(`Anexado: ${f.path} (${tools.fmtBytes(f.content.length)})`) + c.muted(' pela janela'));
|
|
149
|
+
refreshPrompt();
|
|
150
|
+
},
|
|
151
|
+
desanexar: (nome) => {
|
|
152
|
+
state.attachedFiles = nome ? state.attachedFiles.filter((f) => f.path !== nome) : [];
|
|
153
|
+
refreshPrompt();
|
|
154
|
+
},
|
|
155
|
+
voz: (ligar) => handleSlash(ligar ? '/voice' : '/voice parar'),
|
|
156
|
+
continuarConversa: (alvo) => abrirConversa(alvo),
|
|
130
157
|
}, extra || {});
|
|
131
158
|
}
|
|
132
159
|
|
|
@@ -153,7 +180,7 @@ ${c.bold('Comandos')}
|
|
|
153
180
|
${c.brand('/copiar')} copia a última resposta
|
|
154
181
|
${c.brand('/historico')} [termo] procura nos seus pedidos antigos
|
|
155
182
|
${c.brand('/rc')} abre a janela do PrimoCode (chat, sem terminal)
|
|
156
|
-
${c.brand('/ide')} abre a
|
|
183
|
+
${c.brand('/ide')} abre a janela com a prévia do site e os arquivos ao lado
|
|
157
184
|
${c.brand('/login')} entra na sua conta · ${c.brand('/account')} mostra o plano
|
|
158
185
|
${c.brand('/chats')} [n] suas conversas — as mesmas do app e do celular
|
|
159
186
|
${c.brand('/logout')} desconecta este computador da conta
|
|
@@ -210,7 +237,7 @@ const SLASH_COMANDOS = [
|
|
|
210
237
|
['/copiar', 'copia a última resposta'],
|
|
211
238
|
['/historico', 'procura nos seus pedidos antigos: /historico login'],
|
|
212
239
|
['/rc', 'abre a janela do PrimoCode'],
|
|
213
|
-
['/ide', 'abre a
|
|
240
|
+
['/ide', 'abre a janela com a prévia do site e os arquivos ao lado'],
|
|
214
241
|
['/login', 'entra na sua conta Conecta Primo'],
|
|
215
242
|
['/account', 'sua conta, plano e computadores conectados'],
|
|
216
243
|
['/chats', 'suas conversas salvas, as mesmas do app e do celular'],
|
|
@@ -2474,26 +2501,26 @@ async function handleSlash(text) {
|
|
|
2474
2501
|
break;
|
|
2475
2502
|
}
|
|
2476
2503
|
|
|
2477
|
-
/*
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2504
|
+
/* O /ide virou a MESMA janela do /rc, abrindo com a prévia do site
|
|
2505
|
+
à direita. O editor de código saiu ("remove a IDE ou deixa
|
|
2506
|
+
idêntico ao Codex"): quem não programa precisa ver o site
|
|
2507
|
+
nascendo, não de um editor para quebrar o que o agente fez. O
|
|
2508
|
+
comando continua existindo para o dedo viciado não bater em nada. */
|
|
2481
2509
|
case 'ide': {
|
|
2482
|
-
if (janelaAberta
|
|
2483
|
-
await appLib.abrirJanela(janelaAberta.
|
|
2484
|
-
console.log(c.ok('
|
|
2485
|
-
console.log(c.dim(` ${janelaAberta.urlIde}`));
|
|
2510
|
+
if (janelaAberta) {
|
|
2511
|
+
await appLib.abrirJanela(janelaAberta.urlPainel || janelaAberta.url);
|
|
2512
|
+
console.log(c.ok(' Janela com a prévia aberta.') + c.muted(' (no mesmo servidor que já estava de pé)'));
|
|
2486
2513
|
break;
|
|
2487
2514
|
}
|
|
2488
|
-
const sp = new Spinner('abrindo a
|
|
2515
|
+
const sp = new Spinner('abrindo a janela').start();
|
|
2489
2516
|
try {
|
|
2490
2517
|
janelaAberta = await appLib.abrir(opcoesDaJanela({ abrirEm: 'ide' }));
|
|
2491
2518
|
sp.stop();
|
|
2492
2519
|
const j = janelaAberta.janela || {};
|
|
2493
|
-
console.log(c.ok('
|
|
2520
|
+
console.log(c.ok(' Janela aberta, com a prévia do site ao lado.')
|
|
2494
2521
|
+ c.muted(j.modo === 'janela' ? ` (${j.navegador})`
|
|
2495
2522
|
: j.modo === 'aba' ? ' (aba do navegador padrão)' : ''));
|
|
2496
|
-
console.log(c.dim(` ${janelaAberta.
|
|
2523
|
+
console.log(c.dim(` ${janelaAberta.urlPainel}`));
|
|
2497
2524
|
if (j.modo === 'nenhum') {
|
|
2498
2525
|
console.log(c.warn(' Não consegui abrir sozinho — copie o endereço acima no navegador.'));
|
|
2499
2526
|
}
|
|
@@ -2819,7 +2846,7 @@ async function main() {
|
|
|
2819
2846
|
return;
|
|
2820
2847
|
}
|
|
2821
2848
|
|
|
2822
|
-
/* `primo ide`: o terminal de sempre, com a
|
|
2849
|
+
/* `primo ide`: o terminal de sempre, com a janela (e a prévia) já aberta.
|
|
2823
2850
|
Só a palavra SOZINHA: `primo ide para gatos` continua sendo um pedido
|
|
2824
2851
|
ao agente (modo um-tiro), como sempre foi. */
|
|
2825
2852
|
const abrirIde = args.length === 1 && args[0].toLowerCase() === 'ide';
|
|
@@ -2939,7 +2966,13 @@ async function main() {
|
|
|
2939
2966
|
try {
|
|
2940
2967
|
if (ehBash(text)) await rodarBash(text);
|
|
2941
2968
|
else if (isSlash(text)) await handleSlash(text);
|
|
2942
|
-
else
|
|
2969
|
+
else {
|
|
2970
|
+
// Com a janela aberta, o pedido digitado AQUI também vira
|
|
2971
|
+
// balão lá — senão a janela mostraria a resposta de uma
|
|
2972
|
+
// pergunta que ninguém fez.
|
|
2973
|
+
if (janelaAberta && janelaAberta.pedidoDoTerminal) janelaAberta.pedidoDoTerminal(text);
|
|
2974
|
+
await sendPrompt(text);
|
|
2975
|
+
}
|
|
2943
2976
|
} catch (e) {
|
|
2944
2977
|
fala.problema(e);
|
|
2945
2978
|
}
|
|
@@ -3004,7 +3037,7 @@ async function main() {
|
|
|
3004
3037
|
// O que sobrou de adiantado não era resposta de nada: vira comando,
|
|
3005
3038
|
// na ordem em que foi digitado. Nada se perde, só esperou a vez.
|
|
3006
3039
|
segurando = false;
|
|
3007
|
-
// Depois da abertura (e do login dela): a
|
|
3040
|
+
// Depois da abertura (e do login dela): a janela sem conta abriria
|
|
3008
3041
|
// mandando pedidos que o servidor recusa.
|
|
3009
3042
|
if (abrirIde) queue.push('/ide');
|
|
3010
3043
|
while (adiantadas.length) queue.push(adiantadas.shift());
|
package/lib/act.js
CHANGED
|
@@ -138,6 +138,9 @@ function limparParaOModelo(result) {
|
|
|
138
138
|
|
|
139
139
|
function logResult(kind, result, profundidade) {
|
|
140
140
|
const p = fala.resultado(profundidade);
|
|
141
|
+
// A linha da janela (lib/app.js) fecha aqui: o mesmo resultado que o
|
|
142
|
+
// terminal desenha embaixo, resumido. Ver o canal em lib/fala.js.
|
|
143
|
+
fala.avisar('resultado', fala.resumoDoResultado(kind, result));
|
|
141
144
|
if (!result) return;
|
|
142
145
|
// Uma tool que falhou é informação para o AGENTE, que vai consertar na
|
|
143
146
|
// volta seguinte — não é o erro do usuário. Âmbar, uma linha, sem o
|
|
@@ -1131,6 +1134,7 @@ async function runAct(userPrompt, opts) {
|
|
|
1131
1134
|
const porta = await permissao.pedir(portaoControle, tc.name, tc.arguments, autorizar);
|
|
1132
1135
|
if (!porta.ok) {
|
|
1133
1136
|
fala.acao(tc.name, tc.arguments, profundidade);
|
|
1137
|
+
fala.avisar('resultado', { nome: tc.name, ok: false, resumo: 'não autorizado' });
|
|
1134
1138
|
console.log(fala.resultado(profundidade) + c.warn('não autorizado'));
|
|
1135
1139
|
registro.anotar(livro, tc.name, tc.arguments, { ok: false, error: porta.error });
|
|
1136
1140
|
messages.push({ role: 'tool', tool_call_id: tc.id, content: JSON.stringify({ ok: false, error: porta.error }) });
|
|
@@ -1148,6 +1152,7 @@ async function runAct(userPrompt, opts) {
|
|
|
1148
1152
|
});
|
|
1149
1153
|
if (!risco.ok) {
|
|
1150
1154
|
fala.acao(tc.name, tc.arguments, profundidade);
|
|
1155
|
+
fala.avisar('resultado', { nome: tc.name, ok: false, resumo: `não autorizado — ${risco.motivo}` });
|
|
1151
1156
|
console.log(fala.resultado(profundidade) + c.warn(`não autorizado — ${risco.motivo}`));
|
|
1152
1157
|
registro.anotar(livro, tc.name, tc.arguments, { ok: false, error: risco.error });
|
|
1153
1158
|
messages.push({ role: 'tool', tool_call_id: tc.id, content: JSON.stringify({ ok: false, error: risco.error }) });
|