primocode 8.15.0 → 8.16.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 +1 -137
- package/lib/effort.js +178 -1
- package/package.json +1 -1
package/bin/primocode.js
CHANGED
|
@@ -142,142 +142,6 @@ function completarSlash(line) {
|
|
|
142
142
|
// O layout sai em texto PLANO, com as marcas de onde pintar. Assim os dois
|
|
143
143
|
// pintores (o normal e o do ultracode animado) desenham exatamente a mesma
|
|
144
144
|
// régua — sem duas contas de posição para manter em sincronia.
|
|
145
|
-
function layoutEffort(idx) {
|
|
146
|
-
const cols = Math.max(52, Math.min(process.stdout.columns || 100, 104));
|
|
147
|
-
const rotulos = effort.NOMES;
|
|
148
|
-
const larguras = rotulos.map((n) => Math.max(n.length + 3, 9));
|
|
149
|
-
const posicoes = [];
|
|
150
|
-
let x = 23; // recuo da régua, igual ao do mockup
|
|
151
|
-
for (let i = 0; i < rotulos.length; i++) {
|
|
152
|
-
posicoes.push(x + Math.floor(larguras[i] / 2));
|
|
153
|
-
x += larguras[i];
|
|
154
|
-
}
|
|
155
|
-
const fimRegua = x;
|
|
156
|
-
const marca = posicoes[idx];
|
|
157
|
-
|
|
158
|
-
let trilha = '';
|
|
159
|
-
for (let k = 23; k < fimRegua; k++) {
|
|
160
|
-
if (k === marca) trilha += '▲';
|
|
161
|
-
else if (k === fimRegua - 12) trilha += '┆'; // ultracode é um degrau à parte
|
|
162
|
-
else trilha += '─';
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
let nomes = ' '.repeat(23);
|
|
166
|
-
let deNome = 0, ateNome = 0;
|
|
167
|
-
for (let i = 0; i < rotulos.length; i++) {
|
|
168
|
-
const nome = rotulos[i];
|
|
169
|
-
const pad = Math.floor((larguras[i] - nome.length) / 2);
|
|
170
|
-
if (i === idx) { deNome = nomes.length + pad; ateNome = deNome + nome.length; }
|
|
171
|
-
nomes += ' '.repeat(pad) + nome + ' '.repeat(larguras[i] - nome.length - pad);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const nivel = effort.nivelDe(rotulos[idx]);
|
|
175
|
-
const vaoExtremos = Math.max(1, fimRegua - 23 - 6 - 7);
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
cols,
|
|
179
|
-
marca,
|
|
180
|
-
destaque: { de: deNome, ate: ateNome },
|
|
181
|
-
linhas: [
|
|
182
|
-
{ tipo: 'regua', texto: '▔'.repeat(cols) },
|
|
183
|
-
{ tipo: 'titulo', texto: ' Effort' },
|
|
184
|
-
{ tipo: 'vazio', texto: '' },
|
|
185
|
-
{ tipo: 'extremos', texto: ' '.repeat(23) + 'Faster' + ' '.repeat(vaoExtremos) + 'Smarter' },
|
|
186
|
-
{ tipo: 'trilha', texto: ' '.repeat(23) + trilha },
|
|
187
|
-
{ tipo: 'nomes', texto: nomes },
|
|
188
|
-
{ tipo: 'resumo', texto: ' '.repeat(23) + nivel.resumo },
|
|
189
|
-
{ tipo: 'vazio', texto: '' },
|
|
190
|
-
{ tipo: 'ajuda', texto: ' ←/→ ajusta · Enter confirma · Esc cancela' },
|
|
191
|
-
],
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// ── O brilho do ultracode ────────────────────────────────────────────────
|
|
196
|
-
// No nível máximo o painel inteiro ganha um fundo roxo que ondula, como no
|
|
197
|
-
// Claude Code. São faixas verticais de roxo em brilhos diferentes; a onda
|
|
198
|
-
// anda para o lado a cada quadro, e o texto fica branco por cima.
|
|
199
|
-
//
|
|
200
|
-
// Roxos do cubo de 256 cores, ordenados pelo brilho REAL (luminância), do
|
|
201
|
-
// mais escuro ao mais claro — a onda escolhe um deles por faixa. Fora da
|
|
202
|
-
// lista ficaram os roxos escuros que puxam para o vinho (53-56): quebravam a
|
|
203
|
-
// família violeta. Só 256 cores (não truecolor): funciona em qualquer
|
|
204
|
-
// terminal, inclusive no Terminal.app do macOS.
|
|
205
|
-
const ROXOS = [57, 92, 93, 63, 98, 99, 105, 141];
|
|
206
|
-
|
|
207
|
-
function fundoRoxo(x, fase) {
|
|
208
|
-
// Duas ondas de períodos diferentes: o encontro delas dá o desenho
|
|
209
|
-
// irregular de faixas, em vez de listras repetidas e óbvias.
|
|
210
|
-
const faixa = Math.floor(x / 2);
|
|
211
|
-
const onda = Math.sin(faixa * 0.55 + fase) * 0.6 + Math.sin(faixa * 0.17 - fase * 0.7) * 0.4;
|
|
212
|
-
const i = Math.round((onda + 1) / 2 * (ROXOS.length - 1));
|
|
213
|
-
return ROXOS[Math.max(0, Math.min(ROXOS.length - 1, i))];
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Pinta a linha inteira (até a largura do painel) com a onda por baixo.
|
|
217
|
-
// `destaque` é o trecho que fica branco e forte (o nível escolhido); o resto
|
|
218
|
-
// da linha sai num lilás claro, para o escolhido saltar aos olhos.
|
|
219
|
-
function pintarLinhaUltra(texto, largura, fase, opts = {}) {
|
|
220
|
-
const base = opts.base || 231; // branco
|
|
221
|
-
const apagado = opts.apagado || base;
|
|
222
|
-
const destaque = opts.destaque;
|
|
223
|
-
let saida = '';
|
|
224
|
-
let corFundo = -1;
|
|
225
|
-
let corTexto = -1;
|
|
226
|
-
let forte = null;
|
|
227
|
-
|
|
228
|
-
for (let x = 0; x < largura; x++) {
|
|
229
|
-
const fundo = fundoRoxo(x, fase);
|
|
230
|
-
if (fundo !== corFundo) { saida += `\x1b[48;5;${fundo}m`; corFundo = fundo; }
|
|
231
|
-
|
|
232
|
-
const dentro = destaque && x >= destaque.de && x < destaque.ate;
|
|
233
|
-
const querForte = opts.negrito || dentro;
|
|
234
|
-
const querCor = dentro ? base : apagado;
|
|
235
|
-
if (querForte !== forte) { saida += querForte ? '\x1b[1m' : '\x1b[22m'; forte = querForte; }
|
|
236
|
-
if (querCor !== corTexto) { saida += `\x1b[38;5;${querCor}m`; corTexto = querCor; }
|
|
237
|
-
|
|
238
|
-
saida += texto[x] || ' ';
|
|
239
|
-
}
|
|
240
|
-
return saida + '\x1b[0m';
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function desenharEffort(idx, fase) {
|
|
244
|
-
const L = layoutEffort(idx);
|
|
245
|
-
const ultra = effort.NOMES[idx] === 'ultracode';
|
|
246
|
-
|
|
247
|
-
if (ultra) {
|
|
248
|
-
// No ultracode o painel todo vira fundo animado. Cada linha é pintada
|
|
249
|
-
// com a MESMA onda, então as faixas ficam alinhadas de cima a baixo.
|
|
250
|
-
const LILAS = 189; // lilás bem claro, para o que não é o escolhido
|
|
251
|
-
return L.linhas.map((l) => {
|
|
252
|
-
if (l.tipo === 'titulo') return pintarLinhaUltra(l.texto, L.cols, fase, { negrito: true });
|
|
253
|
-
if (l.tipo === 'nomes') return pintarLinhaUltra(l.texto, L.cols, fase, { destaque: L.destaque, apagado: LILAS });
|
|
254
|
-
if (l.tipo === 'resumo' || l.tipo === 'extremos') return pintarLinhaUltra(l.texto, L.cols, fase, { base: LILAS, apagado: LILAS });
|
|
255
|
-
return pintarLinhaUltra(l.texto, L.cols, fase, {});
|
|
256
|
-
}).join('\n');
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return L.linhas.map((l) => {
|
|
260
|
-
const t = l.texto;
|
|
261
|
-
switch (l.tipo) {
|
|
262
|
-
case 'regua': return c.dim(t);
|
|
263
|
-
case 'titulo': return c.bold(c.white(t));
|
|
264
|
-
case 'extremos': return c.muted(t);
|
|
265
|
-
case 'trilha': {
|
|
266
|
-
// O marcador aceso, o resto da trilha recuada.
|
|
267
|
-
const antes = t.slice(0, L.marca);
|
|
268
|
-
const depois = t.slice(L.marca + 1);
|
|
269
|
-
return c.dim(antes) + c.brand('▲') + c.dim(depois);
|
|
270
|
-
}
|
|
271
|
-
case 'nomes': {
|
|
272
|
-
const { de, ate } = L.destaque;
|
|
273
|
-
return c.muted(t.slice(0, de)) + c.bold(c.brand(t.slice(de, ate))) + c.muted(t.slice(ate));
|
|
274
|
-
}
|
|
275
|
-
case 'resumo': return c.dim(t);
|
|
276
|
-
case 'ajuda': return c.muted(t);
|
|
277
|
-
default: return t;
|
|
278
|
-
}
|
|
279
|
-
}).join('\n');
|
|
280
|
-
}
|
|
281
145
|
|
|
282
146
|
// Desenha, escuta as setas, e devolve o nome escolhido (ou null se cancelou).
|
|
283
147
|
function sliderEffort(atual) {
|
|
@@ -293,7 +157,7 @@ function sliderEffort(atual) {
|
|
|
293
157
|
|
|
294
158
|
const pintar = (primeira) => {
|
|
295
159
|
if (!primeira) process.stdout.write(`\x1b[${ALTURA}A\r`);
|
|
296
|
-
process.stdout.write(desenharEffort(idx, fase).split('\n').map((l) => '\x1b[2K' + l).join('\n') + '\n');
|
|
160
|
+
process.stdout.write(effort.desenharEffort(idx, fase).split('\n').map((l) => '\x1b[2K' + l).join('\n') + '\n');
|
|
297
161
|
};
|
|
298
162
|
|
|
299
163
|
// O fundo do ultracode ondula; sair dele apaga a animação na hora, para
|
package/lib/effort.js
CHANGED
|
@@ -48,4 +48,181 @@ function pesquisaDe(nome) {
|
|
|
48
48
|
return nivelDe(nome).pesquisa;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
const { c } = require('./ui.js');
|
|
53
|
+
|
|
54
|
+
/* ═══════════════════════════════════════════════════════════════════════
|
|
55
|
+
O painel do /effort — e o fundo que ondula no ultracode.
|
|
56
|
+
|
|
57
|
+
Isto morava dentro do bin/, junto com o loop do programa. Lá não dava
|
|
58
|
+
para desenhar um quadro e OLHAR: o bin sobe o CLI inteiro quando é
|
|
59
|
+
carregado. Aqui é função pura — recebe o índice e a fase, devolve texto
|
|
60
|
+
com cor. Dá para renderizar quadro a quadro num teste, que é como a
|
|
61
|
+
animação foi conferida.
|
|
62
|
+
═══════════════════════════════════════════════════════════════════════ */
|
|
63
|
+
|
|
64
|
+
function layoutEffort(idx) {
|
|
65
|
+
// Sem teto de largura: o fundo do ultracode preenche o terminal inteiro.
|
|
66
|
+
// Travado em 104 colunas, o painel parava no meio de uma tela larga e o
|
|
67
|
+
// bloco roxo ficava com um degrau escuro do lado — parecia recorte, não
|
|
68
|
+
// fundo. A régua e os rótulos continuam no mesmo lugar; só o pano cresce.
|
|
69
|
+
const cols = Math.max(52, process.stdout.columns || 100);
|
|
70
|
+
const rotulos = NOMES;
|
|
71
|
+
const larguras = rotulos.map((n) => Math.max(n.length + 3, 9));
|
|
72
|
+
const posicoes = [];
|
|
73
|
+
let x = 23; // recuo da régua, igual ao do mockup
|
|
74
|
+
for (let i = 0; i < rotulos.length; i++) {
|
|
75
|
+
posicoes.push(x + Math.floor(larguras[i] / 2));
|
|
76
|
+
x += larguras[i];
|
|
77
|
+
}
|
|
78
|
+
const fimRegua = x;
|
|
79
|
+
const marca = posicoes[idx];
|
|
80
|
+
|
|
81
|
+
let trilha = '';
|
|
82
|
+
for (let k = 23; k < fimRegua; k++) {
|
|
83
|
+
if (k === marca) trilha += '▲';
|
|
84
|
+
else if (k === fimRegua - 12) trilha += '┆'; // ultracode é um degrau à parte
|
|
85
|
+
else trilha += '─';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let nomes = ' '.repeat(23);
|
|
89
|
+
let deNome = 0, ateNome = 0;
|
|
90
|
+
for (let i = 0; i < rotulos.length; i++) {
|
|
91
|
+
const nome = rotulos[i];
|
|
92
|
+
const pad = Math.floor((larguras[i] - nome.length) / 2);
|
|
93
|
+
if (i === idx) { deNome = nomes.length + pad; ateNome = deNome + nome.length; }
|
|
94
|
+
nomes += ' '.repeat(pad) + nome + ' '.repeat(larguras[i] - nome.length - pad);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const nivel = nivelDe(rotulos[idx]);
|
|
98
|
+
const vaoExtremos = Math.max(1, fimRegua - 23 - 6 - 7);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
cols,
|
|
102
|
+
marca,
|
|
103
|
+
destaque: { de: deNome, ate: ateNome },
|
|
104
|
+
linhas: [
|
|
105
|
+
{ tipo: 'regua', texto: '▔'.repeat(cols) },
|
|
106
|
+
{ tipo: 'titulo', texto: ' Effort' },
|
|
107
|
+
{ tipo: 'vazio', texto: '' },
|
|
108
|
+
{ tipo: 'extremos', texto: ' '.repeat(23) + 'Faster' + ' '.repeat(vaoExtremos) + 'Smarter' },
|
|
109
|
+
{ tipo: 'trilha', texto: ' '.repeat(23) + trilha },
|
|
110
|
+
{ tipo: 'nomes', texto: nomes },
|
|
111
|
+
{ tipo: 'resumo', texto: ' '.repeat(23) + nivel.resumo },
|
|
112
|
+
{ tipo: 'vazio', texto: '' },
|
|
113
|
+
{ tipo: 'ajuda', texto: ' ←/→ ajusta · Enter confirma · Esc cancela' },
|
|
114
|
+
],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── O brilho do ultracode ────────────────────────────────────────────────
|
|
119
|
+
// No nível máximo o painel inteiro ganha um fundo roxo que ondula, como no
|
|
120
|
+
// Claude Code. São faixas verticais de roxo em brilhos diferentes; a onda
|
|
121
|
+
// anda para o lado a cada quadro, e o texto fica branco por cima.
|
|
122
|
+
//
|
|
123
|
+
// Roxos do cubo de 256 cores, ordenados pelo brilho REAL (luminância), do
|
|
124
|
+
// mais escuro ao mais claro — a onda escolhe um deles por faixa. Fora da
|
|
125
|
+
// lista ficaram os roxos escuros que puxam para o vinho (53-56): quebravam a
|
|
126
|
+
// família violeta. Só 256 cores (não truecolor): funciona em qualquer
|
|
127
|
+
// terminal, inclusive no Terminal.app do macOS.
|
|
128
|
+
// A rampa é ESTREITA de propósito: só violetas vizinhos, do escuro ao médio.
|
|
129
|
+
//
|
|
130
|
+
// A lista antiga ia de 57 a 141 e passava por 63 (azul) e 92 (magenta
|
|
131
|
+
// escuro). Vizinhas na tela, essas cores não leem como uma superfície só:
|
|
132
|
+
// leem como listras — e listra clara demais apaga o texto branco por cima.
|
|
133
|
+
// O fundo tem de parecer um pano roxo respirando atrás do painel, não uma
|
|
134
|
+
// bandeira. Os tons claros ficam de fora por isso.
|
|
135
|
+
const ROXOS = [54, 55, 56, 57, 57, 93, 93, 99, 98, 92, 56, 55];
|
|
136
|
+
|
|
137
|
+
function fundoRoxo(x, fase) {
|
|
138
|
+
// Duas ondas de períodos diferentes: o encontro delas dá o desenho
|
|
139
|
+
// irregular de faixas, em vez de listras repetidas e óbvias.
|
|
140
|
+
//
|
|
141
|
+
// As frequências caíram (0.55 → 0.13) porque as faixas tinham três
|
|
142
|
+
// colunas de largura: de longe aquilo não era um fundo ondulando, era
|
|
143
|
+
// chuviscado. Faixa larga anda devagar pela tela, que é o movimento que
|
|
144
|
+
// se quer ver — o painel respira em vez de piscar.
|
|
145
|
+
const faixa = x / 2;
|
|
146
|
+
const onda = Math.sin(faixa * 0.13 + fase) * 0.62 + Math.sin(faixa * 0.041 - fase * 0.55) * 0.38;
|
|
147
|
+
// A curva ³ empurra os valores para o MEIO da rampa: os extremos (o mais
|
|
148
|
+
// escuro e o mais claro) só aparecem no pico da onda, e o painel passa a
|
|
149
|
+
// maior parte do tempo num roxo médio, onde o texto branco se lê.
|
|
150
|
+
const suave = Math.pow(onda, 3) * 0.55 + onda * 0.45;
|
|
151
|
+
const i = Math.round((suave + 1) / 2 * (ROXOS.length - 1));
|
|
152
|
+
return ROXOS[Math.max(0, Math.min(ROXOS.length - 1, i))];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Pinta a linha inteira (até a largura do painel) com a onda por baixo.
|
|
156
|
+
// `destaque` é o trecho que fica branco e forte (o nível escolhido); o resto
|
|
157
|
+
// da linha sai num lilás claro, para o escolhido saltar aos olhos.
|
|
158
|
+
function pintarLinhaUltra(texto, largura, fase, opts = {}) {
|
|
159
|
+
const base = opts.base || 231; // branco
|
|
160
|
+
const apagado = opts.apagado || base;
|
|
161
|
+
const destaque = opts.destaque;
|
|
162
|
+
let saida = '';
|
|
163
|
+
let corFundo = -1;
|
|
164
|
+
let corTexto = -1;
|
|
165
|
+
let forte = null;
|
|
166
|
+
|
|
167
|
+
for (let x = 0; x < largura; x++) {
|
|
168
|
+
const fundo = fundoRoxo(x, fase);
|
|
169
|
+
if (fundo !== corFundo) { saida += `\x1b[48;5;${fundo}m`; corFundo = fundo; }
|
|
170
|
+
|
|
171
|
+
const dentro = destaque && x >= destaque.de && x < destaque.ate;
|
|
172
|
+
const querForte = opts.negrito || dentro;
|
|
173
|
+
const querCor = dentro ? base : apagado;
|
|
174
|
+
if (querForte !== forte) { saida += querForte ? '\x1b[1m' : '\x1b[22m'; forte = querForte; }
|
|
175
|
+
if (querCor !== corTexto) { saida += `\x1b[38;5;${querCor}m`; corTexto = querCor; }
|
|
176
|
+
|
|
177
|
+
saida += texto[x] || ' ';
|
|
178
|
+
}
|
|
179
|
+
return saida + '\x1b[0m';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function desenharEffort(idx, fase) {
|
|
183
|
+
const L = layoutEffort(idx);
|
|
184
|
+
const ultra = NOMES[idx] === 'ultracode';
|
|
185
|
+
|
|
186
|
+
if (ultra) {
|
|
187
|
+
// No ultracode o painel todo vira fundo animado. Cada linha é pintada
|
|
188
|
+
// com a MESMA onda, então as faixas ficam alinhadas de cima a baixo.
|
|
189
|
+
const LILAS = 189; // lilás bem claro, para o que não é o escolhido
|
|
190
|
+
return L.linhas.map((l) => {
|
|
191
|
+
// A régua é uma fileira de "▔". Sobre o roxo ela virava uma
|
|
192
|
+
// listra clara atravessando o topo e cortava o bloco em dois.
|
|
193
|
+
// No ultra ela some e vira fundo liso: a borda de cima do painel
|
|
194
|
+
// passa a ser o próprio degradê, que é o que se quer ver.
|
|
195
|
+
if (l.tipo === 'regua') return pintarLinhaUltra('', L.cols, fase, {});
|
|
196
|
+
if (l.tipo === 'titulo') return pintarLinhaUltra(l.texto, L.cols, fase, { negrito: true });
|
|
197
|
+
if (l.tipo === 'nomes') return pintarLinhaUltra(l.texto, L.cols, fase, { destaque: L.destaque, apagado: LILAS });
|
|
198
|
+
if (l.tipo === 'resumo' || l.tipo === 'extremos') return pintarLinhaUltra(l.texto, L.cols, fase, { base: LILAS, apagado: LILAS });
|
|
199
|
+
return pintarLinhaUltra(l.texto, L.cols, fase, {});
|
|
200
|
+
}).join('\n');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return L.linhas.map((l) => {
|
|
204
|
+
const t = l.texto;
|
|
205
|
+
switch (l.tipo) {
|
|
206
|
+
case 'regua': return c.dim(t);
|
|
207
|
+
case 'titulo': return c.bold(c.white(t));
|
|
208
|
+
case 'extremos': return c.muted(t);
|
|
209
|
+
case 'trilha': {
|
|
210
|
+
// O marcador aceso, o resto da trilha recuada.
|
|
211
|
+
const antes = t.slice(0, L.marca);
|
|
212
|
+
const depois = t.slice(L.marca + 1);
|
|
213
|
+
return c.dim(antes) + c.brand('▲') + c.dim(depois);
|
|
214
|
+
}
|
|
215
|
+
case 'nomes': {
|
|
216
|
+
const { de, ate } = L.destaque;
|
|
217
|
+
return c.muted(t.slice(0, de)) + c.bold(c.brand(t.slice(de, ate))) + c.muted(t.slice(ate));
|
|
218
|
+
}
|
|
219
|
+
case 'resumo': return c.dim(t);
|
|
220
|
+
case 'ajuda': return c.muted(t);
|
|
221
|
+
default: return t;
|
|
222
|
+
}
|
|
223
|
+
}).join('\n');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = { NIVEIS, NOMES, normalizar, nivelDe, indiceDe, modeloDe, pesquisaDe,
|
|
227
|
+
layoutEffort, fundoRoxo, pintarLinhaUltra, desenharEffort, ROXOS };
|
|
228
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primocode",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.16.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": {
|