primocode 7.12.2 → 7.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/act.js +5 -0
- package/lib/streaming.js +173 -72
- package/package.json +1 -1
package/lib/act.js
CHANGED
|
@@ -185,6 +185,11 @@ async function runAct(userPrompt, opts) {
|
|
|
185
185
|
|
|
186
186
|
let finalText = '';
|
|
187
187
|
|
|
188
|
+
// O pedido do usuário aparece na barra de comando do painel, digitado
|
|
189
|
+
// letra a letra — só o pedido principal; sub-tarefa de agente não é
|
|
190
|
+
// instrução de gente.
|
|
191
|
+
if (!subagent) { try { painel.instrucao(userPrompt); } catch {} }
|
|
192
|
+
|
|
188
193
|
for (let iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
|
|
189
194
|
const sp = new Spinner(subagent ? 'subagente trabalhando' : 'Primo Code pensando').start();
|
|
190
195
|
|
package/lib/streaming.js
CHANGED
|
@@ -40,6 +40,7 @@ const state = {
|
|
|
40
40
|
abas: [], // [{ id, nome, passos: 0 }] — "Ao vivo" é virtual, não entra aqui
|
|
41
41
|
abaAtual: null,
|
|
42
42
|
log: [],
|
|
43
|
+
instrucoes: [], // o que o usuário pediu — a página autopreenche digitando
|
|
43
44
|
erroFoto: null,
|
|
44
45
|
ultimaFoto: 0,
|
|
45
46
|
passo: 0,
|
|
@@ -123,6 +124,22 @@ function entrarNaAba(nome) {
|
|
|
123
124
|
state.abaAtual = aba;
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
/**
|
|
128
|
+
* A instrução que o usuário acabou de dar. A página autopreenche na barra de
|
|
129
|
+
* comando, letra por letra, e marca o começo dela na linha do tempo.
|
|
130
|
+
*/
|
|
131
|
+
function instrucao(texto) {
|
|
132
|
+
if (!state.on) return;
|
|
133
|
+
const t = String(texto || '').trim();
|
|
134
|
+
if (!t) return;
|
|
135
|
+
state.instrucoes.push({ n: state.instrucoes.length + 1, hora: new Date().toTimeString().slice(0, 8), texto: corta(t, 300) });
|
|
136
|
+
if (state.instrucoes.length > 40) state.instrucoes.splice(0, state.instrucoes.length - 40);
|
|
137
|
+
|
|
138
|
+
state.passo++;
|
|
139
|
+
state.log.push({ n: state.passo, hora: new Date().toTimeString().slice(0, 8), tipo: 'instrucao', acao: corta(t, 160), ok: true, aba: null });
|
|
140
|
+
if (state.log.length > MAX_LOG) state.log.splice(0, state.log.length - MAX_LOG);
|
|
141
|
+
}
|
|
142
|
+
|
|
126
143
|
/**
|
|
127
144
|
* Chamada pelo loop do agente depois de CADA tool. Quando o streaming está
|
|
128
145
|
* desligado é um no-op — o caminho normal não paga nada por isto.
|
|
@@ -188,67 +205,106 @@ const MASCOTE_SVG = `<svg viewBox="0 0 9 3.6" aria-hidden="true">
|
|
|
188
205
|
<g fill="#0b1220"><rect x="3" y=".35" width=".8" height=".5" rx=".1"/><rect x="5.2" y=".35" width=".8" height=".5" rx=".1"/><rect x="3.9" y="1.25" width="1.2" height=".28" rx=".14"/></g>
|
|
189
206
|
</svg>`;
|
|
190
207
|
|
|
191
|
-
// A
|
|
192
|
-
// inclinado
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
//
|
|
208
|
+
// A tela finalizada, a partir do desenho do dono: fundo grafite, mascote
|
|
209
|
+
// inclinado, "Primocode" branco no alto; a janela de borda branca grossa com
|
|
210
|
+
// as três bolinhas e as abas separadas por "|"; e, novidade combinada, a
|
|
211
|
+
// BARRA DE COMANDO — a instrução que você deu no terminal aparece ali,
|
|
212
|
+
// autopreenchendo letra por letra, com cursor piscando, enquanto o agente
|
|
213
|
+
// executa. Abaixo da moldura, a linha do tempo: miniaturas para voltar em
|
|
214
|
+
// qualquer passo e a lista de ações, com cada pedido marcando onde começou.
|
|
215
|
+
const FAVICON = 'data:image/svg+xml,' + encodeURIComponent(
|
|
216
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 3.6">${MASCOTE_SVG.replace(/^<svg[^>]*>|<\/svg>$/g, '')}</svg>`,
|
|
217
|
+
);
|
|
218
|
+
|
|
197
219
|
const PAGINA = `<!doctype html>
|
|
198
220
|
<html lang="pt-BR"><head><meta charset="utf-8">
|
|
199
221
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
200
|
-
<title>
|
|
222
|
+
<title>Primocode · Ao vivo</title>
|
|
223
|
+
<link rel="icon" href="${FAVICON}">
|
|
201
224
|
<style>
|
|
202
225
|
* { box-sizing: border-box; margin: 0; }
|
|
203
|
-
|
|
226
|
+
::selection { background: rgba(255,255,255,.2); }
|
|
227
|
+
body {
|
|
228
|
+
background: radial-gradient(1200px 500px at 50% -100px, #2e2e2e 0%, #262626 55%, #1f1f1f 100%) fixed #262626;
|
|
229
|
+
color: #fff; font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
230
|
+
min-height: 100vh; display: flex; flex-direction: column; align-items: center; padding: 0 18px 34px;
|
|
231
|
+
}
|
|
204
232
|
|
|
205
|
-
/* Cabeçalho
|
|
206
|
-
#topo { position: relative; width: min(
|
|
207
|
-
#topo .mascote { position: absolute; left:
|
|
233
|
+
/* ── Cabeçalho ── */
|
|
234
|
+
#topo { position: relative; width: min(1120px, 100%); padding: 46px 0 28px; text-align: center; }
|
|
235
|
+
#topo .mascote { position: absolute; left: 4px; top: 28px; width: 100px; height: 42px; transform: rotate(-32deg); filter: drop-shadow(0 6px 14px rgba(34,211,238,.35)); animation: flutua 3.2s ease-in-out infinite alternate; }
|
|
236
|
+
@keyframes flutua { from { translate: 0 0 } to { translate: 0 5px } }
|
|
208
237
|
#topo .mascote svg { width: 100%; height: 100%; display: block; }
|
|
209
|
-
#topo h1 { font-size: clamp(
|
|
210
|
-
#topo .vivo { position: absolute; right:
|
|
211
|
-
.dot { width: 9px; height: 9px; border-radius: 50%; background: #46d160; animation: pulsa 1.4s infinite; }
|
|
212
|
-
@keyframes pulsa { 50% { opacity: .
|
|
213
|
-
|
|
214
|
-
/* A janela
|
|
215
|
-
#janela {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
#barra
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
#
|
|
238
|
+
#topo h1 { font-size: clamp(36px, 6vw, 60px); font-weight: 650; letter-spacing: .5px; text-shadow: 0 3px 22px rgba(0,0,0,.55); }
|
|
239
|
+
#topo .vivo { position: absolute; right: 2px; top: 50px; display: inline-flex; align-items: center; gap: 8px; color: #a9a9a9; font-size: 12.5px; background: #1c1c1cd9; border: 1px solid #363636; border-radius: 999px; padding: 6px 14px; }
|
|
240
|
+
.dot { width: 9px; height: 9px; border-radius: 50%; background: #46d160; box-shadow: 0 0 8px #46d16088; animation: pulsa 1.4s infinite; }
|
|
241
|
+
@keyframes pulsa { 50% { opacity: .3 } }
|
|
242
|
+
|
|
243
|
+
/* ── A janela ── */
|
|
244
|
+
#janela {
|
|
245
|
+
width: min(1120px, 100%); background: #000; border: 9px solid #f5f5f5; border-radius: 44px;
|
|
246
|
+
overflow: hidden; display: flex; flex-direction: column;
|
|
247
|
+
box-shadow: 0 34px 90px rgba(0,0,0,.65), 0 0 0 1px rgba(255,255,255,.06), 0 10px 34px rgba(0,0,0,.5);
|
|
248
|
+
}
|
|
249
|
+
#barra { position: relative; display: flex; align-items: center; background: linear-gradient(#262626, #212121); padding: 15px 28px; min-height: 60px; border-bottom: 1px solid #0c0c0c; }
|
|
250
|
+
#barra .b { flex: none; margin-right: 12px; box-shadow: inset 0 -2px 4px rgba(0,0,0,.35), 0 1px 2px rgba(0,0,0,.5); }
|
|
251
|
+
#barra .b.r { width: 17px; height: 17px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #ff5a5a, #d40000); }
|
|
252
|
+
#barra .b.y { width: 30px; height: 17px; border-radius: 999px; background: radial-gradient(circle at 35% 30%, #ffe95c, #f5c400); }
|
|
253
|
+
#barra .b.g { width: 24px; height: 14px; border-radius: 999px; background: radial-gradient(circle at 35% 30%, #6fe589, #24b53e); }
|
|
254
|
+
|
|
255
|
+
#abas { position: absolute; left: 50%; transform: translateX(-50%); max-width: 60%; display: flex; align-items: center; gap: 13px; overflow-x: auto; white-space: nowrap; scrollbar-width: none; font-size: clamp(15px, 2.2vw, 22px); font-weight: 550; }
|
|
224
256
|
#abas::-webkit-scrollbar { display: none; }
|
|
225
|
-
.aba { border: 0; background: none; cursor: pointer; font: inherit; color: rgba(255,255,255,.
|
|
226
|
-
.aba:hover { color: rgba(255,255,255,.
|
|
227
|
-
.aba.ativa { color: #fff; }
|
|
228
|
-
.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
#
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
#
|
|
239
|
-
|
|
257
|
+
.aba { border: 0; background: none; cursor: pointer; font: inherit; color: rgba(255,255,255,.45); padding: 3px 2px; transition: color .18s ease, text-shadow .18s ease; }
|
|
258
|
+
.aba:hover { color: rgba(255,255,255,.85); }
|
|
259
|
+
.aba.ativa { color: #fff; text-shadow: 0 0 16px rgba(255,255,255,.45); }
|
|
260
|
+
.aba .qtd { color: rgba(255,255,255,.35); font-size: .62em; vertical-align: super; margin-left: 4px; font-weight: 600; }
|
|
261
|
+
.sep { color: rgba(255,255,255,.28); font-weight: 300; }
|
|
262
|
+
|
|
263
|
+
/* ── Barra de comando: a instrução autopreenchendo ── */
|
|
264
|
+
#comando { display: flex; align-items: center; gap: 12px; background: #141414; border-bottom: 1px solid #0a0a0a; padding: 12px 26px; font-family: ui-monospace, 'Cascadia Code', Consolas, monospace; font-size: 14.5px; min-height: 46px; }
|
|
265
|
+
#comando .chevron { color: #46d160; font-weight: 700; flex: none; }
|
|
266
|
+
#comando .texto { color: #eaeaea; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
267
|
+
#comando .texto.vazio { color: #5c5c5c; font-style: italic; }
|
|
268
|
+
#comando .cursor { flex: none; width: 8px; height: 17px; background: #eaeaea; margin-left: 2px; animation: pisca 1s steps(1) infinite; }
|
|
269
|
+
@keyframes pisca { 50% { opacity: 0 } }
|
|
270
|
+
#comando .hora { margin-left: auto; color: #5c5c5c; font-size: 11.5px; flex: none; }
|
|
271
|
+
|
|
272
|
+
/* ── A tela ── */
|
|
273
|
+
#tela { position: relative; min-height: 460px; display: flex; align-items: center; justify-content: center; background: #000; }
|
|
274
|
+
#tela img { width: 100%; max-height: 62vh; object-fit: contain; display: none; opacity: 0; transition: opacity .28s ease; }
|
|
275
|
+
#aviso { color: #fff; text-align: center; padding: 90px 24px; }
|
|
276
|
+
#aviso .titulo { font-size: clamp(20px, 3.2vw, 32px); font-weight: 550; }
|
|
277
|
+
#aviso .sub { color: #8f8f8f; font-size: 14.5px; margin-top: 14px; line-height: 1.7; }
|
|
278
|
+
#carimbo { position: absolute; left: 18px; bottom: 14px; background: rgba(10,10,10,.72); backdrop-filter: blur(6px); border: 1px solid #2e2e2e; color: #c9c9c9; font-size: 12px; padding: 5px 13px; border-radius: 999px; display: none; max-width: 85%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
279
|
+
#carimbo b { color: #fff; font-weight: 600; }
|
|
280
|
+
|
|
281
|
+
/* ── Linha do tempo ── */
|
|
282
|
+
#historico { width: min(1120px, 100%); padding-top: 20px; }
|
|
283
|
+
#filme { display: flex; gap: 10px; padding: 4px 2px 14px; overflow-x: auto; scrollbar-width: thin; scrollbar-color: #3a3a3a transparent; }
|
|
284
|
+
.foto { flex: none; border: 1.5px solid #3a3a3a; border-radius: 10px; background: #000; cursor: pointer; padding: 0; width: 104px; height: 62px; overflow: hidden; opacity: .65; transition: transform .16s ease, opacity .16s ease, border-color .16s ease, box-shadow .16s ease; }
|
|
285
|
+
.foto:hover { opacity: 1; transform: translateY(-2px); border-color: #7a7a7a; }
|
|
240
286
|
.foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
241
|
-
.foto.ativa { border-color: #fff; opacity: 1; }
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
.item
|
|
287
|
+
.foto.ativa { border-color: #fff; opacity: 1; box-shadow: 0 0 0 2px rgba(255,255,255,.25), 0 6px 18px rgba(0,0,0,.45); }
|
|
288
|
+
|
|
289
|
+
#cartao { background: #1c1c1c; border: 1px solid #2c2c2c; border-radius: 18px; overflow: hidden; }
|
|
290
|
+
#cartao header { display: flex; align-items: center; justify-content: space-between; padding: 12px 18px; border-bottom: 1px solid #272727; color: #bdbdbd; font-size: 13px; font-weight: 600; letter-spacing: .3px; }
|
|
291
|
+
#cartao header span b { color: #fff; }
|
|
292
|
+
#passos { max-height: 240px; overflow-y: auto; padding: 6px 0 10px; scrollbar-width: thin; scrollbar-color: #3a3a3a transparent; }
|
|
293
|
+
#passos::-webkit-scrollbar { width: 8px; } #passos::-webkit-scrollbar-thumb { background: #3a3a3a; border-radius: 4px; }
|
|
294
|
+
.item { padding: 5px 18px; display: flex; gap: 10px; font-size: 13.5px; align-items: baseline; transition: background .12s ease; }
|
|
295
|
+
.item:hover { background: #222; }
|
|
296
|
+
.item .n { color: #6b6b6b; min-width: 3ch; text-align: right; font-variant-numeric: tabular-nums; }
|
|
297
|
+
.item .ok { color: #46d160; } .item .falha { color: #ff6b6b; }
|
|
298
|
+
.item .txt { flex: 1; word-break: break-word; color: #dcdcdc; }
|
|
299
|
+
.item .txt .erro { color: #ff8a8a; font-size: 12px; display: block; margin-top: 1px; }
|
|
300
|
+
.item .hora { color: #6b6b6b; font-size: 11px; font-variant-numeric: tabular-nums; }
|
|
249
301
|
.item.temfoto { cursor: pointer; } .item.temfoto:hover .txt { color: #fff; }
|
|
302
|
+
.item.pedido { background: #191919; border-top: 1px solid #262626; border-bottom: 1px solid #262626; margin: 6px 0; padding: 8px 18px; }
|
|
303
|
+
.item.pedido .txt { color: #fff; font-weight: 600; }
|
|
304
|
+
.item.pedido .chev { color: #46d160; font-weight: 800; }
|
|
250
305
|
|
|
251
|
-
footer { color: #
|
|
306
|
+
footer { color: #6b6b6b; font-size: 12px; padding-top: 18px; }
|
|
307
|
+
footer b { color: #9a9a9a; font-weight: 600; }
|
|
252
308
|
</style></head>
|
|
253
309
|
<body>
|
|
254
310
|
<div id="topo">
|
|
@@ -262,43 +318,76 @@ const PAGINA = `<!doctype html>
|
|
|
262
318
|
<span class="b r"></span><span class="b y"></span><span class="b g"></span>
|
|
263
319
|
<nav id="abas"></nav>
|
|
264
320
|
</div>
|
|
321
|
+
<div id="comando">
|
|
322
|
+
<span class="chevron">❯</span>
|
|
323
|
+
<span class="texto vazio" id="cmdtexto">aguardando a sua instrução no terminal…</span>
|
|
324
|
+
<span class="cursor"></span>
|
|
325
|
+
<span class="hora" id="cmdhora"></span>
|
|
326
|
+
</div>
|
|
265
327
|
<section id="tela">
|
|
266
328
|
<img id="frame" alt="tela que a IA está usando">
|
|
267
|
-
<div id="aviso">
|
|
329
|
+
<div id="aviso">
|
|
330
|
+
<div class="titulo">Tela que a IA está usando aparece aqui</div>
|
|
331
|
+
<div class="sub">Dê uma instrução no terminal do PrimoCode e veja cada passo, ao vivo.<br>Cada app em que ele mexer vira uma aba — volte nelas para rever o que já foi feito.</div>
|
|
332
|
+
</div>
|
|
268
333
|
<div id="carimbo"></div>
|
|
269
334
|
</section>
|
|
270
335
|
</div>
|
|
271
336
|
|
|
272
337
|
<div id="historico">
|
|
273
338
|
<div id="filme"></div>
|
|
274
|
-
<div id="
|
|
339
|
+
<div id="cartao">
|
|
340
|
+
<header><span>Linha do tempo · <b id="abanome">Ao vivo</b></span><span id="resumo"></span></header>
|
|
341
|
+
<div id="passos"></div>
|
|
342
|
+
</div>
|
|
275
343
|
</div>
|
|
276
|
-
<footer>só nesta máquina (127.0.0.1) ·
|
|
344
|
+
<footer>só nesta máquina <b>(127.0.0.1)</b> · <b>/streaming</b> desliga</footer>
|
|
277
345
|
|
|
278
346
|
<script>
|
|
279
347
|
const VIVO = 0; // id da aba "Ao vivo"
|
|
280
|
-
let dados = { abas: [], frames: [], log: [] };
|
|
348
|
+
let dados = { abas: [], frames: [], log: [], instrucoes: [] };
|
|
281
349
|
let abaSel = VIVO; // aba escolhida pelo usuário
|
|
282
350
|
let fotoSel = null; // frame fixado no filmstrip (null = mais recente)
|
|
283
351
|
let ultimoEstado = '';
|
|
284
352
|
|
|
353
|
+
// ── autopreencher a instrução, letra por letra ──
|
|
354
|
+
let digitando = null, instrucaoNaTela = 0;
|
|
355
|
+
function autopreencher(inst) {
|
|
356
|
+
if (!inst || inst.n === instrucaoNaTela) return;
|
|
357
|
+
instrucaoNaTela = inst.n;
|
|
358
|
+
clearInterval(digitando);
|
|
359
|
+
const el = document.getElementById('cmdtexto');
|
|
360
|
+
el.classList.remove('vazio');
|
|
361
|
+
el.textContent = '';
|
|
362
|
+
document.getElementById('cmdhora').textContent = inst.hora;
|
|
363
|
+
let i = 0;
|
|
364
|
+
digitando = setInterval(() => {
|
|
365
|
+
i += 1 + Math.floor(Math.random() * 2); // cadência de gente digitando
|
|
366
|
+
el.textContent = inst.texto.slice(0, i);
|
|
367
|
+
if (i >= inst.texto.length) clearInterval(digitando);
|
|
368
|
+
}, 34);
|
|
369
|
+
}
|
|
370
|
+
|
|
285
371
|
function esc(s) { return String(s ?? '').replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); }
|
|
286
372
|
|
|
287
373
|
function framesDaAba(id) {
|
|
288
374
|
return id === VIVO ? dados.frames : dados.frames.filter((f) => f.aba === id);
|
|
289
375
|
}
|
|
290
376
|
function logDaAba(id) {
|
|
291
|
-
return id === VIVO ? dados.log : dados.log.filter((e) => e.aba === id);
|
|
377
|
+
return id === VIVO ? dados.log : dados.log.filter((e) => e.aba === id || e.tipo === 'instrucao');
|
|
292
378
|
}
|
|
293
379
|
|
|
294
380
|
function render() {
|
|
295
|
-
// Abas: "Ao vivo" + uma por app/janela,
|
|
381
|
+
// Abas: "Ao vivo" + uma por app/janela, separadas por |
|
|
296
382
|
const nav = document.getElementById('abas');
|
|
297
383
|
const abas = [{ id: VIVO, nome: 'Ao vivo' }, ...dados.abas];
|
|
298
384
|
nav.innerHTML = abas.map((a) =>
|
|
299
|
-
'<button class="aba' + (a.id === abaSel ? ' ativa' : '') + '" data-id="' + a.id + '">' + esc(a.nome)
|
|
385
|
+
'<button class="aba' + (a.id === abaSel ? ' ativa' : '') + '" data-id="' + a.id + '">' + esc(a.nome)
|
|
386
|
+
+ (a.passos ? '<span class="qtd">' + a.passos + '</span>' : '') + '</button>'
|
|
300
387
|
).join('<span class="sep">|</span>');
|
|
301
388
|
nav.querySelectorAll('.aba').forEach((b) => b.onclick = () => { abaSel = Number(b.dataset.id); fotoSel = null; render(); });
|
|
389
|
+
const abaObj = abas.find((a) => a.id === abaSel) || abas[0];
|
|
390
|
+
document.getElementById('abanome').textContent = abaObj.nome;
|
|
302
391
|
|
|
303
392
|
// Imagem: a fixada no filmstrip, senão a mais nova da aba
|
|
304
393
|
const fs = framesDaAba(abaSel);
|
|
@@ -307,19 +396,23 @@ function render() {
|
|
|
307
396
|
const aviso = document.getElementById('aviso');
|
|
308
397
|
const carimbo = document.getElementById('carimbo');
|
|
309
398
|
if (atual) {
|
|
310
|
-
|
|
311
|
-
|
|
399
|
+
if (img.dataset.n !== String(atual.id)) {
|
|
400
|
+
img.style.opacity = '0';
|
|
401
|
+
img.onload = () => { img.style.opacity = '1'; };
|
|
402
|
+
img.src = '/frame?n=' + atual.id;
|
|
403
|
+
img.dataset.n = String(atual.id);
|
|
404
|
+
}
|
|
312
405
|
img.style.display = 'block'; aviso.style.display = 'none';
|
|
313
406
|
carimbo.style.display = 'block';
|
|
314
|
-
carimbo.
|
|
407
|
+
carimbo.innerHTML = '<b>#' + atual.id + '</b> · ' + atual.hora + ' · ' + esc(atual.acao) + (fotoSel != null ? ' — <b>clique na miniatura de novo para voltar ao ao-vivo</b>' : '');
|
|
315
408
|
} else {
|
|
316
409
|
img.style.display = 'none'; aviso.style.display = 'block'; carimbo.style.display = 'none';
|
|
317
|
-
if (dados.erroFoto) aviso.textContent = 'Sem foto da tela: ' + dados.erroFoto;
|
|
410
|
+
if (dados.erroFoto) aviso.querySelector('.sub').textContent = 'Sem foto da tela: ' + dados.erroFoto;
|
|
318
411
|
}
|
|
319
412
|
|
|
320
|
-
// Filmstrip da aba (as últimas
|
|
413
|
+
// Filmstrip da aba (as últimas 16)
|
|
321
414
|
const filme = document.getElementById('filme');
|
|
322
|
-
const tira = fs.slice(-
|
|
415
|
+
const tira = fs.slice(-16);
|
|
323
416
|
filme.innerHTML = tira.map((f) =>
|
|
324
417
|
'<button class="foto' + ((atual && f.id === atual.id) ? ' ativa' : '') + '" data-id="' + f.id + '" title="' + esc(f.acao) + '"><img loading="lazy" src="/frame?n=' + f.id + '"></button>').join('');
|
|
325
418
|
filme.querySelectorAll('.foto').forEach((b) => b.onclick = () => {
|
|
@@ -329,14 +422,20 @@ function render() {
|
|
|
329
422
|
});
|
|
330
423
|
if (fotoSel == null) filme.scrollLeft = filme.scrollWidth;
|
|
331
424
|
|
|
332
|
-
//
|
|
333
|
-
const passos = logDaAba(abaSel).slice(-
|
|
334
|
-
document.getElementById('
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
425
|
+
// Linha do tempo da aba (mais novos primeiro); pedidos viram divisórias
|
|
426
|
+
const passos = logDaAba(abaSel).slice(-60).reverse();
|
|
427
|
+
document.getElementById('resumo').textContent = passos.filter((e) => e.tipo !== 'instrucao').length + ' passos';
|
|
428
|
+
document.getElementById('passos').innerHTML = passos.map((e) => {
|
|
429
|
+
if (e.tipo === 'instrucao') {
|
|
430
|
+
return '<div class="item pedido"><span class="n">' + e.n + '</span><span class="chev">❯</span>'
|
|
431
|
+
+ '<span class="txt">' + esc(e.acao) + '</span><span class="hora">' + e.hora + '</span></div>';
|
|
432
|
+
}
|
|
433
|
+
return '<div class="item' + (e.frame ? ' temfoto" data-frame="' + e.frame : '') + '">'
|
|
434
|
+
+ '<span class="n">' + e.n + '</span>'
|
|
435
|
+
+ '<span class="' + (e.ok ? 'ok' : 'falha') + '">' + (e.ok ? '✔' : '✗') + '</span>'
|
|
436
|
+
+ '<span class="txt">' + esc(e.acao) + (e.erro ? '<span class="erro">' + esc(e.erro) + '</span>' : '') + '</span>'
|
|
437
|
+
+ '<span class="hora">' + e.hora + '</span></div>';
|
|
438
|
+
}).join('');
|
|
340
439
|
document.querySelectorAll('.item.temfoto').forEach((el) => el.onclick = () => { fotoSel = Number(el.dataset.frame); render(); });
|
|
341
440
|
}
|
|
342
441
|
|
|
@@ -345,6 +444,7 @@ async function tick() {
|
|
|
345
444
|
const s = await (await fetch('/state')).json();
|
|
346
445
|
dados = s;
|
|
347
446
|
document.getElementById('st').textContent = 'ao vivo';
|
|
447
|
+
autopreencher(s.instrucoes[s.instrucoes.length - 1]);
|
|
348
448
|
const assinatura = JSON.stringify([s.frames.length, s.log.length, s.abas.length, s.erroFoto]);
|
|
349
449
|
if (assinatura !== ultimoEstado) { ultimoEstado = assinatura; render(); }
|
|
350
450
|
} catch (e) {
|
|
@@ -373,6 +473,7 @@ function start() {
|
|
|
373
473
|
abas: state.abas,
|
|
374
474
|
frames: state.frames,
|
|
375
475
|
log: state.log.slice(-120),
|
|
476
|
+
instrucoes: state.instrucoes.slice(-20),
|
|
376
477
|
}));
|
|
377
478
|
return;
|
|
378
479
|
}
|
|
@@ -416,4 +517,4 @@ function stop() {
|
|
|
416
517
|
state.url = '';
|
|
417
518
|
}
|
|
418
519
|
|
|
419
|
-
module.exports = { start, stop, step, isOn, url, descrever };
|
|
520
|
+
module.exports = { start, stop, step, instrucao, isOn, url, descrever };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primocode",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.13.0",
|
|
4
4
|
"description": "PrimoCode — agente de engenharia com IA e cursor próprio. Modelos grátis. 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": {
|