primocode 7.17.0 → 7.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/primocode.js +138 -30
- package/package.json +1 -1
package/bin/primocode.js
CHANGED
|
@@ -119,12 +119,11 @@ function completarSlash(line) {
|
|
|
119
119
|
// Régua com os níveis, o marcador ▲ embaixo do escolhido, "Faster" à
|
|
120
120
|
// esquerda e "Smarter" à direita. ←/→ move, Enter confirma, Esc cancela.
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
// O layout sai em texto PLANO, com as marcas de onde pintar. Assim os dois
|
|
123
|
+
// pintores (o normal e o do ultracode animado) desenham exatamente a mesma
|
|
124
|
+
// régua — sem duas contas de posição para manter em sincronia.
|
|
125
|
+
function layoutEffort(idx) {
|
|
123
126
|
const cols = Math.max(52, Math.min(process.stdout.columns || 100, 104));
|
|
124
|
-
const regua = '▔'.repeat(cols);
|
|
125
|
-
const linhas = [];
|
|
126
|
-
|
|
127
|
-
// Cada nível ocupa uma coluna própria; o ultracode fica destacado no fim.
|
|
128
127
|
const rotulos = effort.NOMES;
|
|
129
128
|
const larguras = rotulos.map((n) => Math.max(n.length + 3, 9));
|
|
130
129
|
const posicoes = [];
|
|
@@ -134,38 +133,130 @@ function desenharEffort(idx) {
|
|
|
134
133
|
x += larguras[i];
|
|
135
134
|
}
|
|
136
135
|
const fimRegua = x;
|
|
137
|
-
|
|
138
|
-
linhas.push(c.dim(regua));
|
|
139
|
-
linhas.push(' ' + c.bold(c.white('Effort')));
|
|
140
|
-
linhas.push('');
|
|
141
|
-
|
|
142
|
-
// Faster ....▲.... Smarter — a trilha, com o marcador na posição atual.
|
|
143
136
|
const marca = posicoes[idx];
|
|
137
|
+
|
|
144
138
|
let trilha = '';
|
|
145
139
|
for (let k = 23; k < fimRegua; k++) {
|
|
146
|
-
if (k === marca) trilha +=
|
|
147
|
-
else if (k === fimRegua - 12) trilha +=
|
|
148
|
-
else trilha +=
|
|
140
|
+
if (k === marca) trilha += '▲';
|
|
141
|
+
else if (k === fimRegua - 12) trilha += '┆'; // ultracode é um degrau à parte
|
|
142
|
+
else trilha += '─';
|
|
149
143
|
}
|
|
150
|
-
linhas.push(' ' + c.muted('Faster') + ' '.repeat(Math.max(1, fimRegua - 23 - 6 - 7)) + c.muted('Smarter'));
|
|
151
|
-
linhas.push(' ' + trilha);
|
|
152
144
|
|
|
153
|
-
|
|
154
|
-
let
|
|
145
|
+
let nomes = ' '.repeat(23);
|
|
146
|
+
let deNome = 0, ateNome = 0;
|
|
155
147
|
for (let i = 0; i < rotulos.length; i++) {
|
|
156
148
|
const nome = rotulos[i];
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
linhaNomes += ' '.repeat(pad) + texto + ' '.repeat(espaco - nome.length - pad);
|
|
149
|
+
const pad = Math.floor((larguras[i] - nome.length) / 2);
|
|
150
|
+
if (i === idx) { deNome = nomes.length + pad; ateNome = deNome + nome.length; }
|
|
151
|
+
nomes += ' '.repeat(pad) + nome + ' '.repeat(larguras[i] - nome.length - pad);
|
|
161
152
|
}
|
|
162
|
-
linhas.push(linhaNomes);
|
|
163
153
|
|
|
164
154
|
const nivel = effort.nivelDe(rotulos[idx]);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
155
|
+
const vaoExtremos = Math.max(1, fimRegua - 23 - 6 - 7);
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
cols,
|
|
159
|
+
marca,
|
|
160
|
+
destaque: { de: deNome, ate: ateNome },
|
|
161
|
+
linhas: [
|
|
162
|
+
{ tipo: 'regua', texto: '▔'.repeat(cols) },
|
|
163
|
+
{ tipo: 'titulo', texto: ' Effort' },
|
|
164
|
+
{ tipo: 'vazio', texto: '' },
|
|
165
|
+
{ tipo: 'extremos', texto: ' '.repeat(23) + 'Faster' + ' '.repeat(vaoExtremos) + 'Smarter' },
|
|
166
|
+
{ tipo: 'trilha', texto: ' '.repeat(23) + trilha },
|
|
167
|
+
{ tipo: 'nomes', texto: nomes },
|
|
168
|
+
{ tipo: 'resumo', texto: ' '.repeat(23) + nivel.resumo },
|
|
169
|
+
{ tipo: 'vazio', texto: '' },
|
|
170
|
+
{ tipo: 'ajuda', texto: ' ←/→ ajusta · Enter confirma · Esc cancela' },
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ── O brilho do ultracode ────────────────────────────────────────────────
|
|
176
|
+
// No nível máximo o painel inteiro ganha um fundo roxo que ondula, como no
|
|
177
|
+
// Claude Code. São faixas verticais de roxo em brilhos diferentes; a onda
|
|
178
|
+
// anda para o lado a cada quadro, e o texto fica branco por cima.
|
|
179
|
+
//
|
|
180
|
+
// Roxos do cubo de 256 cores, ordenados pelo brilho REAL (luminância), do
|
|
181
|
+
// mais escuro ao mais claro — a onda escolhe um deles por faixa. Fora da
|
|
182
|
+
// lista ficaram os roxos escuros que puxam para o vinho (53-56): quebravam a
|
|
183
|
+
// família violeta. Só 256 cores (não truecolor): funciona em qualquer
|
|
184
|
+
// terminal, inclusive no Terminal.app do macOS.
|
|
185
|
+
const ROXOS = [57, 92, 93, 63, 98, 99, 105, 141];
|
|
186
|
+
|
|
187
|
+
function fundoRoxo(x, fase) {
|
|
188
|
+
// Duas ondas de períodos diferentes: o encontro delas dá o desenho
|
|
189
|
+
// irregular de faixas, em vez de listras repetidas e óbvias.
|
|
190
|
+
const faixa = Math.floor(x / 2);
|
|
191
|
+
const onda = Math.sin(faixa * 0.55 + fase) * 0.6 + Math.sin(faixa * 0.17 - fase * 0.7) * 0.4;
|
|
192
|
+
const i = Math.round((onda + 1) / 2 * (ROXOS.length - 1));
|
|
193
|
+
return ROXOS[Math.max(0, Math.min(ROXOS.length - 1, i))];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Pinta a linha inteira (até a largura do painel) com a onda por baixo.
|
|
197
|
+
// `destaque` é o trecho que fica branco e forte (o nível escolhido); o resto
|
|
198
|
+
// da linha sai num lilás claro, para o escolhido saltar aos olhos.
|
|
199
|
+
function pintarLinhaUltra(texto, largura, fase, opts = {}) {
|
|
200
|
+
const base = opts.base || 231; // branco
|
|
201
|
+
const apagado = opts.apagado || base;
|
|
202
|
+
const destaque = opts.destaque;
|
|
203
|
+
let saida = '';
|
|
204
|
+
let corFundo = -1;
|
|
205
|
+
let corTexto = -1;
|
|
206
|
+
let forte = null;
|
|
207
|
+
|
|
208
|
+
for (let x = 0; x < largura; x++) {
|
|
209
|
+
const fundo = fundoRoxo(x, fase);
|
|
210
|
+
if (fundo !== corFundo) { saida += `\x1b[48;5;${fundo}m`; corFundo = fundo; }
|
|
211
|
+
|
|
212
|
+
const dentro = destaque && x >= destaque.de && x < destaque.ate;
|
|
213
|
+
const querForte = opts.negrito || dentro;
|
|
214
|
+
const querCor = dentro ? base : apagado;
|
|
215
|
+
if (querForte !== forte) { saida += querForte ? '\x1b[1m' : '\x1b[22m'; forte = querForte; }
|
|
216
|
+
if (querCor !== corTexto) { saida += `\x1b[38;5;${querCor}m`; corTexto = querCor; }
|
|
217
|
+
|
|
218
|
+
saida += texto[x] || ' ';
|
|
219
|
+
}
|
|
220
|
+
return saida + '\x1b[0m';
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function desenharEffort(idx, fase) {
|
|
224
|
+
const L = layoutEffort(idx);
|
|
225
|
+
const ultra = effort.NOMES[idx] === 'ultracode';
|
|
226
|
+
|
|
227
|
+
if (ultra) {
|
|
228
|
+
// No ultracode o painel todo vira fundo animado. Cada linha é pintada
|
|
229
|
+
// com a MESMA onda, então as faixas ficam alinhadas de cima a baixo.
|
|
230
|
+
const LILAS = 189; // lilás bem claro, para o que não é o escolhido
|
|
231
|
+
return L.linhas.map((l) => {
|
|
232
|
+
if (l.tipo === 'titulo') return pintarLinhaUltra(l.texto, L.cols, fase, { negrito: true });
|
|
233
|
+
if (l.tipo === 'nomes') return pintarLinhaUltra(l.texto, L.cols, fase, { destaque: L.destaque, apagado: LILAS });
|
|
234
|
+
if (l.tipo === 'resumo' || l.tipo === 'extremos') return pintarLinhaUltra(l.texto, L.cols, fase, { base: LILAS, apagado: LILAS });
|
|
235
|
+
return pintarLinhaUltra(l.texto, L.cols, fase, {});
|
|
236
|
+
}).join('\n');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return L.linhas.map((l) => {
|
|
240
|
+
const t = l.texto;
|
|
241
|
+
switch (l.tipo) {
|
|
242
|
+
case 'regua': return c.dim(t);
|
|
243
|
+
case 'titulo': return c.bold(c.white(t));
|
|
244
|
+
case 'extremos': return c.muted(t);
|
|
245
|
+
case 'trilha': {
|
|
246
|
+
// O marcador aceso, o resto da trilha recuada.
|
|
247
|
+
const antes = t.slice(0, L.marca);
|
|
248
|
+
const depois = t.slice(L.marca + 1);
|
|
249
|
+
return c.dim(antes) + c.brand('▲') + c.dim(depois);
|
|
250
|
+
}
|
|
251
|
+
case 'nomes': {
|
|
252
|
+
const { de, ate } = L.destaque;
|
|
253
|
+
return c.muted(t.slice(0, de)) + c.bold(c.brand(t.slice(de, ate))) + c.muted(t.slice(ate));
|
|
254
|
+
}
|
|
255
|
+
case 'resumo': return c.dim(t);
|
|
256
|
+
case 'ajuda': return c.muted(t);
|
|
257
|
+
default: return t;
|
|
258
|
+
}
|
|
259
|
+
}).join('\n');
|
|
169
260
|
}
|
|
170
261
|
|
|
171
262
|
// Desenha, escuta as setas, e devolve o nome escolhido (ou null se cancelou).
|
|
@@ -177,21 +268,38 @@ function sliderEffort(atual) {
|
|
|
177
268
|
}
|
|
178
269
|
let idx = effort.indiceDe(atual);
|
|
179
270
|
const ALTURA = 9; // linhas que o desenho ocupa — para redesenhar por cima
|
|
271
|
+
let fase = 0;
|
|
272
|
+
let anima = null;
|
|
180
273
|
|
|
181
274
|
const pintar = (primeira) => {
|
|
182
275
|
if (!primeira) process.stdout.write(`\x1b[${ALTURA}A\r`);
|
|
183
|
-
process.stdout.write(desenharEffort(idx).split('\n').map((l) => '\x1b[2K' + l).join('\n') + '\n');
|
|
276
|
+
process.stdout.write(desenharEffort(idx, fase).split('\n').map((l) => '\x1b[2K' + l).join('\n') + '\n');
|
|
184
277
|
};
|
|
278
|
+
|
|
279
|
+
// O fundo do ultracode ondula; sair dele apaga a animação na hora, para
|
|
280
|
+
// não redesenhar sozinho um painel que já está parado.
|
|
281
|
+
const cuidarDaAnimacao = () => {
|
|
282
|
+
const ultra = effort.NOMES[idx] === 'ultracode';
|
|
283
|
+
if (ultra && !anima) {
|
|
284
|
+
anima = setInterval(() => { fase += 0.32; pintar(false); }, 90);
|
|
285
|
+
anima.unref();
|
|
286
|
+
} else if (!ultra && anima) {
|
|
287
|
+
clearInterval(anima); anima = null;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
185
291
|
pintar(true);
|
|
292
|
+
cuidarDaAnimacao();
|
|
186
293
|
|
|
187
294
|
const aoTeclar = (ch, key) => {
|
|
188
295
|
if (!key) return;
|
|
189
|
-
if (key.name === 'right' || key.name === 'l') { idx = Math.min(effort.NOMES.length - 1, idx + 1); pintar(false); return; }
|
|
190
|
-
if (key.name === 'left' || key.name === 'h') { idx = Math.max(0, idx - 1); pintar(false); return; }
|
|
296
|
+
if (key.name === 'right' || key.name === 'l') { idx = Math.min(effort.NOMES.length - 1, idx + 1); cuidarDaAnimacao(); pintar(false); return; }
|
|
297
|
+
if (key.name === 'left' || key.name === 'h') { idx = Math.max(0, idx - 1); cuidarDaAnimacao(); pintar(false); return; }
|
|
191
298
|
if (key.name === 'return' || key.name === 'enter') { encerrar(effort.NOMES[idx]); return; }
|
|
192
299
|
if (key.name === 'escape' || (key.ctrl && key.name === 'c')) { encerrar(null); return; }
|
|
193
300
|
};
|
|
194
301
|
const encerrar = (valor) => {
|
|
302
|
+
if (anima) { clearInterval(anima); anima = null; }
|
|
195
303
|
process.stdin.removeListener('keypress', aoTeclar);
|
|
196
304
|
sliderAtivo = false;
|
|
197
305
|
resolve(valor);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primocode",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.18.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": {
|