terminal-smart-cli 0.91.1 → 0.92.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/lib/ssh.js CHANGED
@@ -88,10 +88,22 @@ function connect(opts = {}) {
88
88
  function exec(cmd, { timeoutMs = 120000 } = {}) {
89
89
  return new Promise((resolve, reject) => {
90
90
  if (!_conn) return reject(new Error('Não conectado. Rode "ts vps" ou conectar_vps primeiro.'));
91
- _conn.exec(cmd, (err, stream) => {
92
- if (err) return reject(err);
93
- let stdout = '', stderr = '', done = false;
94
- const to = setTimeout(() => { if (!done) { done = true; try { stream.close(); } catch (_) {} resolve({ code: 124, stdout, stderr: stderr + '\n[timeout]' }); } }, timeoutMs);
91
+ let stdout = '', stderr = '', done = false, stream = null;
92
+ // Timeout GLOBAL da chamada — armado ANTES do exec, então dispara MESMO se _conn.exec
93
+ // nunca chamar o callback. Numa conexão meia-morta (TCP vivo, sshd travado) o exec ficava
94
+ // pendurado pra SEMPRE (bug do hang de 40min). Ao estourar, derruba a conexão pra a PRÓXIMA
95
+ // chamada reconectar do zero (via _lastGood) em vez de pendurar de novo.
96
+ const to = setTimeout(() => {
97
+ if (done) return; done = true;
98
+ try { if (stream) stream.close(); } catch (_) {}
99
+ try { if (_conn) _conn.end(); } catch (_) {}
100
+ _conn = null; _info = null;
101
+ resolve({ code: 124, stdout, stderr: (stderr || '') + '\n[timeout: sem resposta em ' + Math.round(timeoutMs / 1000) + 's — a conexão pode ter travado; reconecte e tente de novo, e rode tarefas longas em background com setsid]' });
102
+ }, timeoutMs);
103
+ _conn.exec(cmd, (err, s) => {
104
+ if (done) { try { s && s.close(); } catch (_) {} return; }
105
+ if (err) { done = true; clearTimeout(to); return reject(err); }
106
+ stream = s;
95
107
  stream.on('close', (code) => { if (done) return; done = true; clearTimeout(to); resolve({ code: code == null ? 0 : code, stdout, stderr }); });
96
108
  stream.on('data', (d) => { stdout += d.toString(); if (stdout.length > 200000) stdout = stdout.slice(-120000); });
97
109
  stream.stderr.on('data', (d) => { stderr += d.toString(); if (stderr.length > 60000) stderr = stderr.slice(-40000); });
package/lib/tools.js CHANGED
@@ -381,7 +381,14 @@ async function execute(name, input, opts = {}) {
381
381
  }
382
382
  case 'executar_remoto': {
383
383
  const ssh = require('./ssh');
384
- if (!ssh.isConnected()) return { erro: 'Não conectado a nenhum servidor. Chame conectar_vps primeiro.' };
384
+ // Conexão caiu (ou um exec anterior estourou o timeout e a derrubou)? Reconecta 1x
385
+ // SOZINHO com a última que funcionou (_lastGood: mesmo host/user/chave) — sem pedir
386
+ // nada ao usuário. Assim um SSH que travou não pendura a missão: o timeout do exec
387
+ // devolve o controle, e a próxima chamada se reconecta e segue.
388
+ if (!ssh.isConnected()) {
389
+ if (ssh.lastGood()) { try { await ssh.connect(); } catch (_) {} }
390
+ if (!ssh.isConnected()) return { erro: 'Não conectado a nenhum servidor. Chame conectar_vps primeiro.' };
391
+ }
385
392
  const comando = String(input.comando || '');
386
393
  const out = await ssh.exec(comando, { timeoutMs: 180000 });
387
394
  const c = compactor.compact(comando, out.stdout || '', { codigo: out.code });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminal-smart-cli",
3
- "version": "0.91.1",
3
+ "version": "0.92.0",
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"