terminal-smart-cli 0.65.0 → 0.66.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 CHANGED
@@ -1183,6 +1183,14 @@ async function metaCmd() {
1183
1183
  const intervaloMin = flagNum('--intervalo', 5); // min de espera entre janelas ao aguardar crédito
1184
1184
  // Anti-loop-infinito: se ninguém definiu teto, cai num limite de janelas seguro.
1185
1185
  const maxJanelasEff = maxJanelas || ((budgetTotal || maxHoras) ? 0 : 20);
1186
+ // CRITÉRIOS EXECUTÁVEIS (verify): --criterios <arquivo.json> = a PROVA de que a missão
1187
+ // cumpriu o pedido (não basta compilar/abrir). Falhou → missão sai "NÃO verificada".
1188
+ let criteria = [];
1189
+ const _critFile = (() => { const i = rawArgs.findIndex(a => a === '--criterios' || a === '--criteria'); return i >= 0 ? rawArgs[i + 1] : null; })();
1190
+ if (_critFile) {
1191
+ try { const j = JSON.parse(require('fs').readFileSync(_critFile, 'utf8')); criteria = Array.isArray(j) ? j : (j.criteria || []); }
1192
+ catch (e) { console.error(ui.errLine((cfg.lang === 'en' ? 'criteria file: ' : 'arquivo de critérios: ') + (e.message || e))); process.exit(2); }
1193
+ }
1186
1194
 
1187
1195
  const existing = metaMod.load(dir);
1188
1196
  if (FLAGS.has('--status')) {
@@ -1229,7 +1237,7 @@ async function metaCmd() {
1229
1237
  const goalArg = janela === 1 ? (goal || null) : null; // janelas seguintes só retomam
1230
1238
  try {
1231
1239
  st = await metaMod.run(goalArg, {
1232
- token, lang: cfg.lang || 'pt', yes, budget, maxRounds, dir, model: forcedModel, thinker, maxMinutes, designer, design, eye, visualLadder, mockup, arch,
1240
+ token, lang: cfg.lang || 'pt', yes, budget, maxRounds, dir, model: forcedModel, thinker, maxMinutes, designer, design, eye, visualLadder, mockup, arch, criteria,
1233
1241
  onAlert: ({ type, text }) => {
1234
1242
  sp.stop();
1235
1243
  const ic = type === 'human' ? C.warn('🙋') : type === 'escalate' ? C.indigo('🧠') : type === 'stagnated' ? C.err('🛑') : type === 'design' ? C.cyan('🎨') : type === 'retry' || type === 'conn' ? C.warn('📡') : C.warn('⏱');
@@ -1304,6 +1312,11 @@ async function metaCmd() {
1304
1312
  const _vtag = (_vl.ok ? C.ok : C.warn)(` · ${_vl.icon} ${_vl.txt}`);
1305
1313
  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));
1306
1314
  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() + ')' : '')));
1315
+ // Evidence Ledger da missão: mostra cada critério executável provado/falho.
1316
+ if (st.verifyReport && st.verifyReport.total) {
1317
+ console.log(' ' + C.dim((cfg.lang === 'en' ? 'Criteria: ' : 'Critérios: ') + st.verifyReport.passed + '/' + st.verifyReport.total));
1318
+ for (const r of st.verifyReport.results) console.log(' ' + (r.ok ? C.ok('✔') : C.err('✗')) + ' ' + C.dim((r.label || '') + (r.ok ? '' : ' — ' + (r.detail || ''))));
1319
+ }
1307
1320
  metaMod.notify(token, T.meta_notify_done(st.goal, done, st.creditsSpent) + (_vl.ok ? '' : `\n⚠️ ${_vl.txt}`));
1308
1321
  } else if (st.pause_reason === 'awaiting_human' && st.humanRequest) {
1309
1322
  console.log(ui.infoLine(C.bold('🙋 Preciso de você: ') + st.humanRequest.motivo));
package/lib/i18n.js CHANGED
@@ -43,6 +43,7 @@ const STR = {
43
43
  ['ts agente --continuar "..."', 'retoma o trabalho anterior desta pasta'],
44
44
  ['ts agente "..." --navegador', 'EXPERIMENTAL: dá um Chrome real ao agente (abrir/ler/clicar/print+visão)'],
45
45
  ['ts meta "objetivo grande"', 'MISSÃO: checklist + rodadas até terminar (noturno)'],
46
+ ['ts meta "..." --criterios prova.json', 'só declara "verificada" se os critérios executáveis (verify) passarem de verdade'],
46
47
  ['ts meta --status', 'estado da missão deste diretório'],
47
48
  ['ts eval suite.json', 'avalia o agente numa suíte de casos (juiz de IA + nota)'],
48
49
  ['ts verificar --cmd "npm test" --url ... --porta N', 'PROVA determinística de conclusão (build/http/porta/arquivo); exit 1 pra CI'],
package/lib/meta.js CHANGED
@@ -1001,6 +1001,20 @@ async function makeChecklist(goal, token) {
1001
1001
  * onStep/askApprove/onRemote (repassados pro agente)
1002
1002
  * Retorna o estado final {status: done|paused, ...}.
1003
1003
  */
1004
+ // CRITÉRIOS EXECUTÁVEIS (verify): a prova FINAL da missão. Rodados quando os gates de
1005
+ // build/run passam, ANTES de declarar 'verified'. Se algum critério do usuário falha, a
1006
+ // missão NÃO é verificada (honestidade — não basta compilar/abrir; tem que CUMPRIR o pedido).
1007
+ // Sem critérios → nada a provar (retorna true). runAll nunca lança.
1008
+ async function _checkCriteria(st, dir) {
1009
+ if (!st.criteria || !st.criteria.length) return true;
1010
+ try {
1011
+ const rep = await require('./verify').runAll(st.criteria, { cwd: dir });
1012
+ st.verifyReport = { passed: rep.passed, total: rep.total, allOk: rep.allOk, results: rep.results.map(r => ({ ok: r.ok, label: r.label, detail: r.detail })) };
1013
+ if (!rep.allOk) st.runNote = (st.runNote || '') + ` critérios: ${rep.passed}/${rep.total} passaram · falharam: ${rep.results.filter(r => !r.ok).map(r => r.label).slice(0, 3).join(' | ')}`;
1014
+ return rep.allOk;
1015
+ } catch (_) { return true; }
1016
+ }
1017
+
1004
1018
  async function run(goal, opts = {}) {
1005
1019
  const { token, lang = 'pt', yes = false, budget = 400, maxRounds = 20, dir = process.cwd(), model = null, thinker = null, maxMinutes = 0, designer = null, design = 'auto', runGate = true, eye = null, visualLadder = true } = opts;
1006
1020
  const onChecklist = opts.onChecklist || (() => {});
@@ -1043,7 +1057,7 @@ async function run(goal, opts = {}) {
1043
1057
  }
1044
1058
  const mk = await makeChecklist(goal + (designBrief ? '\n\n[Há um DESIGN SYSTEM definido — o checklist deve refletir a aplicação desse visual]' : '') + (archBrief ? '\n\n[Há um CONTRATO DE ARQUITETURA definido — os itens devem seguir os componentes/arquivos dele]' : ''), token);
1045
1059
  st = { goal: String(goal).slice(0, 4000), mockup: opts.mockup || null, archBrief, feasBrief, checklist: mk.itens, rounds: [], creditsSpent: (mk.credits || 0) + designCred + archCred + feasCred,
1046
- budget, maxRounds, status: 'running', model: model || null, designBrief: designBrief || null, created_at: new Date().toISOString() };
1060
+ budget, maxRounds, status: 'running', model: model || null, designBrief: designBrief || null, criteria: Array.isArray(opts.criteria) ? opts.criteria : [], created_at: new Date().toISOString() };
1047
1061
  save(st, dir);
1048
1062
  } else {
1049
1063
  st.status = 'running';
@@ -1126,9 +1140,9 @@ async function run(goal, opts = {}) {
1126
1140
  // Aprovado: impecável OU só com nitpicks cosméticos (não vale queimar rodada cara).
1127
1141
  st.visualOk = true;
1128
1142
  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.verification = 'verified'; st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1143
+ st.verification = (await _checkCriteria(st, dir)) ? 'verified' : 'unverified'; st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1130
1144
  }
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; }
1145
+ } else { st.visualOk = true; st.verification = (await _checkCriteria(st, dir)) ? 'verified' : 'unverified'; st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st; }
1132
1146
  } else {
1133
1147
  // CRASHOU ao abrir → trata como erro pro executor corrigir (loop igual ao build)
1134
1148
  st.buildFixes = (st.buildFixes || 0) + 1;
@@ -1143,7 +1157,8 @@ async function run(goal, opts = {}) {
1143
1157
  let wg = { ok: true }; try { wg = await webRunGate(b, { token, eye, eyeGate: !!eye && (st.visualFixes || 0) < MAX_VISUAL_FIXES }); } catch (_) {}
1144
1158
  st.creditsSpent += wg.credits || 0;
1145
1159
  if (wg.ok) {
1146
- st.buildVerified = true; st.runVerified = true; st.visualOk = true; st.verification = 'verified';
1160
+ st.buildVerified = true; st.runVerified = true; st.visualOk = true;
1161
+ st.verification = (await _checkCriteria(st, dir)) ? 'verified' : 'unverified';
1147
1162
  if (wg.shot) st.webShot = wg.shot;
1148
1163
  st.status = 'done'; st.finished_at = new Date().toISOString(); save(st, dir); onRoundDone({ checklist: st.checklist, spent: st.creditsSpent }); return st;
1149
1164
  } else {
@@ -1381,4 +1396,4 @@ function verificationLabel(ver, lang) {
1381
1396
  }
1382
1397
  }
1383
1398
 
1384
- module.exports = { webRunGate, run, load, notify, stateFile, detectBuild, ensureToolchain, runBuild, escalate, designPhase, archPhase, looksVisual, looksComplex, runApp, visualGate, ensureEmulator, _projKind, _llmVision, verificationLabel };
1399
+ module.exports = { webRunGate, run, load, notify, stateFile, detectBuild, ensureToolchain, runBuild, escalate, designPhase, archPhase, looksVisual, looksComplex, runApp, visualGate, ensureEmulator, _projKind, _llmVision, verificationLabel, _checkCriteria };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminal-smart-cli",
3
- "version": "0.65.0",
3
+ "version": "0.66.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"