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 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/Ultra' : ' · requer Pro/Ultra') : ''}`,
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 Pro or Ultra.' : 'GPT Image 2 requer plano Pro ou Ultra.')
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 Ultra at terminalsmart.com.br/planos' : 'Assine o Ultra em terminalsmart.com.br/planos')); return; }
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: 'Seus créditos acabaram. Gerencie em terminalsmart.com.br/planos',
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: 'You are out of credits. Manage at terminalsmart.com.br/planos',
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 › ',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminal-smart-cli",
3
- "version": "0.97.4",
3
+ "version": "0.97.6",
4
4
  "description": "Terminal Smart no seu terminal — pergunte, analise logs por pipe e orquestre agentes de IA. Comando: ts",
5
5
  "bin": {
6
6
  "ts": "bin/ts.js"