terminal-smart-cli 0.60.0 → 0.62.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/README.md CHANGED
@@ -29,7 +29,12 @@ ts "como libero a porta 443 no ufw?"
29
29
  | `ts agente --ler` / `--plano` | Modo só-leitura (Ask) / propõe um plano sem agir |
30
30
  | `ts agente --worktree` | Isola a run num git worktree (não toca a árvore principal) |
31
31
  | `ts agente --stream-json` | Modo headless/CI: só NDJSON tipado no stdout |
32
- | `ts meta "objetivo grande"` | Missão: checklist + rodadas até terminar (modo noturno) |
32
+ | `ts diagnosticar "erro"` | **Investiga a causa raiz**: hipótese sonda (só-leitura) → verificação adversarial → veredito. `--remoto "ssh user@host"` investiga uma VPS |
33
+ | `ts sentinela add "nome" --cmd "..."` | **Vigia determinístico (zero token)**: check por regra (`--contem`/`--sem`/`exit0`); falhou → avisa no Telegram (`--escalar` anexa o diagnóstico). `ts sentinela instalar` agenda no cron/Task Scheduler |
34
+ | `ts indexar` · `ts buscar "..."` | **Busca semântica no código** (BM25 local, sem custo); o agente usa via `buscar_codigo` |
35
+ | `ts sonhar` | Consolida a memória episódica do projeto em camadas (dream session); `ts sonhar listar` mostra o histórico |
36
+ | `ts perfil usar <nome>` | Personas com **cofre de memória isolado**; `--perfil <nome>` usa um pontualmente |
37
+ | `ts meta "objetivo grande"` | Missão: checklist + rodadas até terminar (modo noturno). Reporta verificação **honesta**: verificada / build-ok-execução-não / não-verificada |
33
38
  | `ts eval suite.json` | Avalia o agente numa suíte de casos (juiz de IA + nota; `--json`/exit 1 pra CI) |
34
39
  | `ts acp` | Servidor Agent Client Protocol — pluga o `ts` em editores tipo Zed |
35
40
  | `ts run "objetivo"` | Orquestra agentes na nuvem (plano + aprovação) |
package/bin/ts.js CHANGED
@@ -879,7 +879,7 @@ async function agentCmd(words, { askFn, cwd: cwdIn = null, onCwd = null } = {})
879
879
  // HEADLESS stream-json: fecha com assistant (texto) + result (métricas) e sai.
880
880
  if (streamJson) {
881
881
  _emit(core.AgentEvents.assistant(out.text || ''));
882
- _emit(core.AgentEvents.result({ steps: out.steps, credits: out.credits, tokens: out.tokens, context: out.context || null, needHuman: out.needHuman || null, cwd: effCwd, duration_ms: Date.now() - t0, worktree: _wt ? { path: _wt.path, branch: _wt.branch, base: _wt.base, changed: (_wtInfo && _wtInfo.changed) || 0 } : null }));
882
+ _emit(core.AgentEvents.result({ steps: out.steps, credits: out.credits, tokens: out.tokens, context: out.context || null, needHuman: out.needHuman || null, toolErrors: out.toolErrors || [], cwd: effCwd, duration_ms: Date.now() - t0, worktree: _wt ? { path: _wt.path, branch: _wt.branch, base: _wt.base, changed: (_wtInfo && _wtInfo.changed) || 0 } : null }));
883
883
  return;
884
884
  }
885
885
  if (JSON_OUT) { console.log(JSON.stringify({ ok: true, result: out.text, steps: out.steps, credits: out.credits, tokens: out.tokens, context: out.context, needHuman: out.needHuman })); return; }
@@ -1304,8 +1304,11 @@ async function metaCmd() {
1304
1304
  console.log('\n' + _metaChecklistBox(st.checklist));
1305
1305
  if (JSON_OUT) { console.log(JSON.stringify(st)); }
1306
1306
  if (st.status === 'done') {
1307
- console.log(ui.okLine(C.bold(T.meta_done) + C.dim(` · ${st.rounds.length} rodada(s) · ${st.creditsSpent} créditos · ${secs} min` + (st.escalations ? ` · ${st.escalations} escalonamento(s)` : ''))));
1308
- metaMod.notify(token, T.meta_notify_done(st.goal, done, st.creditsSpent));
1307
+ const _vl = metaMod.verificationLabel(st.verification, cfg.lang);
1308
+ const _vtag = (_vl.ok ? C.ok : C.warn)(` · ${_vl.icon} ${_vl.txt}`);
1309
+ console.log((_vl.ok ? ui.okLine : ui.infoLine)(C.bold(T.meta_done) + C.dim(` · ${st.rounds.length} rodada(s) · ${st.creditsSpent} créditos · ${secs} min` + (st.escalations ? ` · ${st.escalations} escalonamento(s)` : '')) + _vtag));
1310
+ if (!_vl.ok) console.log(' ' + C.dim((cfg.lang === 'en' ? 'Heads up: the deliverable was produced but NOT fully proven — check it before relying on it.' : 'Atenção: o entregável foi produzido mas NÃO foi totalmente provado — confira antes de confiar.') + (st.runNote ? ' (' + String(st.runNote).trim() + ')' : '')));
1311
+ metaMod.notify(token, T.meta_notify_done(st.goal, done, st.creditsSpent) + (_vl.ok ? '' : `\n⚠️ ${_vl.txt}`));
1309
1312
  } else if (st.pause_reason === 'awaiting_human' && st.humanRequest) {
1310
1313
  console.log(ui.infoLine(C.bold('🙋 Preciso de você: ') + st.humanRequest.motivo));
1311
1314
  console.log(' ' + C.dim(st.humanRequest.o_que_fazer));
@@ -1616,7 +1619,7 @@ function buscarCmd(args) {
1616
1619
  if (!hits.length) { console.log('\n' + ui.infoLine(en ? 'nothing relevant — try other terms' : 'nada relevante — tente outros termos')); return; }
1617
1620
  console.log('\n' + ui.box([
1618
1621
  C.bold(en ? 'Code search' : 'Busca no código') + C.dim(' "' + q.slice(0, 48) + '"'),
1619
- ...hits.flatMap(h => ['', C.cyan(h.file + ':' + h.l0 + '-' + h.l1) + C.dim(' ' + h.score),
1622
+ ...hits.flatMap(h => ['', C.cyan(h.file + ':' + h.l0 + '-' + h.l1) + C.dim(' ' + h.score) + (h.sig && h.sig.length ? C.dim(' · define: ' + h.sig.slice(0, 4).join(', ')) : ''),
1620
1623
  ...h.snippet.split('\n').filter(l => l.trim()).slice(0, 2).map(l => C.dim(' ' + l.slice(0, 74)))]),
1621
1624
  ], { title: 'ts buscar' }));
1622
1625
  }
package/lib/agent.js CHANGED
@@ -355,6 +355,7 @@ async function run(task, opts = {}) {
355
355
  const acc = { inTok: 0, outTok: 0, cachedTok: 0 };
356
356
  const _mcpSeen = new Set(); // servidores MCP já autorizados NESTA sessão (1ª chamada pede OK)
357
357
  const actions = []; // ações REAIS bem-sucedidas (evidência objetiva pro marcador do meta)
358
+ const _toolErrs = []; // erros de ferramenta TIPADOS na run (core.classifyToolResult) — sinal duro anti-done-falso
358
359
  let finalText = '', usedModel = 'smart', steps = 0, charged = 0, _visionCredits = 0;
359
360
  const ctxWindow = winFor(model);
360
361
  // MEMÓRIA EPISÓDICA: ao fim da run, grava UM episódio (o que fez aqui) → a próxima run
@@ -649,9 +650,13 @@ async function run(task, opts = {}) {
649
650
  onStep({ name, detail: argsShort(name, input) });
650
651
  result = await tools.execute(name, input, { confineDir, baseDir: cwd, token });
651
652
  steps++;
652
- // LEDGER DE ERROS (Evolve 3): registro determinístico de erro REAL de ferramenta
653
- // (só neste branch recusa de gate/roMode NÃO é erro do projeto). Zero IA.
654
- if (result && (result.erro || (typeof result.codigo === 'number' && result.codigo !== 0))) {
653
+ // TOOLRESULT TIPADO (core.classifyToolResult): classe de erro DETERMINÍSTICA. A verdade
654
+ // sobre "deu certo?" vem daqui, não da narrativa do modelo. 'blocked' = política (gate),
655
+ // não falha de execução não conta pro ledger nem pro sinal de erro da run.
656
+ const _tr = core.classifyToolResult(result);
657
+ if (!_tr.ok && _tr.status !== 'blocked') {
658
+ _toolErrs.push({ tool: name, class: _tr.errorClass, retryable: _tr.retryable, evidence: _tr.evidence });
659
+ // LEDGER DE ERROS (Evolve 3): registro determinístico, zero IA.
655
660
  try { require('./memoria').logErro(confineDir || cwd, name, String(result.erro || result.stderr || ('exit ' + result.codigo))); } catch (_) {}
656
661
  }
657
662
  // HOOK PostToolUse (determinístico): feedback (ex: lint/format) vai pro modelo ver.
@@ -717,7 +722,10 @@ async function run(task, opts = {}) {
717
722
  if (_hooks._any) { try { _hooksMod.run(_hooks, 'Stop', { cwd, text: finalText, steps }); } catch (_) {} }
718
723
  _logEp(stopped ? 'cancel' : (loopedOut ? 'stuck' : 'done'));
719
724
  await _bill();
720
- return { text: finalText, steps, credits: charged + _visionCredits, tokens: acc, model: usedModel, actions, messages, cwd, context: lastCtx };
725
+ // toolErrors: erros de ferramenta que NÃO foram seguidos de uma ação bem-sucedida da MESMA
726
+ // ferramenta depois (heurística leve de "não-recuperado") — sinal duro pro meta não marcar done falso.
727
+ const _lastErr = _toolErrs.length ? _toolErrs[_toolErrs.length - 1] : null;
728
+ return { text: finalText, steps, credits: charged + _visionCredits, tokens: acc, model: usedModel, actions, messages, cwd, context: lastCtx, toolErrors: _toolErrs, lastToolError: _lastErr };
721
729
  }
722
730
 
723
731
  module.exports = { run, llm, _test: { winFor, estMsgsTok, COMPACT_AT, KEEP_TAIL, loopSig, isCycle, loopDecision } };
package/lib/core.js CHANGED
@@ -74,8 +74,62 @@ const AgentEvents = {
74
74
  // nomes dos eventos, pra quem for validar/mapear (App/Web)
75
75
  const EVENT_TYPES = ['system', 'tool', 'assistant', 'result'];
76
76
 
77
+ // ── 4) TOOLRESULT TIPADO — classificação DETERMINÍSTICA (o modelo não decide sucesso) ──
78
+ // Insight das análises externas (GPT): "o modelo propõe; o harness autoriza, executa,
79
+ // observa e COMPROVA". Erro de ferramenta NUNCA pode virar etapa `done`. Aqui uma função
80
+ // PURA transforma o retorno bruto de qualquer ferramenta num envelope tipado sem alterar o
81
+ // raw (retrocompatível). Classe de erro alimenta o Recovery Engine e o ledger; `ok:false`
82
+ // deve barrar a marcação de sucesso a montante (meta/orquestrador).
83
+ const ERROR_CLASSES = ['permission_denied', 'not_found', 'port_in_use', 'missing_dep', 'package_lock',
84
+ 'timeout', 'compile_error', 'test_failed', 'network', 'auth', 'git_conflict', 'invalid_schema',
85
+ 'blocked', 'unknown'];
86
+ // classes transitórias → vale re-tentar (mesma abordagem); as demais exigem mudar de abordagem.
87
+ const RETRYABLE_CLASSES = new Set(['network', 'timeout', 'package_lock', 'port_in_use']);
88
+
89
+ function classifyError(msg) {
90
+ const s = String(msg || '').toLowerCase();
91
+ // POLÍTICA (nossos gates) — não é erro do mundo, é recusa: não re-tenta, não conta como falha de exec
92
+ if (/\bbloquead|\brecus|read-only|só-leitura|loop detectad|\bloop:|aprova(ção|r) neg|negou.*aprova/i.test(s)) return 'blocked';
93
+ if (/eacces|permission denied|access is denied|operation not permitted|acesso negado|permissão negada/i.test(s)) return 'permission_denied';
94
+ if (/could not get lock|dpkg was interrupted|resource temporarily unavailable.*lock|another (app|process) .*lock|unable to (acquire|lock)/i.test(s)) return 'package_lock';
95
+ if (/eaddrinuse|address already in use|porta .*(ocupad|em uso)|already running/i.test(s)) return 'port_in_use';
96
+ if (/cannot find module|command not found|not recognized as|modulenotfounderror|no module named|no such command|is not installed|não (foi )?encontrad[oa] o comando/i.test(s)) return 'missing_dep';
97
+ if (/enoent|no such file|não encontrad|not found|arquivo inexistente|404/i.test(s)) return 'not_found';
98
+ if (/etimedout|timed out|timeout|excedeu o tempo/i.test(s)) return 'timeout';
99
+ if (/econnrefused|enotfound|getaddrinfo|network|connection refused|conexão recusada|conn|dns/i.test(s)) return 'network';
100
+ if (/401|403|unauthorized|authentication failed|invalid credentials|credenciais inválidas|não autorizado/i.test(s)) return 'auth';
101
+ if (/merge conflict|\bconflict\b|needs merge|conflito de merge/i.test(s)) return 'git_conflict';
102
+ if (/syntaxerror|unexpected token|compile error|erro de compilação|error ts\d|cannot compile|parse error na compil/i.test(s)) return 'compile_error';
103
+ if (/\d+ (failing|failed)\b|test(s)? failed|assertion|expected .* (to|but)|falhou.*teste|teste(s)? falhar/i.test(s)) return 'test_failed';
104
+ if (/invalid json|json.*(parse|inválido)|schema|malformed/i.test(s)) return 'invalid_schema';
105
+ return 'unknown';
106
+ }
107
+
108
+ // raw = retorno de uma ferramenta (execute). Devolve { ok, status, errorClass, retryable, evidence }.
109
+ // NÃO muta o raw. Convenções do TS: {erro} = falha; {codigo|exitCode}≠0 = falha de shell;
110
+ // {written|created|resumo|stdout|...} = evidência de sucesso.
111
+ function classifyToolResult(raw) {
112
+ if (raw == null || typeof raw !== 'object') return { ok: true, status: 'ok', errorClass: null, retryable: false, evidence: raw != null ? String(raw).slice(0, 200) : '' };
113
+ const exit = raw.codigo != null ? raw.codigo : (raw.exitCode != null ? raw.exitCode : null);
114
+ const errMsg = raw.erro || raw.error || (exit != null && exit !== 0 ? (raw.stderr || raw.stdout || ('exit ' + exit)) : '');
115
+ const failed = !!raw.erro || !!raw.error || (exit != null && exit !== 0);
116
+ if (failed) {
117
+ const errorClass = classifyError(errMsg);
118
+ return {
119
+ ok: false,
120
+ status: errorClass === 'blocked' ? 'blocked' : 'failed',
121
+ errorClass,
122
+ retryable: RETRYABLE_CLASSES.has(errorClass),
123
+ evidence: String(errMsg).replace(/\s+/g, ' ').slice(0, 300),
124
+ };
125
+ }
126
+ const ev = raw.written || raw.created || raw.resumo || raw.arquivo || (raw.stdout != null ? String(raw.stdout).slice(0, 200) : '') || (raw.total != null ? (raw.total + ' resultado(s)') : '');
127
+ return { ok: true, status: 'ok', errorClass: null, retryable: false, evidence: String(ev || '').replace(/\s+/g, ' ').slice(0, 200) };
128
+ }
129
+
77
130
  module.exports = {
78
131
  DESTRUCTIVE, isDestructive,
79
132
  MODEL_WINDOWS, CTX_WINDOW_DEFAULT, DEFAULT_EXECUTOR, COMPACT_AT, KEEP_TAIL, winFor, estMsgsTok,
80
133
  AgentEvents, EVENT_TYPES,
134
+ ERROR_CLASSES, RETRYABLE_CLASSES, classifyError, classifyToolResult,
81
135
  };
package/lib/indice.js CHANGED
Binary file
package/lib/meta.js CHANGED
@@ -1100,7 +1100,7 @@ async function run(goal, opts = {}) {
1100
1100
  if (runGate && (b.kind === 'android' || b.kind === 'flutter')) {
1101
1101
  onRound({ n: st.rounds.length + 1, item: (lang === 'en' ? 'Launching the app on the emulator (run gate)…' : 'Abrindo o app no emulador (run gate)…'), attempt: 1 });
1102
1102
  const rg = runApp(b, dir, onAlert);
1103
- if (rg.skipped) { st.buildVerified = true; st.visualOk = true; st.status = 'done'; st.runNote = 'run gate pulado: ' + rg.reason; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st; }
1103
+ if (rg.skipped) { st.buildVerified = true; st.verification = 'built_not_run'; st.status = 'done'; st.runNote = 'run gate pulado: ' + rg.reason; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st; }
1104
1104
  if (rg.ok) {
1105
1105
  st.buildVerified = true; st.runVerified = true;
1106
1106
  // ── VISUAL GATE: app abre → tira print e o "olho" critica o layout.
@@ -1126,9 +1126,9 @@ async function run(goal, opts = {}) {
1126
1126
  // Aprovado: impecável OU só com nitpicks cosméticos (não vale queimar rodada cara).
1127
1127
  st.visualOk = true;
1128
1128
  if (vg.severity === 'ressalvas') { st.runNote = (st.runNote || '') + ' visual aprovado com ressalvas cosméticas (sem defeito estrutural)'; onAlert({ type: 'design', text: `👁 ts: visual APROVADO — sobrou só nitpick cosmético (sem defeito estrutural). Não vou gastar polimento caro à toa.` }); }
1129
- st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1129
+ st.verification = 'verified'; st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1130
1130
  }
1131
- } else { st.visualOk = true; st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st; }
1131
+ } else { st.visualOk = true; st.verification = 'verified'; st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st; }
1132
1132
  } else {
1133
1133
  // CRASHOU ao abrir → trata como erro pro executor corrigir (loop igual ao build)
1134
1134
  st.buildFixes = (st.buildFixes || 0) + 1;
@@ -1143,7 +1143,7 @@ async function run(goal, opts = {}) {
1143
1143
  let wg = { ok: true }; try { wg = await webRunGate(b, { token, eye, eyeGate: !!eye && (st.visualFixes || 0) < MAX_VISUAL_FIXES }); } catch (_) {}
1144
1144
  st.creditsSpent += wg.credits || 0;
1145
1145
  if (wg.ok) {
1146
- st.buildVerified = true; st.runVerified = true; st.visualOk = true;
1146
+ st.buildVerified = true; st.runVerified = true; st.visualOk = true; st.verification = 'verified';
1147
1147
  if (wg.shot) st.webShot = wg.shot;
1148
1148
  st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1149
1149
  } else {
@@ -1156,7 +1156,7 @@ async function run(goal, opts = {}) {
1156
1156
  st.buildError = errText;
1157
1157
  }
1158
1158
  } else {
1159
- st.buildVerified = true; st.visualOk = true; st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1159
+ st.buildVerified = true; st.verification = 'built_not_run'; st.runNote = (st.runNote || '') + ' sem gate de execução pra este tipo de projeto — build ok, execução NÃO verificada'; st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1160
1160
  }
1161
1161
  } else { st.buildFixes = (st.buildFixes || 0) + 1; errText = r.out; st.buildError = r.out; }
1162
1162
  // ── ESCALONAMENTO: só em erro REAL de build/crash. Mesmo erro de novo → PENSADOR caro diagnostica ──
@@ -1180,12 +1180,18 @@ async function run(goal, opts = {}) {
1180
1180
  pend = [fixItem];
1181
1181
  }
1182
1182
  } else if (!st.buildVerified || (eye && !st.visualOk)) {
1183
- // Portão precisava rodar mas estourou o teto (build ou visual): encerra registrando a limitação.
1184
- st.buildVerified = true; st.visualOk = true;
1185
- st.status = 'done'; st.finished_at = new Date().toISOString();
1186
- st.runNote = (st.runNote || '') + (visualCapLeft ? '' : ' visual: teto de polimentos atingido');
1183
+ // Portão precisava rodar mas estourou o teto (build ou visual). HONESTIDADE: NÃO forjar
1184
+ // buildVerified/visualOk (ausência de prova NÃO é sucesso). Encerra com status honesto.
1185
+ st.status = 'done';
1186
+ st.verification = st.buildVerified ? 'built_not_run' : 'unverified';
1187
+ st.runNote = (st.runNote || '') + (st.buildVerified
1188
+ ? ' visual: teto de polimentos atingido — aprovação visual NÃO confirmada'
1189
+ : ' build: teto de correções atingido — NÃO compilou/rodou de forma verificada');
1190
+ st.finished_at = new Date().toISOString();
1187
1191
  save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1188
1192
  } else {
1193
+ // Não precisava de gate (tarefa não-compilável: análise/relatório/config). Honesto: sem gate a aplicar.
1194
+ st.verification = st.verification || 'no_gate';
1189
1195
  st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir);
1190
1196
  return st;
1191
1197
  }
@@ -1359,4 +1365,20 @@ async function notify(token, text) {
1359
1365
  try { await api('/api/cli/notify', { method: 'POST', token, body: { text }, timeoutMs: 15000 }); } catch (_) {}
1360
1366
  }
1361
1367
 
1362
- module.exports = { webRunGate, run, load, notify, stateFile, detectBuild, ensureToolchain, runBuild, escalate, designPhase, archPhase, looksVisual, looksComplex, runApp, visualGate, ensureEmulator, _projKind, _llmVision };
1368
+ // Rótulo HONESTO da verificação da missão (nunca finge que provou o que não provou).
1369
+ // verified = build + execução (e visual, se houve olho) passaram de verdade nos gates
1370
+ // built_not_run = compilou, mas a execução não foi verificada (sem gate do tipo, gate pulado, teto visual)
1371
+ // unverified = teto de correções esgotado SEM compilar/rodar de forma verificada
1372
+ // no_gate = tarefa não-compilável (análise/relatório/config) — não havia o que verificar
1373
+ function verificationLabel(ver, lang) {
1374
+ const en = lang === 'en';
1375
+ switch (ver) {
1376
+ case 'verified': return { icon: '✓', txt: en ? 'verified (build + run)' : 'verificada (build + execução)', ok: true };
1377
+ case 'built_not_run': return { icon: '≈', txt: en ? 'build OK — run NOT verified' : 'build OK — execução NÃO verificada', ok: false };
1378
+ case 'unverified': return { icon: '⚠', txt: en ? 'NOT verified (fix limit reached)' : 'NÃO verificada (teto de correções atingido)', ok: false };
1379
+ case 'no_gate': return { icon: '·', txt: en ? 'no build/run gate for this task' : 'sem gate de build/execução p/ esta tarefa', ok: true };
1380
+ default: return { icon: '·', txt: en ? 'not applicable' : 'não aplicável', ok: true };
1381
+ }
1382
+ }
1383
+
1384
+ module.exports = { webRunGate, run, load, notify, stateFile, detectBuild, ensureToolchain, runBuild, escalate, designPhase, archPhase, looksVisual, looksComplex, runApp, visualGate, ensureEmulator, _projKind, _llmVision, verificationLabel };
package/lib/tools.js CHANGED
@@ -522,7 +522,7 @@ async function execute(name, input, opts = {}) {
522
522
  const k = Math.min(15, Math.max(1, Number(input.max) || 6));
523
523
  const hits = ix.search(baseDir, consulta, k, idx);
524
524
  if (!hits.length) return { resultados: [], aviso: 'nada relevante no índice — tente outros termos, ou rode "ts indexar" se o projeto mudou muito.' };
525
- return { resultados: hits.map(h => ({ arquivo: h.file, linhas: h.l0 + '-' + h.l1, score: h.score, previa: h.snippet })), ...(construiu ? { nota: 'índice construído agora (' + idx.N + ' trechos)' } : {}) };
525
+ return { resultados: hits.map(h => ({ arquivo: h.file, linhas: h.l0 + '-' + h.l1, score: h.score, ...(h.sig && h.sig.length ? { define: h.sig } : {}), previa: h.snippet })), ...(construiu ? { nota: 'índice construído agora (' + idx.N + ' trechos)' } : {}) };
526
526
  }
527
527
  case 'buscar_web': {
528
528
  const q = String(input.consulta || '').trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminal-smart-cli",
3
- "version": "0.60.0",
3
+ "version": "0.62.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"