terminal-smart-cli 0.50.0 → 0.51.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/ts.js +3 -1
- package/lib/diagnose.js +28 -2
- package/lib/i18n.js +2 -0
- package/package.json +1 -1
package/bin/ts.js
CHANGED
|
@@ -1361,6 +1361,8 @@ async function diagnosticarCmd(args) {
|
|
|
1361
1361
|
else if (e.type === 'probe') console.log(' ' + C.dim('$ ') + e.probe.slice(0, 90));
|
|
1362
1362
|
else if (e.type === 'blocked') console.log(' ' + C.err(en ? 'probe blocked (not read-only)' : 'sonda bloqueada (não é só-leitura)'));
|
|
1363
1363
|
else if (e.type === 'skip') console.log(' ' + C.dim(en ? 'repeated probe skipped' : 'sonda repetida pulada'));
|
|
1364
|
+
else if (e.type === 'verify') console.log(' ' + C.dim('↯ ') + (en ? 'adversarial check (trying to refute it)…' : 'checagem adversarial (tentando refutar)…'));
|
|
1365
|
+
else if (e.type === 'refuted') console.log(' ' + C.err(en ? '✗ own conclusion refuted — back to investigating' : '✗ própria conclusão refutada — volta a investigar'));
|
|
1364
1366
|
else if (e.type === 'stuck') console.log(' ' + C.dim(en ? 'exhausted hypotheses' : 'hipóteses esgotadas'));
|
|
1365
1367
|
},
|
|
1366
1368
|
});
|
|
@@ -1369,7 +1371,7 @@ async function diagnosticarCmd(args) {
|
|
|
1369
1371
|
if (r.status === 'no_credits') { console.log(ui.errLine(T.no_credits)); return; }
|
|
1370
1372
|
if (r.status === 'solved') {
|
|
1371
1373
|
console.log(ui.box([
|
|
1372
|
-
C.ok(en ? 'ROOT CAUSE FOUND' : 'CAUSA RAIZ ENCONTRADA') + C.dim(' (' + r.category + ', ' + r.rounds + (en ? ' rounds' : ' rodadas') + ', ' + r.credits + ' cr)'),
|
|
1374
|
+
C.ok(en ? 'ROOT CAUSE FOUND' : 'CAUSA RAIZ ENCONTRADA') + (r.verified ? C.ok(en ? ' ✓verified' : ' ✓verificada') : C.dim(en ? ' (unverified)' : ' (não verificada)')) + C.dim(' (' + r.category + ', ' + r.rounds + (en ? ' rounds' : ' rodadas') + ', ' + r.credits + ' cr)'),
|
|
1373
1375
|
'',
|
|
1374
1376
|
C.bold(en ? 'Cause: ' : 'Causa: ') + r.rootCause,
|
|
1375
1377
|
'',
|
package/lib/diagnose.js
CHANGED
|
@@ -65,8 +65,34 @@ async function diagnose(symptom, opts = {}) {
|
|
|
65
65
|
onEvent({ type: 'think', round, hypothesis: j.hypothesis || '', category: j.category || '', thought: j.thought || '', confidence: j.confidence || 0 });
|
|
66
66
|
|
|
67
67
|
if (j.status === 'solved' && (j.root_cause || j.fix)) {
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
// ── VERIFICAÇÃO ADVERSARIAL: antes de cravar, TENTA REFUTAR a própria conclusão. ──
|
|
69
|
+
// (nasceu de um falso-positivo real: "libtask.so quebrada" quando os símbolos
|
|
70
|
+
// indefinidos eram resolvidos pelo executável gs em runtime — ldd -r engana.)
|
|
71
|
+
const claim = j.root_cause || j.hypothesis || '';
|
|
72
|
+
onEvent({ type: 'verify', round, rootCause: claim });
|
|
73
|
+
const vAsk = lang === 'en'
|
|
74
|
+
? 'Before finalizing, ADVERSARIALLY refute this. Give ONE read-only probe whose output would DISPROVE the root cause if it is wrong. Classic trap: a symbol/lib/file that looks "missing/broken" but is provided elsewhere (e.g. an undefined symbol in a .so is resolved by the MAIN executable at runtime → check the main binary with nm -C). JSON {"refute_probe":"...","disproves_if":"..."}'
|
|
75
|
+
: 'Antes de finalizar, REFUTE adversarialmente. Dê UMA sonda só-leitura cuja saída DESMENTIRIA a causa raiz se ela estiver errada. Armadilha clássica: um símbolo/lib/arquivo que parece "faltando/quebrado" mas é provido em OUTRO lugar (ex.: símbolo indefinido numa .so é resolvido pelo EXECUTÁVEL principal em runtime → cheque o binário principal com nm -C). JSON {"refute_probe":"...","disproves_if":"..."}';
|
|
76
|
+
let vr = null; try { vr = await agent.llm({ baseUrl: k.baseUrl, key: k.key, model, noTools: true, signalMs: 90000, messages: [{ role: 'system', content: sysPrompt(lang, target) }, { role: 'user', content: (lang === 'en' ? 'SYMPTOM:\n' : 'SINTOMA:\n') + symptom + '\n\n' + (lang === 'en' ? 'EVIDENCE:\n' : 'EVIDÊNCIAS:\n') + evLog + '\n\n' + (lang === 'en' ? 'PROPOSED ROOT CAUSE: ' : 'CAUSA RAIZ PROPOSTA: ') + claim + '\n\n' + vAsk }] }); } catch (_) {}
|
|
77
|
+
if (vr) { inTok += (vr.usage.prompt_tokens || 0); outTok += (vr.usage.completion_tokens || 0); }
|
|
78
|
+
const vj = vr ? extractJson(vr.msg.content) : null;
|
|
79
|
+
const rprobe = vj && String(vj.refute_probe || '').trim();
|
|
80
|
+
if (rprobe && isProbe(rprobe) && !seenProbes.has(rprobe)) {
|
|
81
|
+
seenProbes.add(rprobe);
|
|
82
|
+
onEvent({ type: 'probe', round, hypothesis: '↯ verificação: ' + (j.hypothesis || ''), probe: rprobe, expect: vj.disproves_if || '' });
|
|
83
|
+
let rout; try { const ex = await tools.execute('executar_comando', { comando: wrap(rprobe) }, { baseDir: cwd, token }); rout = ex.erro ? ('ERRO: ' + ex.erro) : ([ex.stdout, ex.stderr].filter(Boolean).join('\n') || ('(sem saída, exit ' + (ex.codigo ?? '?') + ')')); } catch (e) { rout = 'FALHA: ' + (e.message || e); }
|
|
84
|
+
evidence.push({ round, hypothesis: '↯ verificação: ' + (j.hypothesis || ''), probe: rprobe, output: rout });
|
|
85
|
+
let fr = null; try { fr = await agent.llm({ baseUrl: k.baseUrl, key: k.key, model, noTools: true, signalMs: 60000, messages: [{ role: 'system', content: sysPrompt(lang, target) }, { role: 'user', content: (lang === 'en' ? 'Root cause claim: ' : 'Causa raiz alegada: ') + claim + '\n' + (lang === 'en' ? 'Refutation probe output:\n' : 'Saída da sonda de refutação:\n') + String(rout).slice(0, 1600) + '\n\n' + (lang === 'en' ? 'CONFIRMED or REFUTED? JSON {"verdict":"confirmed|refuted","reason":"..."}' : 'CONFIRMADA ou REFUTADA? JSON {"verdict":"confirmed|refuted","reason":"..."}') }] }); } catch (_) {}
|
|
86
|
+
if (fr) { inTok += (fr.usage.prompt_tokens || 0); outTok += (fr.usage.completion_tokens || 0); }
|
|
87
|
+
const fj = fr ? extractJson(fr.msg.content) : null;
|
|
88
|
+
if (fj && /refut/i.test(String(fj.verdict))) {
|
|
89
|
+
onEvent({ type: 'refuted', round, reason: fj.reason || '' });
|
|
90
|
+
evidence.push({ round, hypothesis: '✗ REFUTADA: ' + (j.hypothesis || ''), probe: '(veredito)', output: 'Causa REFUTADA — ' + (fj.reason || '') + ' — seguir investigando.' });
|
|
91
|
+
continue; // a própria conclusão caiu na verificação → volta a investigar
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
result = { status: 'solved', rootCause: claim, fix: j.fix || '', category: j.category || 'unknown', confidence: j.confidence || 0, verified: !!rprobe, evidence, rounds: round };
|
|
95
|
+
onEvent({ type: 'solved', rootCause: result.rootCause, fix: result.fix, category: result.category, verified: result.verified });
|
|
70
96
|
break;
|
|
71
97
|
}
|
|
72
98
|
if (j.status === 'stuck' || !j.probe) {
|
package/lib/i18n.js
CHANGED
|
@@ -31,6 +31,8 @@ const STR = {
|
|
|
31
31
|
{ title: 'Agente LOCAL (mãos nesta máquina)', items: [
|
|
32
32
|
['ts agente "tarefa"', 'executa DE VERDADE aqui: comandos, arquivos, diagnóstico'],
|
|
33
33
|
['ts agente "..." --yes', 'autônomo (destrutivo pede aprovação no Telegram)'],
|
|
34
|
+
['ts diagnosticar "erro"', 'INVESTIGA a causa raiz: hipótese→sonda→veredito (só-leitura)'],
|
|
35
|
+
['ts diagnosticar "..." --remoto "ssh user@host"', 'investiga uma máquina remota'],
|
|
34
36
|
['ts agente --continuar "..."', 'retoma o trabalho anterior desta pasta'],
|
|
35
37
|
['ts agente "..." --navegador', 'EXPERIMENTAL: dá um Chrome real ao agente (abrir/ler/clicar/print+visão)'],
|
|
36
38
|
['ts meta "objetivo grande"', 'MISSÃO: checklist + rodadas até terminar (noturno)'],
|