terminal-smart-cli 0.97.30 → 0.97.41
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 +56 -17
- package/lib/agent.js +196 -31
- package/lib/conversation-scope.js +21 -0
- package/lib/intelligence-core.js +19 -10
- package/lib/meta.js +300 -44
- package/lib/tools.js +32 -1
- package/lib/verify.js +14 -1
- package/package.json +2 -2
package/lib/tools.js
CHANGED
|
@@ -39,6 +39,18 @@ function _snapshot(absPath) {
|
|
|
39
39
|
// pra compatibilidade (tools.isDestructive segue funcionando pra quem já importava).
|
|
40
40
|
const { isDestructive } = require('./core');
|
|
41
41
|
|
|
42
|
+
// `findstr`, `rg` e `grep` usam o código 1 para informar que a busca foi
|
|
43
|
+
// executada corretamente, mas não encontrou ocorrências. Para o harness isso
|
|
44
|
+
// é evidência de inspeção (por exemplo: confirmar que um texto antigo já não
|
|
45
|
+
// existe), e não uma falha operacional que justifique repetir a mesma ação.
|
|
46
|
+
function _isReadOnlySearchNoMatch(command, code, stdout, stderr) {
|
|
47
|
+
if (Number(code) !== 1 || String(stdout || '').trim() || String(stderr || '').trim()) return false;
|
|
48
|
+
const executable = String(command || '')
|
|
49
|
+
.trim()
|
|
50
|
+
.replace(/^\s*cd\s+(?:\/d\s+)?(?:"[^"]+"|'[^']+'|[^&|]+)\s*(?:&&|&)\s*/i, '');
|
|
51
|
+
return /^(?:findstr|rg|grep)\b/i.test(executable);
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
// Conteúdo de e-mail/site/arquivo pode tentar convencer o modelo a mandar
|
|
43
55
|
// segredos para fora. O prompt ajuda, mas a defesa precisa existir também no
|
|
44
56
|
// executor: se um comando combina transporte de rede com fonte sensível, ele
|
|
@@ -523,6 +535,15 @@ function _commandScopeViolation(cmd, confineDir) {
|
|
|
523
535
|
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(m[1])) candidates.push(m[1]);
|
|
524
536
|
}
|
|
525
537
|
for (const raw of candidates) {
|
|
538
|
+
// No CMD do Windows, `cd /d C:\\projeto` usa /d como um modificador
|
|
539
|
+
// (troca também a unidade atual), não como caminho Unix absoluto. Sem
|
|
540
|
+
// esta exceção o confinamento recusava uma mudança de pasta totalmente
|
|
541
|
+
// interna antes de o comando chegar ao shell.
|
|
542
|
+
// Opções do CMD também podem ter dois-pontos, por exemplo
|
|
543
|
+
// `findstr /c:"texto"`. Não são caminhos Unix nem tentativas de escapar da
|
|
544
|
+
// raiz. Sem esta exceção uma busca contendo `</script>` era lida como
|
|
545
|
+
// redirecionamento e o `/c:` seguinte virava um falso caminho externo.
|
|
546
|
+
if (process.platform === 'win32' && /^\/[a-z](?::|$)/i.test(raw)) continue;
|
|
526
547
|
const abs = path.resolve(root, raw);
|
|
527
548
|
if (!_scopeContains(root, abs)) {
|
|
528
549
|
return `CAPABILITY_DENIED: comando mutante referencia "${raw}", fora da raiz autorizada "${root}".`;
|
|
@@ -653,6 +674,11 @@ async function execute(name, input, opts = {}) {
|
|
|
653
674
|
}
|
|
654
675
|
const _outsideScope = (p) => {
|
|
655
676
|
if (!opts.confineDir) return false;
|
|
677
|
+
// Uma skill só pode ser lida fora do projeto se o chamador a tiver
|
|
678
|
+
// explicitamente anunciado nesta rodada. Isso permite seguir uma skill
|
|
679
|
+
// instalada sem transformar ~/.ts, ~/.codex etc. em acesso geral.
|
|
680
|
+
if (name === 'ler_arquivo' && Array.isArray(opts.trustedReadPaths)
|
|
681
|
+
&& opts.trustedReadPaths.some(allowed => path.resolve(String(allowed)) === path.resolve(String(p)))) return false;
|
|
656
682
|
return !_scopeContains(opts.confineDir, p);
|
|
657
683
|
};
|
|
658
684
|
const _scopeError = (p) => ({ erro: `CAPABILITY_DENIED: "${path.resolve(p)}" está fora da raiz autorizada "${path.resolve(opts.confineDir)}".` });
|
|
@@ -685,6 +711,11 @@ async function execute(name, input, opts = {}) {
|
|
|
685
711
|
// B18: mascara chave/token ANTES de virar contexto do modelo e linha de log.
|
|
686
712
|
const _rd = require('./core').redactSecrets;
|
|
687
713
|
const r = { stdout: _rd(c.out), stderr: _rd(compactor.stripAnsi(err || '').slice(0, 1500)), codigo: e?.code ?? 0 };
|
|
714
|
+
if (_isReadOnlySearchNoMatch(comandoExecutado, r.codigo, r.stdout, r.stderr)) {
|
|
715
|
+
r.codigo = 0;
|
|
716
|
+
r.no_match = true;
|
|
717
|
+
r.stdout = 'Nenhuma ocorrência encontrada.';
|
|
718
|
+
}
|
|
688
719
|
if (c.note) r.aviso = c.note;
|
|
689
720
|
if (normalized) r.normalizado = normalized.note;
|
|
690
721
|
if (!r.stdout.trim() && !r.stderr.trim() && r.codigo === 0 && /python3? -c/.test(comando) && comando.includes('\n'))
|
|
@@ -1165,4 +1196,4 @@ async function execute(name, input, opts = {}) {
|
|
|
1165
1196
|
}
|
|
1166
1197
|
|
|
1167
1198
|
module.exports = { DEFS, execute, isDestructive, selfDestructiveReason, secretExfiltrationReason, buildProjectMap,
|
|
1168
|
-
_test: { shellGotcha: _shellGotcha, normalizeWindowsReadOnlyCommand: _normalizeWindowsReadOnlyCommand } };
|
|
1199
|
+
_test: { shellGotcha: _shellGotcha, normalizeWindowsReadOnlyCommand: _normalizeWindowsReadOnlyCommand, commandScopeViolation: _commandScopeViolation, isReadOnlySearchNoMatch: _isReadOnlySearchNoMatch } };
|
package/lib/verify.js
CHANGED
|
@@ -17,8 +17,21 @@ function vCommand(c, cwd) {
|
|
|
17
17
|
const want = c.exit != null ? Number(c.exit) : 0;
|
|
18
18
|
try {
|
|
19
19
|
const out = execSync(c.cmd, { cwd, encoding: 'utf8', timeout: (c.timeout_s || 120) * 1000, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });
|
|
20
|
+
const output = String(out || '');
|
|
21
|
+
// Um script como `echo "No tests yet" && exit 0` não é uma prova de saúde.
|
|
22
|
+
// Para critérios que afirmam rodar testes, trate explicitamente essa saída
|
|
23
|
+
// como falha, mesmo que o processo tenha saído com código zero.
|
|
24
|
+
const isTestCommand = /(^|\s)(npm\s+test|pnpm\s+test|yarn\s+test|node\s+.*test)/i.test(String(c.cmd || ''));
|
|
25
|
+
const noTests = /\b(no tests? yet|no tests? (?:found|run)|0 tests? (?:found|run))\b/i.test(output);
|
|
26
|
+
if (want === 0 && isTestCommand && noTests) {
|
|
27
|
+
return { ok: false, detail: 'teste sem casos executados (falso positivo)', errorClass: 'verification_failed', evidence: output.slice(-200).replace(/\s+/g, ' ') };
|
|
28
|
+
}
|
|
29
|
+
const reportedFailure = /(^|\n)\s*(?:✗|FAIL(?:\s|:|$)|AssertionError\b)/im.test(output);
|
|
30
|
+
if (want === 0 && isTestCommand && reportedFailure) {
|
|
31
|
+
return { ok: false, detail: 'teste reportou falha apesar de exit 0 (falso positivo)', errorClass: 'verification_failed', evidence: output.slice(-300).replace(/\s+/g, ' ') };
|
|
32
|
+
}
|
|
20
33
|
const ok = want === 0;
|
|
21
|
-
return { ok, detail: ok ? 'exit 0' : `exit 0 mas esperava ${want}`, evidence:
|
|
34
|
+
return { ok, detail: ok ? 'exit 0' : `exit 0 mas esperava ${want}`, evidence: output.slice(-200).replace(/\s+/g, ' ') };
|
|
22
35
|
} catch (e) {
|
|
23
36
|
const code = typeof e.status === 'number' ? e.status : 1;
|
|
24
37
|
const ok = code === want;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminal-smart-cli",
|
|
3
|
-
"version": "0.97.
|
|
3
|
+
"version": "0.97.41",
|
|
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"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
|
-
"test": "node test/core.test.js && node test/windows-shell-normalization.test.js && node test/gateways.test.js && node test/agent-recovery-guard.test.js && node test/agent-plan-model-contract.test.js && node test/agent-mission-limits.test.js && node test/agent-external-approval.test.js && node test/agent-prompt-injection.test.js && node test/file-concurrency.test.js && node test/mission-observability.test.js && node test/audit-packs.test.js && node test/intelligence-core.test.js && node test/cloud-slug.test.js && node test/eval-model.test.js && node test/project-cache.test.js && node test/memory-bus.test.js && node test/capabilities.test.js && node test/mcp-e2e.test.js && node test/erros.test.js && node test/evolution-telemetry.test.js && node test/owner-audit.test.js && node test/capability-pack.test.js && node test/video-generation.test.js && node test/image-job.test.js && node test/byok.test.js && node test/conhecimento.test.js && node test/policy.test.js && node test/temas.test.js && node test/skill-index.test.js && node test/doctor.test.js && node test/google-workspace-tools.test.js && node test/office-editors.test.js"
|
|
9
|
+
"test": "node test/core.test.js && node test/conversation-scope.test.js && node test/windows-shell-normalization.test.js && node test/gateways.test.js && node test/agent-recovery-guard.test.js && node test/agent-plan-model-contract.test.js && node test/agent-mission-limits.test.js && node test/agent-external-approval.test.js && node test/agent-prompt-injection.test.js && node test/file-concurrency.test.js && node test/mission-observability.test.js && node test/audit-packs.test.js && node test/intelligence-core.test.js && node test/cloud-slug.test.js && node test/eval-model.test.js && node test/project-cache.test.js && node test/memory-bus.test.js && node test/capabilities.test.js && node test/mcp-e2e.test.js && node test/erros.test.js && node test/evolution-telemetry.test.js && node test/owner-audit.test.js && node test/capability-pack.test.js && node test/video-generation.test.js && node test/image-job.test.js && node test/byok.test.js && node test/conhecimento.test.js && node test/policy.test.js && node test/temas.test.js && node test/skill-index.test.js && node test/doctor.test.js && node test/google-workspace-tools.test.js && node test/office-editors.test.js"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"bin",
|