primocode 10.6.0 → 10.7.1
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 +2 -2
- package/bin/primocode.js +58 -37
- package/lib/boas-vindas.js +12 -13
- package/lib/catalogo.js +5 -2
- package/lib/config.js +5 -2
- package/lib/conta.js +194 -169
- package/lib/estudio/cenarios.js +91 -0
- package/lib/estudio/colecao.js +1 -0
- package/lib/estudio/gerativo.js +25 -3
- package/lib/estudio/index.js +46 -5
- package/lib/estudio/kit/mundo.jsx +2 -2
- package/lib/estudio/kit/voxel.jsx +23 -7
- package/lib/estudio/movimentos.js +212 -0
- package/lib/estudio/mundo.js +25 -2
- package/lib/estudio/personagem.js +31 -5
- package/lib/estudio/plano.js +6 -0
- package/lib/nuvem.js +11 -22
- package/lib/planos.js +71 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# PrimoCode v10.
|
|
1
|
+
# PrimoCode v10.7.1
|
|
2
2
|
|
|
3
3
|
Agente de engenharia brasileiro para o terminal, no estilo Claude Code.
|
|
4
4
|
Cria arquivos de verdade, roda comandos, **controla o navegador e o desktop** —
|
|
@@ -9,7 +9,7 @@ OpenRouter, e cada apelido (`top`/`main`/`fast`) é uma **corrente**: se um mode
|
|
|
9
9
|
está no limite de pedidos, o próximo atende. Você não vê o erro, e não paga nada.
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
▐▛███▜▌ Primo Code v10.
|
|
12
|
+
▐▛███▜▌ Primo Code v10.7.1
|
|
13
13
|
▝▜█████▛▘ Bem-vindo de volta, Joel
|
|
14
14
|
▘▘ ▝▝ ~/primocode · /dir <pasta> muda
|
|
15
15
|
```
|
package/bin/primocode.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* PrimoCode CLI
|
|
3
|
+
* PrimoCode CLI
|
|
4
4
|
* Modos: primocode (agente completo, PADRÃO) · chat (conversa pura)
|
|
5
5
|
* Cada sessão trabalha dentro de uma pasta de projeto em ~/primocode/.
|
|
6
6
|
*/
|
|
@@ -42,6 +42,7 @@ const marketplace = require('../lib/marketplace');
|
|
|
42
42
|
const portaoSkill = require('../lib/portao-skill');
|
|
43
43
|
const vozModo = require('../lib/voz');
|
|
44
44
|
const conta = require('../lib/conta');
|
|
45
|
+
const planosTela = require('../lib/planos.js');
|
|
45
46
|
const nuvem = require('../lib/nuvem');
|
|
46
47
|
const compat = require('../lib/compatibilidade');
|
|
47
48
|
const mencoesLib = require('../lib/mencoes');
|
|
@@ -141,6 +142,7 @@ ${c.bold('Comandos')}
|
|
|
141
142
|
${c.brand('/copiar')} copia a última resposta
|
|
142
143
|
${c.brand('/historico')} [termo] procura nos seus pedidos antigos
|
|
143
144
|
${c.brand('/login')} entra na sua conta · ${c.brand('/account')} mostra o plano
|
|
145
|
+
${c.brand('/planos')} os planos e o link para assinar
|
|
144
146
|
${c.brand('/chats')} [n] suas conversas — as mesmas do app e do celular
|
|
145
147
|
${c.brand('/logout')} desconecta este computador da conta
|
|
146
148
|
${c.brand('/comandos')} seus comandos (/revisar, /explicar…) · /comandos novo <nome>
|
|
@@ -196,8 +198,9 @@ const SLASH_COMANDOS = [
|
|
|
196
198
|
['/abrir', 'abre o projeto atual: o servidor de pé, ou a index.html'],
|
|
197
199
|
['/copiar', 'copia a última resposta'],
|
|
198
200
|
['/historico', 'procura nos seus pedidos antigos: /historico login'],
|
|
199
|
-
['/login', 'entra na sua conta
|
|
200
|
-
['/account', 'sua conta
|
|
201
|
+
['/login', 'entra na sua conta (abre o navegador) · /login senha: e-mail e senha aqui'],
|
|
202
|
+
['/account', 'sua conta e o seu plano'],
|
|
203
|
+
['/planos', 'os planos do PrimoCode e o link para assinar'],
|
|
201
204
|
['/chats', 'suas conversas salvas, as mesmas do app e do celular'],
|
|
202
205
|
['/logout', 'desconecta este computador da conta'],
|
|
203
206
|
['!comando', 'roda direto no shell, sem passar pelo agente (o campo fica âmbar)'],
|
|
@@ -1131,9 +1134,9 @@ async function sendPrompt(userText) {
|
|
|
1131
1134
|
que houve e como resolver, em vez de deixar a pessoa achando que o
|
|
1132
1135
|
produto está quebrado. */
|
|
1133
1136
|
if (state.liberado === false) {
|
|
1134
|
-
console.log(c.err(' O PrimoCode pede
|
|
1135
|
-
console.log(c.muted('
|
|
1136
|
-
+ c.muted(' · já assinou? ') + c.brand('/
|
|
1137
|
+
console.log(c.err(' O PrimoCode pede um plano (a partir de R$ 69,90/mês).'));
|
|
1138
|
+
console.log(c.muted(' Veja e assine com ') + c.brand('/planos')
|
|
1139
|
+
+ c.muted(' · já assinou? ') + c.brand('/account'));
|
|
1137
1140
|
return;
|
|
1138
1141
|
}
|
|
1139
1142
|
|
|
@@ -1736,6 +1739,7 @@ const RENOMEADOS = {
|
|
|
1736
1739
|
// a conta
|
|
1737
1740
|
entrar: 'login', conectar: 'login',
|
|
1738
1741
|
conta: 'account',
|
|
1742
|
+
plano: 'planos', assinar: 'planos', assinatura: 'planos', precos: 'planos',
|
|
1739
1743
|
sair: 'exit', // sair é SAIR; desconectar a conta é /logout
|
|
1740
1744
|
// o histórico
|
|
1741
1745
|
// /historico deixou de ser apelido do /chats: agora procura nos pedidos
|
|
@@ -2478,30 +2482,46 @@ async function handleSlash(text) {
|
|
|
2478
2482
|
console.log(c.muted(' A janela saiu na 10.0 — o PrimoCode agora é só o terminal.'));
|
|
2479
2483
|
break;
|
|
2480
2484
|
|
|
2481
|
-
/* A conta do
|
|
2482
|
-
|
|
2485
|
+
/* A conta do PrimoCode (lib/conta.js). Padrão: abre o navegador, onde
|
|
2486
|
+
se cria a conta, entra ou redefine a senha. `/login senha` é o
|
|
2487
|
+
caminho sem navegador (SSH, servidor). */
|
|
2483
2488
|
case 'login': {
|
|
2489
|
+
const partes = String(rest || '').trim().split(/\s+/);
|
|
2484
2490
|
const jaEsta = conta.atual();
|
|
2485
|
-
if (jaEsta &&
|
|
2491
|
+
if (jaEsta && !partes.includes('trocar')) {
|
|
2486
2492
|
console.log(c.muted(' Já conectado como ') + c.brand(jaEsta.email || (jaEsta.uid.slice(0, 12) + '…'))
|
|
2487
2493
|
+ c.muted(` · plano ${jaEsta.plano}`));
|
|
2488
2494
|
console.log(c.dim(' Para entrar com outra conta: ') + c.brand('/login trocar'));
|
|
2489
2495
|
break;
|
|
2490
2496
|
}
|
|
2491
|
-
if (
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
if (
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2497
|
+
if (jaEsta || conta.doConectaAntigo()) conta.sair();
|
|
2498
|
+
|
|
2499
|
+
let r;
|
|
2500
|
+
if (partes.includes('senha')) {
|
|
2501
|
+
const email = String(await ask(c.brand(' E-mail: ')) || '').trim();
|
|
2502
|
+
if (!email) { console.log(c.muted(' Login cancelado.')); break; }
|
|
2503
|
+
const senha = await askSecret(c.brand(' Senha: '));
|
|
2504
|
+
if (!senha) { console.log(c.muted(' Login cancelado.')); break; }
|
|
2505
|
+
const sp = new Spinner('entrando').start();
|
|
2506
|
+
r = await conta.entrar({ email, senha });
|
|
2507
|
+
sp.stop();
|
|
2508
|
+
} else {
|
|
2509
|
+
const sp = new Spinner('esperando você entrar no navegador').start();
|
|
2510
|
+
r = await conta.entrarPeloNavegador({
|
|
2511
|
+
aviso: (url) => {
|
|
2512
|
+
sp.stop();
|
|
2513
|
+
console.log(c.muted(' Abri o navegador para você criar a conta ou entrar.'));
|
|
2514
|
+
console.log(c.dim(' Não abriu? Copie: ') + c.brand(url));
|
|
2515
|
+
console.log(c.dim(' Sem navegador aqui? ') + c.brand('/login senha'));
|
|
2516
|
+
sp.start();
|
|
2517
|
+
},
|
|
2518
|
+
});
|
|
2519
|
+
sp.stop();
|
|
2520
|
+
}
|
|
2501
2521
|
if (!r.ok) { console.log(c.err(` ${r.error}`)); break; }
|
|
2502
2522
|
console.log(c.ok(' Conectado.')
|
|
2503
|
-
+ c.muted(` Plano ${r.plano}
|
|
2504
|
-
|
|
2523
|
+
+ c.muted(r.pro ? ` Plano ${r.plano}.` : ' Sua conta ainda não tem plano: ') + (r.pro ? '' : c.brand('/planos')));
|
|
2524
|
+
return r;
|
|
2505
2525
|
}
|
|
2506
2526
|
|
|
2507
2527
|
/* O histórico da conta — o MESMO que o app desktop e o celular
|
|
@@ -2558,29 +2578,28 @@ async function handleSlash(text) {
|
|
|
2558
2578
|
break;
|
|
2559
2579
|
}
|
|
2560
2580
|
const sp = new Spinner('conferindo').start();
|
|
2561
|
-
// O plano guardado é a foto do
|
|
2562
|
-
// continuaria gratuito. Quem sabe é o servidor.
|
|
2581
|
+
// O plano guardado é a foto do último login: quem sabe é o documento da conta.
|
|
2563
2582
|
const s = await conta.sessao();
|
|
2564
2583
|
sp.stop();
|
|
2565
|
-
console.log(c.white(' Conta ') + c.muted(eu.uid));
|
|
2584
|
+
console.log(c.white(' Conta ') + c.muted(eu.email || eu.uid));
|
|
2566
2585
|
if (s.ok) {
|
|
2567
|
-
|
|
2568
|
-
|
|
2586
|
+
const ate = s.planoAte ? c.dim(` até ${new Date(s.planoAte).toLocaleDateString('pt-BR')}`) : '';
|
|
2587
|
+
console.log(c.white(' Plano ') + (s.pro ? c.brand(s.plano) + ate : c.muted('sem plano ') + c.brand('/planos')));
|
|
2569
2588
|
} else if (s.offline) {
|
|
2570
2589
|
console.log(c.white(' Plano ') + c.muted(eu.plano) + c.dim(' (sem rede — último conhecido)'));
|
|
2571
2590
|
} else {
|
|
2572
2591
|
console.log(c.err(` ${s.error}`));
|
|
2573
|
-
break;
|
|
2574
|
-
}
|
|
2575
|
-
const d = await conta.dispositivos();
|
|
2576
|
-
if (d.ok && d.dispositivos.length) {
|
|
2577
|
-
console.log(c.white('\n Computadores conectados'));
|
|
2578
|
-
for (const x of d.dispositivos) {
|
|
2579
|
-
const quando = x.ultimo_uso
|
|
2580
|
-
? new Date(x.ultimo_uso * 1000).toLocaleDateString('pt-BR') : '—';
|
|
2581
|
-
console.log(' ' + c.muted((x.apelido || 'Computador').padEnd(14)) + c.dim(quando));
|
|
2582
|
-
}
|
|
2583
2592
|
}
|
|
2593
|
+
console.log(c.dim(' Senha: ') + c.brand(`${conta.SITE}/entrar#esqueci`));
|
|
2594
|
+
break;
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
case 'planos': {
|
|
2598
|
+
const sp = new Spinner('buscando os planos').start();
|
|
2599
|
+
const r = await planosTela.buscarPlanos(state.config.server);
|
|
2600
|
+
sp.stop();
|
|
2601
|
+
const eu = conta.atual();
|
|
2602
|
+
for (const l of planosTela.desenhar(r, { cores: c, atual: eu && eu.pro ? eu.plano : null, site: conta.SITE })) console.log(l);
|
|
2584
2603
|
break;
|
|
2585
2604
|
}
|
|
2586
2605
|
|
|
@@ -2771,6 +2790,8 @@ async function main() {
|
|
|
2771
2790
|
process.exit(await require('../lib/mcp.js').main(process.argv.slice(3)));
|
|
2772
2791
|
}
|
|
2773
2792
|
cfg.ensureStructure();
|
|
2793
|
+
// O token da conta dura uma hora: renova agora e a cada minuto (lib/conta.js).
|
|
2794
|
+
await conta.manterVivo();
|
|
2774
2795
|
|
|
2775
2796
|
// Padrão fixo: ~/primocode, não importa de onde o comando foi dado. Antes ele
|
|
2776
2797
|
// adotava a pasta atual do terminal, e o mesmo "crie um site" caía num lugar
|
|
@@ -3047,7 +3068,7 @@ async function main() {
|
|
|
3047
3068
|
cores: c,
|
|
3048
3069
|
interativo: !!(process.stdin.isTTY && process.stdout.isTTY),
|
|
3049
3070
|
conectado: () => conta.atual(),
|
|
3050
|
-
conectar: () => handleSlash('/login').then(() => conta.atual()),
|
|
3071
|
+
conectar: () => handleSlash('/login').then((r) => (r && r.ok === false ? r : conta.atual() || r)),
|
|
3051
3072
|
sessao: () => conta.sessao(),
|
|
3052
3073
|
}).then((r) => {
|
|
3053
3074
|
// O bloqueio de quem não é Premium/Super. É de CORTESIA: este arquivo
|
package/lib/boas-vindas.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* boas-vindas.js — a abertura do PrimoCode, na primeira vez e em toda vez.
|
|
3
3
|
*
|
|
4
|
-
* Duas coisas acontecem aqui, nesta ordem: a pessoa entra na conta do
|
|
5
|
-
*
|
|
4
|
+
* Duas coisas acontecem aqui, nesta ordem: a pessoa entra na conta do
|
|
5
|
+
* PrimoCode, e o plano dela é conferido. Acabou. Não há terceira pergunta.
|
|
6
6
|
*
|
|
7
7
|
* ── POR QUE NÃO SE ESCOLHE MAIS A IA ─────────────────────────────────────
|
|
8
8
|
* Existiam duas telas depois do login: "Com qual IA você quer trabalhar?" e
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
* A API vem configurada no produto. Entrou na conta, pode pedir a primeira
|
|
18
18
|
* coisa.
|
|
19
19
|
*
|
|
20
|
-
* Desde
|
|
21
|
-
*
|
|
20
|
+
* Desde 12/10/2026 a conta é do próprio PrimoCode (Firebase, sem o Conecta):
|
|
21
|
+
* o /login abre o navegador, onde se cria a conta, entra ou redefine a senha,
|
|
22
|
+
* e `/login senha` faz pelo terminal (ver lib/conta.js).
|
|
22
23
|
*
|
|
23
24
|
* ── O BLOQUEIO É DE CORTESIA ─────────────────────────────────────────────
|
|
24
25
|
* Este arquivo vai publicado no npm com o código à vista: um `if (pro)` aqui
|
|
@@ -62,8 +63,8 @@ function esquecer() {
|
|
|
62
63
|
* @param {object} op.cores
|
|
63
64
|
* @param {boolean} op.interativo false = pipe/CI: não pergunta nada
|
|
64
65
|
* @param {()=>any} op.conectado a credencial local, ou null
|
|
65
|
-
* @param {()=>Promise<any>} op.conectar roda o login (
|
|
66
|
-
* @param {()=>Promise<any>} op.sessao confirma o plano
|
|
66
|
+
* @param {()=>Promise<any>} op.conectar roda o login (abre o navegador)
|
|
67
|
+
* @param {()=>Promise<any>} op.sessao confirma o plano no documento da conta
|
|
67
68
|
*/
|
|
68
69
|
async function rodar({ perguntar, mostrar, cores: c, interativo = true,
|
|
69
70
|
conectado, conectar, sessao } = {}) {
|
|
@@ -80,7 +81,7 @@ async function rodar({ perguntar, mostrar, cores: c, interativo = true,
|
|
|
80
81
|
if (!credencial) {
|
|
81
82
|
mostrar('');
|
|
82
83
|
mostrar(c.bold(c.brand(' Bem-vindo ao PrimoCode.')));
|
|
83
|
-
mostrar(c.muted(' Primeiro,
|
|
84
|
+
mostrar(c.muted(' Primeiro, crie sua conta ou entre nela: vou abrir o navegador.'));
|
|
84
85
|
mostrar('');
|
|
85
86
|
const r = await conectar();
|
|
86
87
|
if (!r || r.ok === false) {
|
|
@@ -112,13 +113,11 @@ async function rodar({ perguntar, mostrar, cores: c, interativo = true,
|
|
|
112
113
|
const pro = s && s.ok ? !!s.pro : !!(credencial && credencial.pro);
|
|
113
114
|
if (!pro) {
|
|
114
115
|
mostrar('');
|
|
115
|
-
mostrar(c.err('
|
|
116
|
-
mostrar(c.muted(
|
|
117
|
-
+ c.brand('Premium') + c.muted(' ou ') + c.brand('Super') + c.muted('.'));
|
|
116
|
+
mostrar(c.err(' Sua conta ainda não tem um plano.'));
|
|
117
|
+
mostrar(c.muted(' O PrimoCode é por assinatura, a partir de ') + c.brand('R$ 69,90/mês') + c.muted('.'));
|
|
118
118
|
mostrar('');
|
|
119
|
-
mostrar(c.dim('
|
|
120
|
-
|
|
121
|
-
mostrar(c.dim(' Já assinou? ') + c.brand('/login')
|
|
119
|
+
mostrar(c.dim(' Veja os planos e assine: ') + c.brand('/planos'));
|
|
120
|
+
mostrar(c.dim(' Já assinou? ') + c.brand('/account')
|
|
122
121
|
+ c.dim(' atualiza o plano nesta máquina.'));
|
|
123
122
|
mostrar('');
|
|
124
123
|
return { liberado: false, motivo: 'sem-plano', plano };
|
package/lib/catalogo.js
CHANGED
|
@@ -109,7 +109,10 @@ const GRUPOS = [
|
|
|
109
109
|
+ 'o render empurra para dentro, encolhe o texto largo e afasta o colado; enfeite de fundo marque decorativo: true.' },
|
|
110
110
|
|
|
111
111
|
{ tool: 'estudio_midia', escreve: true, faz: 'procura e baixa ícone, imagem, música e efeito sonoro da internet, e lista as fontes',
|
|
112
|
-
args: 'acao: biblioteca | imagem | icones | icones3d | animacoes | som | trilha | efeito | fontes | print | elementos | elemento | recortar. termo. id (para baixar). '
|
|
112
|
+
args: 'acao: biblioteca | movimentos | cenarios | salvar_cenario | imagem | icones | icones3d | animacoes | som | trilha | efeito | fontes | print | elementos | elemento | recortar. termo. id (para baixar). '
|
|
113
|
+
+ 'movimentos termo:"quique" categoria:entrada|saida|enfase|loop: os 100+ movimentos prontos com nome; no elemento, movimento:"<nome>" (ou {nome, em, duracao}, ou uma lista) vira quadros-chave sozinho. Varie: não use o mesmo em todo elemento. Pode inventar o seu em anima. '
|
|
114
|
+
+ 'cenarios: os lugares prontos do vídeo 3D e os que a pessoa já salvou. Pode CRIAR um cenário novo na cena (lugar base + ceu, chao, parede, luz, acento, hora, elementos); '
|
|
115
|
+
+ 'no fim do vídeo pergunte "posso salvar este cenário pra usar na próxima vez?" e, SÓ com o sim, salvar_cenario com nome, cenario {…} e autorizado:true. Depois, lugar:"<nome>" traz ele de volta. '
|
|
113
116
|
+ 'biblioteca: o cardápio INTEIRO do que existe (ícone 2D, ícone 3D, animação pronta, efeito sonoro, música, fonte, personagem 3D) — olhe antes de escolher. '
|
|
114
117
|
+ 'icones3d termo:"coffee": os 1.500+ ícones 3D renderizados do Fluent Emoji (MIT); com item:"fluent3d:<nome>" e o id do projeto, baixa e devolve o elemento {tipo:"imagem"} pronto. '
|
|
115
118
|
+ 'animacoes termo:"fire": as 881 animações prontas do Noto (Lottie, vetor; CC BY 4.0, ponha o crédito); com item:"noto:<código>", baixa e devolve o elemento {tipo:"kit", peca:"animacao", src, loop} pronto. '
|
|
@@ -119,7 +122,7 @@ const GRUPOS = [
|
|
|
119
122
|
+ 'Use SE o pedido trouxer um site e o vídeo for SOBRE ele (lançamento, tour, case); vídeo que só cita a marca não precisa. '
|
|
120
123
|
+ 'elementos: url — lê o CÓDIGO do site e lista as peças que dá para tirar (logo, menu, titulo, hero, botao, cartao, imagem, formulario, preco, rodape), cada uma com o seletor. '
|
|
121
124
|
+ 'elemento: url + seletor (ou texto: o que está escrito nele) — tira SÓ aquela peça, em PNG com fundo transparente e no dobro da resolução, e devolve o código dela (html e estilo: fonte, cor, raio, sombra) e um elemento {tipo:"imagem"} pronto; '
|
|
122
|
-
+ 'use para pôr o botão, o cartão de preço ou a logo do site animando no vídeo (ou redesenhe a peça como componente a partir do código). '
|
|
125
|
+
+ 'use para pôr o botão, o cartão de preço ou a logo do site animando no vídeo (ou redesenhe a peça como componente a partir do código). No vídeo 3D (estilo personagem), a peça ENTRA NA CENA em blocos: passe roteiro.objetos:[{nome:"logo", src:<o src devolvido>}] (até 3). '
|
|
123
126
|
+ 'recortar: arquivo — tira o fundo de qualquer foto com IA (rembg), PNG transparente. '
|
|
124
127
|
+ 'efeitos: lista os componentes guardados (os menos usados primeiro). usar-efeito {nome}: copia para o projeto e devolve o elemento — use se um deles servir a ESTE roteiro. '
|
|
125
128
|
+ 'guardar-efeito {arquivo, nome, descricao}: guarda um componente que você escreveu e ficou bom, para os próximos vídeos '
|
package/lib/config.js
CHANGED
|
@@ -32,7 +32,8 @@ const PROJETO_ATIVO_FILE = path.join(CONFIG_DIR, 'projeto-ativo.json');
|
|
|
32
32
|
* função no meio de um turno. Ler quatro linhas de JSON é mais barato que
|
|
33
33
|
* essa aula. */
|
|
34
34
|
function tokenDaConta() {
|
|
35
|
-
|
|
35
|
+
// O token de acesso do Firebase (dura 1h; o conta.manterVivo renova no arquivo).
|
|
36
|
+
try { return JSON.parse(fs.readFileSync(CONTA_FILE, 'utf8')).idToken || null; }
|
|
36
37
|
catch { return null; }
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -321,7 +322,9 @@ function loadConfig() {
|
|
|
321
322
|
* arquivo, e o arquivo ganha da conta. Quem hospeda o próprio
|
|
322
323
|
* servidor e configurou um token não pode ter isso trocado por
|
|
323
324
|
* entrar numa conta. */
|
|
324
|
-
|
|
325
|
+
/* Getter, e não valor: o token da conta vence em uma hora e é
|
|
326
|
+
renovado no arquivo; uma sessão de três horas leria o vencido. */
|
|
327
|
+
get token() { return process.env.PRIMOCODE_TOKEN || file.token || tokenDaConta(); },
|
|
325
328
|
autoApply: file.autoApply === true,
|
|
326
329
|
currentProject: file.currentProject || null,
|
|
327
330
|
userName: file.userName || null,
|