terminal-smart-cli 0.97.4 → 0.97.6
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/ts.js +58 -3
- package/lib/api.js +2 -2
- package/lib/i18n.js +2 -2
- package/package.json +1 -1
package/bin/ts.js
CHANGED
|
@@ -202,7 +202,7 @@ async function imageCmd(args) {
|
|
|
202
202
|
C.bold(en ? 'This action can generate an image' : 'Esta ação pode gerar uma imagem'),
|
|
203
203
|
C.dim(en ? 'Choose before spending credits. There is no silent paid fallback.' : 'Escolha antes de gastar créditos. Não existe fallback pago silencioso.'),
|
|
204
204
|
'',
|
|
205
|
-
` ${C.cyan('1')} ${C.bold(premium.label || 'Premium · GPT Image 2')} ${C.dim('~' + (premium.estimatedCredits || '?') + ' créditos')}${premium.allowed === false ? C.warn(en ? ' · requires Pro
|
|
205
|
+
` ${C.cyan('1')} ${C.bold(premium.label || 'Premium · GPT Image 2')} ${C.dim('~' + (premium.estimatedCredits || '?') + ' créditos')}${premium.allowed === false ? C.warn(en ? ' · requires Basic/Pro' : ' · requer Básico/Pro') : ''}`,
|
|
206
206
|
` ${C.cyan('2')} ${C.bold(economy.label || 'Econômica · Gemini')} ${C.dim('~' + (economy.estimatedCredits || '?') + ' créditos')}`,
|
|
207
207
|
` ${C.cyan('3')} ${C.bold(en ? 'Continue without images' : 'Continuar sem imagens')} ${C.dim(en ? 'no charge' : 'sem cobrança')}`,
|
|
208
208
|
'',
|
|
@@ -214,7 +214,7 @@ async function imageCmd(args) {
|
|
|
214
214
|
const selected = options.find(o => o.id === choice);
|
|
215
215
|
if (!selected || selected.allowed === false) {
|
|
216
216
|
throw new ApiError((selected && selected.upgradeRequired)
|
|
217
|
-
? (en ? 'GPT Image 2 requires
|
|
217
|
+
? (en ? 'GPT Image 2 requires Basic or Pro.' : 'GPT Image 2 requer plano Básico ou Pro.')
|
|
218
218
|
: (en ? 'Invalid image option.' : 'Opção de imagem inválida.'), { code: 'plan_limit' });
|
|
219
219
|
}
|
|
220
220
|
if (choice === 'none') {
|
|
@@ -2651,6 +2651,60 @@ function perfilCmd(args) {
|
|
|
2651
2651
|
], { title: 'ts perfil' }));
|
|
2652
2652
|
}
|
|
2653
2653
|
|
|
2654
|
+
// ── ts site — cria e publica sites estáticos em *.tsite1.com ────────────────
|
|
2655
|
+
async function siteCmd(args) {
|
|
2656
|
+
const token = needToken();
|
|
2657
|
+
const sub = String(args[0] || 'listar').toLowerCase();
|
|
2658
|
+
const rest = args.slice(1);
|
|
2659
|
+
try {
|
|
2660
|
+
if (['listar', 'list', 'ls', 'status'].includes(sub)) {
|
|
2661
|
+
const r = await api('/api/sites', { token });
|
|
2662
|
+
if (JSON_OUT) return console.log(JSON.stringify(r));
|
|
2663
|
+
if (!r.sites || !r.sites.length) return console.log(ui.infoLine('Nenhum site criado. Use: ts site criar <nome> "<descrição>"'));
|
|
2664
|
+
console.log('\n' + ui.box(r.sites.map(s =>
|
|
2665
|
+
C.bold(s.slug) + C.dim(' · ') + (s.status === 'active' ? C.ok('online') : C.dim(s.status)) +
|
|
2666
|
+
C.dim(s.preview ? ' · prévia grátis' : '') + '\n ' + C.cyan(s.url)
|
|
2667
|
+
), { title: `ts site · ${r.plan} · limite ${r.siteLimit || 'demo'}` }) + '\n');
|
|
2668
|
+
return;
|
|
2669
|
+
}
|
|
2670
|
+
if (['criar', 'create', 'gerar', 'generate'].includes(sub)) {
|
|
2671
|
+
const slug = String(rest.shift() || '').trim();
|
|
2672
|
+
const prompt = rest.join(' ').trim();
|
|
2673
|
+
if (!slug || !prompt) return console.log(ui.errLine('uso: ts site criar <nome> "<descreva o site em linguagem natural>"'));
|
|
2674
|
+
console.log(C.dim('criando e publicando o site…'));
|
|
2675
|
+
const r = await api('/api/sites/generate', { token, method: 'POST', body: { slug, prompt }, timeoutMs: 240000 });
|
|
2676
|
+
if (!r.ok) return console.log(ui.errLine(r.error || r.message || 'não foi possível criar o site'));
|
|
2677
|
+
if (JSON_OUT) return console.log(JSON.stringify(r));
|
|
2678
|
+
console.log('\n' + ui.box([
|
|
2679
|
+
C.ok('Site online!'),
|
|
2680
|
+
C.dim('URL: ') + C.bold(r.url),
|
|
2681
|
+
C.dim('modelo: ') + (r.model || 'smart'),
|
|
2682
|
+
C.dim('tokens: ') + `${r.tokens?.input || 0} entrada · ${r.tokens?.output || 0} saída`,
|
|
2683
|
+
C.dim('créditos: ') + String(r.credits || 0),
|
|
2684
|
+
...(r.preview ? [C.warn('Prévia Free: expira em 24h e é removida em 48h.')] : []),
|
|
2685
|
+
], { title: 'ts site' }) + '\n');
|
|
2686
|
+
return;
|
|
2687
|
+
}
|
|
2688
|
+
if (['publicar', 'publish', 'deploy'].includes(sub)) {
|
|
2689
|
+
const slug = String(rest[0] || '').trim(), file = String(rest[1] || '').trim();
|
|
2690
|
+
if (!slug || !file) return console.log(ui.errLine('uso: ts site publicar <nome> <arquivo.html>'));
|
|
2691
|
+
const html = require('fs').readFileSync(require('path').resolve(file), 'utf8');
|
|
2692
|
+
const r = await api('/api/sites/publish', { token, method: 'POST', body: { slug, html }, timeoutMs: 120000 });
|
|
2693
|
+
if (!r.ok) return console.log(ui.errLine(r.error || 'não foi possível publicar'));
|
|
2694
|
+
return console.log(ui.okLine('site online: ' + r.url));
|
|
2695
|
+
}
|
|
2696
|
+
if (['apagar', 'delete', 'rm', 'remover'].includes(sub)) {
|
|
2697
|
+
const id = Number(rest[0]);
|
|
2698
|
+
if (!id) return console.log(ui.errLine('uso: ts site apagar <id> (veja em: ts site listar --json)'));
|
|
2699
|
+
const r = await api('/api/sites/' + id, { token, method: 'DELETE' });
|
|
2700
|
+
return console.log(r.ok ? ui.okLine('site removido') : ui.errLine(r.error || 'falha'));
|
|
2701
|
+
}
|
|
2702
|
+
console.log(ui.infoLine('Comandos: ts site listar | criar <nome> "<descrição>" | publicar <nome> <arquivo.html> | apagar <id>'));
|
|
2703
|
+
} catch (e) {
|
|
2704
|
+
console.log(ui.errLine(e.code === 'auth' ? T.need_login : (e.message || 'falha')));
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2654
2708
|
// ── ts cloud — caixa de dev na nuvem (Fase 1) ────────────────────────────────
|
|
2655
2709
|
async function cloudCmd(args) {
|
|
2656
2710
|
const token = needToken();
|
|
@@ -2688,7 +2742,7 @@ async function cloudCmd(args) {
|
|
|
2688
2742
|
console.log(C.dim(en ? 'provisioning your cloud box…' : 'provisionando sua caixa na nuvem…'));
|
|
2689
2743
|
try {
|
|
2690
2744
|
const r = await call('up', { method: 'POST', body: requestedSlug ? { slug: requestedSlug } : {}, timeoutMs: 120000 });
|
|
2691
|
-
if (!r.ok) { console.log(ui.errLine(r.error || 'falha')); if (r.code === 'plan_required') console.log(C.dim(en ? 'Get
|
|
2745
|
+
if (!r.ok) { console.log(ui.errLine(r.error || 'falha')); if (r.code === 'plan_required') console.log(C.dim(en ? 'Get Pro at terminalsmart.com.br/planos' : 'Assine o Pro em terminalsmart.com.br/planos')); return; }
|
|
2692
2746
|
if (JSON_OUT) { console.log(JSON.stringify(r)); return; }
|
|
2693
2747
|
console.log('\n' + ui.box([
|
|
2694
2748
|
C.ok(en ? 'Cloud box is up!' : 'Caixa na nuvem no ar!'), '',
|
|
@@ -2926,6 +2980,7 @@ function recallCmd(args) {
|
|
|
2926
2980
|
case 'memoria': case 'memória': case 'memory': return memoriaCmd(POS.slice(1));
|
|
2927
2981
|
case 'recall': case 'lembrei': case 'sessoes': case 'sessões': return recallCmd(POS.slice(1));
|
|
2928
2982
|
case 'vps': case 'servidor': return vpsCmd(POS.slice(1));
|
|
2983
|
+
case 'site': case 'sites': case 'pagina': return siteCmd(POS.slice(1));
|
|
2929
2984
|
case 'cloud': case 'nuvem': return cloudCmd(POS.slice(1));
|
|
2930
2985
|
case 'diagnosticar': case 'diagnose': case 'investigar': case 'debug': return diagnosticarCmd(POS.slice(1));
|
|
2931
2986
|
case 'sentinela': case 'sentinel': case 'vigia': case 'monitor': return sentinelaCmd(POS.slice(1));
|
package/lib/api.js
CHANGED
|
@@ -61,8 +61,8 @@ async function api(path, { method = 'GET', body, token, timeoutMs = 60000, retry
|
|
|
61
61
|
let j = null;
|
|
62
62
|
try { j = await res.json(); } catch (_) {}
|
|
63
63
|
if (res.status === 401) throw new ApiError((j && j.message) || 'unauthorized', { status: 401, code: 'auth' });
|
|
64
|
-
if (res.status === 402) throw new ApiError((j && j.message) || 'no credits', { status: 402, code: (j && j.code) || 'no_credits' });
|
|
65
|
-
if (!res.ok) throw new ApiError((j && j.message) || ('HTTP ' + res.status), { status: res.status });
|
|
64
|
+
if (res.status === 402) throw new ApiError((j && (j.message || j.error)) || 'no credits', { status: 402, code: (j && j.code) || 'no_credits' });
|
|
65
|
+
if (!res.ok) throw new ApiError((j && (j.message || j.error)) || ('HTTP ' + res.status), { status: res.status, code: (j && j.code) || '' });
|
|
66
66
|
return j;
|
|
67
67
|
};
|
|
68
68
|
return withRetry(doFetch, { tries, baseMs: 500, onRetry, connOnly: !idempotent });
|
package/lib/i18n.js
CHANGED
|
@@ -151,7 +151,7 @@ const STR = {
|
|
|
151
151
|
lang_invalid: 'Idioma não suportado. Use: ts idioma pt ou ts idioma en',
|
|
152
152
|
err_conn: 'Não consegui falar com o servidor. Verifique sua internet e tente de novo.',
|
|
153
153
|
err_generic: 'Algo deu errado',
|
|
154
|
-
no_credits: '
|
|
154
|
+
no_credits: 'Seu limite de IA acabou. O Free renova diariamente; planos pagos renovam por ciclo. Continue agora em terminalsmart.com.br/planos',
|
|
155
155
|
ask_empty: 'Diga o que você precisa. Ex.: ts "como liberar a porta 443 no ufw?"',
|
|
156
156
|
chat_hint: 'digite sua mensagem · "sair" encerra · "/nova" zera o contexto',
|
|
157
157
|
chat_prompt: 'Você › ',
|
|
@@ -315,7 +315,7 @@ const STR = {
|
|
|
315
315
|
lang_invalid: 'Unsupported language. Use: ts idioma pt or ts idioma en',
|
|
316
316
|
err_conn: 'Could not reach the server. Check your connection and retry.',
|
|
317
317
|
err_generic: 'Something went wrong',
|
|
318
|
-
no_credits: '
|
|
318
|
+
no_credits: 'Your AI limit is over. Free renews daily; paid plans renew each cycle. Continue now at terminalsmart.com.br/planos',
|
|
319
319
|
ask_empty: 'Tell me what you need. E.g.: ts "how do I open port 443 on ufw?"',
|
|
320
320
|
chat_hint: 'type your message · "exit" quits · "/new" resets context',
|
|
321
321
|
chat_prompt: 'You › ',
|