terminal-smart-cli 0.97.58 → 0.97.62
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 +7 -3
- package/lib/agent.js +22 -2
- package/lib/tools.js +9 -0
- package/package.json +2 -2
package/bin/ts.js
CHANGED
|
@@ -243,7 +243,9 @@ async function personalAiCmd(args = []) {
|
|
|
243
243
|
if (sub === 'status') return show(await api('/api/personal-ai/status',{token}));
|
|
244
244
|
if (['usar','use','modo','mode'].includes(sub)) {
|
|
245
245
|
const mode=String(args[1] || '').toLowerCase();
|
|
246
|
-
const state=await api('/api/personal-ai/mode',{method:'POST',token,body:{mode}});
|
|
246
|
+
const state=await api('/api/personal-ai/mode',{method:'POST',token,body:{mode}});
|
|
247
|
+
cfg = config.save({ forceTsCloud: mode === 'automatico' ? true : undefined });
|
|
248
|
+
show(state); return;
|
|
247
249
|
}
|
|
248
250
|
if (['desconectar','disconnect'].includes(sub)) {
|
|
249
251
|
const provider=String(args[1] || '').toLowerCase();
|
|
@@ -1510,7 +1512,7 @@ async function agentCmd(words, { askFn, cwd: cwdIn = null, onCwd = null, maxIter
|
|
|
1510
1512
|
} });
|
|
1511
1513
|
if (shared?.ok && shared.promptBlock) sharedChannelPrompt = shared.promptBlock;
|
|
1512
1514
|
const personalState = await api('/api/personal-ai/status', { token });
|
|
1513
|
-
const personalReady = personalState?.ok && personalState.mode !== 'automatico'
|
|
1515
|
+
const personalReady = !cfg.forceTsCloud && personalState?.ok && personalState.mode !== 'automatico'
|
|
1514
1516
|
&& (personalState.mode === 'chatgpt' ? personalState.chatgpt
|
|
1515
1517
|
: personalState.mode === 'claude' ? personalState.claude
|
|
1516
1518
|
: personalState.chatgpt && personalState.claude);
|
|
@@ -2871,6 +2873,7 @@ async function conectarCmd(words) {
|
|
|
2871
2873
|
// ts conectar nuvem — volta a usar os créditos do TS
|
|
2872
2874
|
if (sub === 'nuvem' || sub === 'cloud' || sub === 'ts') {
|
|
2873
2875
|
keyring.usar(null);
|
|
2876
|
+
cfg = config.save({ forceTsCloud: true });
|
|
2874
2877
|
console.log(' ' + C.ok('✔ ') + (en ? 'back to TS Cloud (your credits).' : 'de volta ao TS Cloud (seus créditos).'));
|
|
2875
2878
|
return;
|
|
2876
2879
|
}
|
|
@@ -3068,8 +3071,9 @@ async function siteCmd(args) {
|
|
|
3068
3071
|
const prompt = rest.join(' ').trim();
|
|
3069
3072
|
const editing = ['editar', 'edit', 'alterar', 'update'].includes(sub);
|
|
3070
3073
|
if (!slug || !prompt) return console.log(ui.errLine(`uso: ts site ${editing ? 'editar' : 'criar'} <nome> "<descreva ${editing ? 'a alteração' : 'o site'} em linguagem natural>"`));
|
|
3074
|
+
if (!FLAGS.has('--confirmar')) return console.log(ui.errLine(`Publicação não executada. Revise o pedido e repita com --confirmar: ts site ${editing ? 'editar' : 'criar'} <nome> "<descrição>" --confirmar`));
|
|
3071
3075
|
console.log(C.dim(editing ? 'carregando, alterando e republicando o site…' : 'criando e publicando o site…'));
|
|
3072
|
-
const r = await api('/api/sites/generate', { token, method: 'POST', body: { slug, prompt }, timeoutMs: 240000 });
|
|
3076
|
+
const r = await api('/api/sites/generate', { token, method: 'POST', body: { slug, prompt, confirmed: true }, timeoutMs: 240000 });
|
|
3073
3077
|
if (!r.ok) return console.log(ui.errLine(r.error || r.message || 'não foi possível criar o site'));
|
|
3074
3078
|
if (JSON_OUT) return console.log(JSON.stringify(r));
|
|
3075
3079
|
console.log('\n' + ui.box([
|
package/lib/agent.js
CHANGED
|
@@ -204,7 +204,7 @@ function modelCallCap(personalSubscription = false, complexTask = false) {
|
|
|
204
204
|
function explicitExclusiveFileTargets(task, cwd) {
|
|
205
205
|
const text = String(task || '');
|
|
206
206
|
const targets = [];
|
|
207
|
-
const pattern = /\b(?:somente|apenas)\s+(?:o\s+arquivo\s+)?["'`]?([^\s,"'`]+\.[a-z0-9]{1,12})["'`]?/gi;
|
|
207
|
+
const pattern = /\b(?:somente|apenas)\s+(?:o\s+arquivo\s+)?(?:existente\s+)?["'`]?([^\s,"'`]+\.[a-z0-9]{1,12})["'`]?/gi;
|
|
208
208
|
for (const match of text.matchAll(pattern)) {
|
|
209
209
|
const raw = String(match[1] || '').replace(/[.;:!?]+$/, '');
|
|
210
210
|
if (raw) targets.push(path.resolve(cwd, raw));
|
|
@@ -835,6 +835,25 @@ function loopSig(name, input) {
|
|
|
835
835
|
}
|
|
836
836
|
|
|
837
837
|
const FILE_MUTATORS = new Set(['escrever_arquivo', 'editar_arquivo', 'editar_documento', 'editar_planilha']);
|
|
838
|
+
function normalizeFileToolInput(name, input, { cwd = process.cwd(), exclusiveTargets = [] } = {}) {
|
|
839
|
+
const out = input && typeof input === 'object' ? Object.assign({}, input) : {};
|
|
840
|
+
if (!FILE_MUTATORS.has(name)) return out;
|
|
841
|
+
const alias = out.caminho || out.path || out.arquivo || out.file || out.filename;
|
|
842
|
+
if (alias && String(alias).trim() && String(alias).trim() !== '.') {
|
|
843
|
+
out.caminho = alias;
|
|
844
|
+
} else if (exclusiveTargets.length === 1) {
|
|
845
|
+
out.caminho = path.relative(cwd, exclusiveTargets[0]) || exclusiveTargets[0];
|
|
846
|
+
}
|
|
847
|
+
if (name === 'escrever_arquivo' && !Object.prototype.hasOwnProperty.call(out, 'conteudo')) {
|
|
848
|
+
const contentAlias = out.content ?? out.contents ?? out.text ?? out.body;
|
|
849
|
+
if (contentAlias !== undefined) out.conteudo = contentAlias;
|
|
850
|
+
}
|
|
851
|
+
if (name === 'editar_arquivo') {
|
|
852
|
+
if (!Object.prototype.hasOwnProperty.call(out, 'buscar')) out.buscar = out.search ?? out.find ?? out.oldText;
|
|
853
|
+
if (!Object.prototype.hasOwnProperty.call(out, 'substituir')) out.substituir = out.replace ?? out.replacement ?? out.newText;
|
|
854
|
+
}
|
|
855
|
+
return out;
|
|
856
|
+
}
|
|
838
857
|
function mutationBatchConflicts(toolCalls, cwd) {
|
|
839
858
|
const groups = new Map();
|
|
840
859
|
for (const tc of (Array.isArray(toolCalls) ? toolCalls : [])) {
|
|
@@ -1812,6 +1831,7 @@ async function run(task, opts = {}) {
|
|
|
1812
1831
|
for (const tc of tcs) {
|
|
1813
1832
|
const name = (tc.function && tc.function.name) || '';
|
|
1814
1833
|
let input = {}; try { input = JSON.parse((tc.function && tc.function.arguments) || '{}'); } catch (_) {}
|
|
1834
|
+
input = normalizeFileToolInput(name, input, { cwd, exclusiveTargets: _exclusiveFileTargets });
|
|
1815
1835
|
let result;
|
|
1816
1836
|
let _cachedContent = '';
|
|
1817
1837
|
let _ran = false; // true só quando uma ferramenta REALMENTE executou (não gate/bloqueio) → status ✓/✗
|
|
@@ -2514,4 +2534,4 @@ async function run(task, opts = {}) {
|
|
|
2514
2534
|
return { text: finalText, steps, credits: charged + _visionCredits, tokens: acc, model: usedModel, actions, messages, cwd, context: lastCtx, toolErrors: _toolErrs, lastToolError: _lastErr, guard: guardStopped, completion, verification: verifyReport, observability: _observability, report: _finalReport, orchestration: { plan: _planDecision, roles: _roleTrace, inspections: _inspectionTrace, phaseBudgets: _phaseBudgets, phaseUsage: _phaseUsage }, missionCache: _missionCache.stats() };
|
|
2515
2535
|
}
|
|
2516
2536
|
|
|
2517
|
-
module.exports = { run, llm, _test: { systemPrompt, projectBrief, inspectionGateDecision, independentInspectorDecision, candidateAdmitsIncomplete, isInspectionCommand, parseStageJson, materialDecisionPreflight, actionExpectedForTask, requiresActionEvidence, shouldRunPlanner, isComplexTask, validatePlannerDecision, planUpgradeLimit, commandRecoveryHint, windowsUnsupportedUnixCommand, mutationBatchConflicts, normalizePlannerDecision, normalizeInspectorDecision, winFor, estMsgsTok, COMPACT_AT, KEEP_TAIL, loopSig, isCycle, loopDecision, decideApproval, failureFingerprint, missionGuardDecision, missionBudgetSuggestion, missionTokenCap, missionTimeCap, modelCallWindow, modelCallCap, explicitExclusiveFileTargets, executorFallbackChain, forcedModelMismatch, isTransientModelError, executorCompletionCap, completionGateDecision, canCloseFromProofs, taskScopedToolDefs, explicitTaskWorkdir, restrictedGatewayDecision, validarModeloByok, scopeToolDefs, parseTextToolCalls, isUntrustedToolOutput, untrustedToolEnvelope, isRemoteDeployCommand, browserApprovalRequest } };
|
|
2537
|
+
module.exports = { run, llm, _test: { systemPrompt, projectBrief, inspectionGateDecision, independentInspectorDecision, candidateAdmitsIncomplete, isInspectionCommand, parseStageJson, materialDecisionPreflight, actionExpectedForTask, requiresActionEvidence, shouldRunPlanner, isComplexTask, validatePlannerDecision, planUpgradeLimit, commandRecoveryHint, windowsUnsupportedUnixCommand, mutationBatchConflicts, normalizeFileToolInput, normalizePlannerDecision, normalizeInspectorDecision, winFor, estMsgsTok, COMPACT_AT, KEEP_TAIL, loopSig, isCycle, loopDecision, decideApproval, failureFingerprint, missionGuardDecision, missionBudgetSuggestion, missionTokenCap, missionTimeCap, modelCallWindow, modelCallCap, explicitExclusiveFileTargets, executorFallbackChain, forcedModelMismatch, isTransientModelError, executorCompletionCap, completionGateDecision, canCloseFromProofs, taskScopedToolDefs, explicitTaskWorkdir, restrictedGatewayDecision, validarModeloByok, scopeToolDefs, parseTextToolCalls, isUntrustedToolOutput, untrustedToolEnvelope, isRemoteDeployCommand, browserApprovalRequest } };
|
package/lib/tools.js
CHANGED
|
@@ -799,6 +799,12 @@ async function execute(name, input, opts = {}) {
|
|
|
799
799
|
return { total: resultados.length, resultados, aviso: resultados.length < arquivos.length ? 'Lote limitado pelo teto de contexto; peca os trechos restantes em outro lote.' : undefined };
|
|
800
800
|
}
|
|
801
801
|
case 'escrever_arquivo': {
|
|
802
|
+
if (!input.caminho || !String(input.caminho).trim() || String(input.caminho).trim() === '.') {
|
|
803
|
+
return { erro: 'Informe o caminho completo do ARQUIVO em caminho (ex.: docs/relatorio.md). O diretório de trabalho sozinho não é um arquivo.' };
|
|
804
|
+
}
|
|
805
|
+
if (!Object.prototype.hasOwnProperty.call(input, 'conteudo')) {
|
|
806
|
+
return { erro: 'Informe o conteúdo do arquivo em conteudo. A escrita foi recusada para não apagar o arquivo com conteúdo ausente.' };
|
|
807
|
+
}
|
|
802
808
|
let p = _abs(input.caminho, baseDir);
|
|
803
809
|
{ const g = _guardTsHome(p); if (g) return { erro: g }; }
|
|
804
810
|
// Confinamento (missões): modelos fracos inventam pastas absolutas
|
|
@@ -832,6 +838,9 @@ async function execute(name, input, opts = {}) {
|
|
|
832
838
|
} finally { held.lock.release(); }
|
|
833
839
|
}
|
|
834
840
|
case 'editar_arquivo': {
|
|
841
|
+
if (!input.caminho || !String(input.caminho).trim() || String(input.caminho).trim() === '.') {
|
|
842
|
+
return { erro: 'Informe o caminho completo do ARQUIVO em caminho (ex.: docs/relatorio.md). O diretório de trabalho sozinho não é um arquivo.' };
|
|
843
|
+
}
|
|
835
844
|
// Edição por ÂNCORA (ideia do hashline do OMYP): troca SÓ o trecho buscado, sem
|
|
836
845
|
// reescrever o arquivo — modelo barato edita com precisão, gasta menos tokens de
|
|
837
846
|
// saída e não corre o risco de "perder" o resto do arquivo num rewrite.
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminal-smart-cli",
|
|
3
|
-
"version": "0.97.
|
|
3
|
+
"version": "0.97.62",
|
|
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/durable-operation.test.js && node test/mission-tool-cache.test.js && node test/content-quality-runtime-files.test.js && node test/personal-agent-llm.test.js && node test/personal-inspector-efficiency.test.js && node test/personal-inspector-context.test.js && node test/planner-fallback.test.js"
|
|
9
|
+
"test": "node test/durable-operation.test.js && node test/mission-tool-cache.test.js && node test/content-quality-runtime-files.test.js && node test/personal-agent-llm.test.js && node test/personal-inspector-efficiency.test.js && node test/personal-inspector-context.test.js && node test/planner-fallback.test.js && node test/cli-agent-regressions.test.js"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"bin",
|