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 +6 -1
- package/bin/ts.js +7 -4
- package/lib/agent.js +12 -4
- package/lib/core.js +54 -0
- package/lib/indice.js +0 -0
- package/lib/meta.js +32 -10
- package/lib/tools.js +1 -1
- package/package.json +1 -1
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
|
|
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
|
-
|
|
1308
|
-
|
|
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
|
-
//
|
|
653
|
-
//
|
|
654
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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):
|
|
1184
|
-
|
|
1185
|
-
st.status = 'done';
|
|
1186
|
-
st.
|
|
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
|
-
|
|
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();
|