terminal-smart-cli 0.97.46 → 0.97.47
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 +104 -7
- package/lib/agent.js +24 -4
- package/lib/intelligence-core.js +2 -2
- package/package.json +2 -2
package/bin/ts.js
CHANGED
|
@@ -104,6 +104,18 @@ function fail(e) {
|
|
|
104
104
|
process.exit(1);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
function providerCapacityHint(e) {
|
|
108
|
+
const message = String((e && e.message) || '');
|
|
109
|
+
if (!/openrouter\.ai\/settings\/credits|request requires more credits|can only afford|fewer max_tokens|available credits given your current in-flight requests|in-flight requests settle/i.test(message)) return '';
|
|
110
|
+
let active = null;
|
|
111
|
+
try { active = require('../lib/keyring').ativo(); } catch (_) {}
|
|
112
|
+
if (!active) return '';
|
|
113
|
+
const provider = active.provedor || active.id || 'provedor particular';
|
|
114
|
+
return cfg.lang === 'en'
|
|
115
|
+
? `Your own ${provider} key has insufficient provider balance/capacity. Terminal Smart plan credits were not consumed. Add balance at the provider or run \`ts conectar nuvem\` to use your TS plan.`
|
|
116
|
+
: `Sua chave própria do ${provider} está sem saldo/capacidade no provedor. Os créditos do plano Terminal Smart não foram consumidos. Recarregue o provedor ou rode \`ts conectar nuvem\` para usar o plano TS.`;
|
|
117
|
+
}
|
|
118
|
+
|
|
107
119
|
// ── Ajuda ────────────────────────────────────────────────────────────────────
|
|
108
120
|
function help() {
|
|
109
121
|
const out = [ui.banner(pkg.version, T.tagline)];
|
|
@@ -215,6 +227,57 @@ async function logout() {
|
|
|
215
227
|
console.log(ui.okLine(T.logout_ok));
|
|
216
228
|
}
|
|
217
229
|
|
|
230
|
+
// ── Planos pessoais ChatGPT / Claude (mesma conta do Telegram/Web/App) ──────
|
|
231
|
+
async function personalAiCmd(args = []) {
|
|
232
|
+
const token=needToken(); const en=cfg.lang === 'en'; const sub=String(args[0] || 'status').toLowerCase();
|
|
233
|
+
const label=p=>p === 'chatgpt' ? 'ChatGPT/Codex' : 'Claude';
|
|
234
|
+
const show=state=>{
|
|
235
|
+
if (JSON_OUT) { console.log(JSON.stringify(state)); return; }
|
|
236
|
+
console.log('\n' + ui.box([
|
|
237
|
+
`${en ? 'Mode' : 'Modo'}: ${state.mode || 'automatico'}`,
|
|
238
|
+
`ChatGPT/Codex: ${state.chatgpt ? 'conectado' : 'não conectado'}`,
|
|
239
|
+
`Claude: ${state.claude ? 'conectado' : 'não conectado'}`,
|
|
240
|
+
'', C.dim(en ? 'Personal subscriptions use 0 TS model credits.' : 'Assinaturas pessoais usam 0 créditos de modelo TS.'),
|
|
241
|
+
], { title:'IA da conta' }) + '\n');
|
|
242
|
+
};
|
|
243
|
+
if (sub === 'status') return show(await api('/api/personal-ai/status',{token}));
|
|
244
|
+
if (['usar','use','modo','mode'].includes(sub)) {
|
|
245
|
+
const mode=String(args[1] || '').toLowerCase();
|
|
246
|
+
const state=await api('/api/personal-ai/mode',{method:'POST',token,body:{mode}}); show(state); return;
|
|
247
|
+
}
|
|
248
|
+
if (['desconectar','disconnect'].includes(sub)) {
|
|
249
|
+
const provider=String(args[1] || '').toLowerCase();
|
|
250
|
+
const state=await api('/api/personal-ai/disconnect',{method:'POST',token,body:{provider}}); show(state); return;
|
|
251
|
+
}
|
|
252
|
+
if (['conectar','connect'].includes(sub)) {
|
|
253
|
+
const provider=String(args[1] || '').toLowerCase();
|
|
254
|
+
if (!['chatgpt','claude'].includes(provider)) throw new Error('Use: ts ia conectar chatgpt|claude');
|
|
255
|
+
const login=await api('/api/personal-ai/login/start',{method:'POST',token,body:{provider}});
|
|
256
|
+
if (login.alreadyConnected) return show(await api('/api/personal-ai/status',{token}));
|
|
257
|
+
console.log('\n' + ui.box([
|
|
258
|
+
login.url,
|
|
259
|
+
...(login.code ? ['', `${en ? 'Device code' : 'Código do aparelho'}: ${C.bold(login.code)}`] : []),
|
|
260
|
+
'', C.dim(en ? 'Open the official page and finish authorization.' : 'Abra a página oficial e conclua a autorização.'),
|
|
261
|
+
], { title:`Login ${label(provider)}` }) + '\n');
|
|
262
|
+
if (process.env.TS_NO_BROWSER !== '1') try {
|
|
263
|
+
const { exec }=require('child_process'); const command=process.platform === 'win32' ? `start "" "${login.url}"` : process.platform === 'darwin' ? `open "${login.url}"` : `xdg-open "${login.url}"`;
|
|
264
|
+
exec(command,()=>{});
|
|
265
|
+
} catch (_) {}
|
|
266
|
+
if (provider === 'claude' && process.stdin.isTTY) {
|
|
267
|
+
const code=String(await ui.ask(en ? 'Paste the code returned by Claude: ' : 'Cole o código devolvido pelo Claude: ')).trim();
|
|
268
|
+
if (code) await api('/api/personal-ai/login/code',{method:'POST',token,body:{provider,code}});
|
|
269
|
+
}
|
|
270
|
+
for (let i=0;i<240;i++) {
|
|
271
|
+
await new Promise(resolve=>setTimeout(resolve,2500));
|
|
272
|
+
const state=await api(`/api/personal-ai/login/status?provider=${provider}`,{token});
|
|
273
|
+
if (state.connected) { console.log(ui.okLine(`${label(provider)} ${en ? 'connected' : 'conectado'}.`)); return; }
|
|
274
|
+
if (state.state === 'failed' || state.state === 'expired') throw new Error(state.error || 'O login não foi concluído.');
|
|
275
|
+
}
|
|
276
|
+
throw new Error(en ? 'Login timed out.' : 'O login expirou.');
|
|
277
|
+
}
|
|
278
|
+
throw new Error('Use: ts ia status | conectar chatgpt|claude | usar automatico|chatgpt|claude|paralelo | desconectar chatgpt|claude');
|
|
279
|
+
}
|
|
280
|
+
|
|
218
281
|
// ── Chat ─────────────────────────────────────────────────────────────────────
|
|
219
282
|
// A conversa é isolada por pasta de trabalho. Assim o contexto continua quando
|
|
220
283
|
// alguém conversa no mesmo projeto, mas não vaza de um projeto para outro.
|
|
@@ -1403,6 +1466,28 @@ async function agentCmd(words, { askFn, cwd: cwdIn = null, onCwd = null, maxIter
|
|
|
1403
1466
|
};
|
|
1404
1467
|
const _liveTimer = (!_noTTY && !streamJson) ? setInterval(() => sp.text(_statusLine()), 1000) : null;
|
|
1405
1468
|
if (streamJson) _emit(core.AgentEvents.systemInit({ model: model || 'auto', cwd: startCwd, mode: plan ? 'plan' : readOnly ? 'ask' : 'agent' }));
|
|
1469
|
+
// Mesmo agente de projeto e mesmo fluxo usados no Telegram, Web e App.
|
|
1470
|
+
// É best-effort para o CLI continuar funcional durante indisponibilidade do backend.
|
|
1471
|
+
let sharedChannelPrompt = '';
|
|
1472
|
+
let sharedConversationId = null;
|
|
1473
|
+
try {
|
|
1474
|
+
sharedConversationId = await ensureConv(token, 'agent', startCwd);
|
|
1475
|
+
const shared = await api('/api/channel/resolve', { method:'POST', token, body:{
|
|
1476
|
+
surface:'cli', text:task, conversationId:sharedConversationId,
|
|
1477
|
+
} });
|
|
1478
|
+
if (shared?.ok && shared.promptBlock) sharedChannelPrompt = shared.promptBlock;
|
|
1479
|
+
const personal = await api('/api/personal-ai/respond', { method:'POST', token, body:{
|
|
1480
|
+
surface:'cli', text:task, conversationId:sharedConversationId,
|
|
1481
|
+
agentId:shared?.agent?.id || null, usageId:`cli-${sharedConversationId}-${Date.now()}`,
|
|
1482
|
+
} });
|
|
1483
|
+
if (personal?.ok && Array.isArray(personal.results) && personal.results.length) {
|
|
1484
|
+
const collaboration = personal.results.map(item =>
|
|
1485
|
+
`### ${item.provider === 'chatgpt' ? 'ChatGPT/Codex' : 'Claude'} (plano pessoal)\n${String(item.text || '').slice(0, 12000)}`
|
|
1486
|
+
).join('\n\n');
|
|
1487
|
+
sharedChannelPrompt += `\n\nPLANEJAMENTO/REVISÃO DE MODELOS PESSOAIS (valide com ferramentas locais antes de afirmar execução):\n${collaboration}`;
|
|
1488
|
+
if (!streamJson) _hlog(' ' + C.dim(`IA pessoal: ${personal.results.map(item => item.provider === 'chatgpt' ? 'ChatGPT/Codex' : 'Claude').join(' + ')} · 0 créditos TS`));
|
|
1489
|
+
}
|
|
1490
|
+
} catch (_) {}
|
|
1406
1491
|
let out;
|
|
1407
1492
|
try {
|
|
1408
1493
|
// --passos N (ou --steps): quantas iterações o agente pode fazer numa run (default 15, teto 120).
|
|
@@ -1417,6 +1502,7 @@ async function agentCmd(words, { askFn, cwd: cwdIn = null, onCwd = null, maxIter
|
|
|
1417
1502
|
const _maxTokens = _tki >= 0 ? Number(process.argv[_tki + 1]) : _inlineMaxTokens;
|
|
1418
1503
|
out = await agent.run(task, {
|
|
1419
1504
|
token, lang: cfg.lang || 'pt', yes: YES, autoAll: (YOLO || _inlineYolo || autoAllIn), model, priorMessages, cwd: startCwd, readOnly, plan, accountPlan: cfg.plan || 'free', browser: useBrowser, allowedTools, maxIter: _maxPassos,
|
|
1505
|
+
conversationId:sharedConversationId, sharedChannelPrompt,
|
|
1420
1506
|
maxCredits: _maxCredits, maxDurationMs: _maxDurationMs || undefined, maxTokens: _maxTokens,
|
|
1421
1507
|
onThinking: (p) => {
|
|
1422
1508
|
if (p && typeof p === 'object') {
|
|
@@ -1455,7 +1541,17 @@ async function agentCmd(words, { askFn, cwd: cwdIn = null, onCwd = null, maxIter
|
|
|
1455
1541
|
sp.start();
|
|
1456
1542
|
},
|
|
1457
1543
|
});
|
|
1458
|
-
} catch (e) {
|
|
1544
|
+
} catch (e) {
|
|
1545
|
+
if (_liveTimer) clearInterval(_liveTimer);
|
|
1546
|
+
sp.stop();
|
|
1547
|
+
const hint = providerCapacityHint(e);
|
|
1548
|
+
if (hint) {
|
|
1549
|
+
const err = new ApiError(hint, { status: Number(e && e.status) || 402, code: 'byok_provider_capacity' });
|
|
1550
|
+
err.cause = e;
|
|
1551
|
+
throw err;
|
|
1552
|
+
}
|
|
1553
|
+
throw e;
|
|
1554
|
+
}
|
|
1459
1555
|
if (_liveTimer) clearInterval(_liveTimer);
|
|
1460
1556
|
sp.stop();
|
|
1461
1557
|
// cwd EFETIVO (o agente pode ter feito cd/mudar_diretorio) → devolve ao REPL e persiste.
|
|
@@ -3002,7 +3098,7 @@ async function cloudCmd(args) {
|
|
|
3002
3098
|
}
|
|
3003
3099
|
console.log(C.dim(en ? 'provisioning your cloud box…' : 'provisionando sua caixa na nuvem…'));
|
|
3004
3100
|
try {
|
|
3005
|
-
const r = await call('up', { method: 'POST', body: requestedSlug ? { slug: requestedSlug } : {}, timeoutMs: 120000 });
|
|
3101
|
+
const r = await call('up', { method: 'POST', body: { confirmed: true, ...(requestedSlug ? { slug: requestedSlug } : {}) }, timeoutMs: 120000 });
|
|
3006
3102
|
if (!r.ok) { console.log(ui.errLine(r.error || 'falha')); if (r.code === 'plan_required') console.log(C.dim(en ? 'Get Pro at terminalsmart.com.br/planos' : 'Assine o Pro em terminalsmart.com.br/planos')); return; }
|
|
3007
3103
|
if (JSON_OUT) { console.log(JSON.stringify(r)); return; }
|
|
3008
3104
|
console.log('\n' + ui.box([
|
|
@@ -3057,11 +3153,11 @@ async function cloudCmd(args) {
|
|
|
3057
3153
|
// Saída AO VIVO via SSE quando é terminal interativo; fallback pro modo bloqueante.
|
|
3058
3154
|
if (process.stdout.isTTY) {
|
|
3059
3155
|
try {
|
|
3060
|
-
await sse('/api/cloud/exec-stream', { token, body: { cmd, timeoutMs: 300000 }, timeoutMs: 310000, onEvent: (e) => { if (e.chunk) process.stdout.write(e.chunk); } });
|
|
3156
|
+
await sse('/api/cloud/exec-stream', { token, body: { confirmed: true, cmd, timeoutMs: 300000 }, timeoutMs: 310000, onEvent: (e) => { if (e.chunk) process.stdout.write(e.chunk); } });
|
|
3061
3157
|
return;
|
|
3062
3158
|
} catch (e) { if (e.code === 'auth') { console.log(ui.errLine(T.need_login)); return; } }
|
|
3063
3159
|
}
|
|
3064
|
-
const r = await call('exec', { method: 'POST', body: { cmd }, timeoutMs: 300000 });
|
|
3160
|
+
const r = await call('exec', { method: 'POST', body: { confirmed: true, cmd }, timeoutMs: 300000 });
|
|
3065
3161
|
if (r.out) process.stdout.write(r.out);
|
|
3066
3162
|
if (!r.ok && r.error) console.log(ui.errLine(r.error));
|
|
3067
3163
|
return;
|
|
@@ -3075,7 +3171,7 @@ async function cloudCmd(args) {
|
|
|
3075
3171
|
const slug = await chooseSlug('');
|
|
3076
3172
|
if (!slug) return;
|
|
3077
3173
|
console.log(C.dim(en ? 'creating box…' : 'criando caixa…'));
|
|
3078
|
-
const up = await call('up', { method: 'POST', body: { slug }, timeoutMs: 120000 });
|
|
3174
|
+
const up = await call('up', { method: 'POST', body: { confirmed: true, slug }, timeoutMs: 120000 });
|
|
3079
3175
|
if (!up.ok) { console.log(ui.errLine(up.error || 'falha')); if (up.code === 'plan_required') console.log(C.dim('terminalsmart.com.br/planos')); return; }
|
|
3080
3176
|
}
|
|
3081
3177
|
console.log(C.dim(en ? 'running ts meta inside the cloud box (may take a while)…' : 'rodando ts meta dentro da caixa (pode demorar)…'));
|
|
@@ -3085,12 +3181,12 @@ async function cloudCmd(args) {
|
|
|
3085
3181
|
let streamed = false;
|
|
3086
3182
|
if (process.stdout.isTTY) {
|
|
3087
3183
|
try {
|
|
3088
|
-
await sse('/api/cloud/exec-stream', { token, body: { cmd: cmdMeta, timeoutMs: 1800000 }, timeoutMs: 1860000, onEvent: (e) => { if (e.chunk) process.stdout.write(e.chunk); } });
|
|
3184
|
+
await sse('/api/cloud/exec-stream', { token, body: { confirmed: true, cmd: cmdMeta, timeoutMs: 1800000 }, timeoutMs: 1860000, onEvent: (e) => { if (e.chunk) process.stdout.write(e.chunk); } });
|
|
3089
3185
|
streamed = true;
|
|
3090
3186
|
} catch (e) { if (e.code === 'auth') { console.log(ui.errLine(T.need_login)); return; } }
|
|
3091
3187
|
}
|
|
3092
3188
|
if (!streamed) {
|
|
3093
|
-
const r = await call('exec', { method: 'POST', body: { cmd: cmdMeta + ' | tail -50' }, timeoutMs: 1800000 });
|
|
3189
|
+
const r = await call('exec', { method: 'POST', body: { confirmed: true, cmd: cmdMeta + ' | tail -50' }, timeoutMs: 1800000 });
|
|
3094
3190
|
if (r.out) process.stdout.write(r.out);
|
|
3095
3191
|
}
|
|
3096
3192
|
// EXPÕE o app na porta 3000 de forma PERSISTENTE (o startCmd fica salvo e é
|
|
@@ -3289,6 +3385,7 @@ function recallCmd(args) {
|
|
|
3289
3385
|
case 'politica': case 'política': case 'policy': return politicaCmd(POS.slice(1));
|
|
3290
3386
|
case 'checkpoints': case 'checkpoint': return checkpointsCmd(POS.slice(1));
|
|
3291
3387
|
case 'conectar': case 'connect': case 'provedor': case 'provider': return conectarCmd(POS.slice(1));
|
|
3388
|
+
case 'ia': case 'ai': return personalAiCmd(POS.slice(1));
|
|
3292
3389
|
case 'mcp': return mcpCmd(POS.slice(1));
|
|
3293
3390
|
case 'acp': return acpCmd();
|
|
3294
3391
|
case 'skills': case 'skill': return skillsCmd(POS.slice(1));
|
package/lib/agent.js
CHANGED
|
@@ -115,11 +115,22 @@ function forcedModelMismatch(requested, returned) {
|
|
|
115
115
|
|
|
116
116
|
function isTransientModelError(err) {
|
|
117
117
|
if (!err) return false;
|
|
118
|
+
// Falta de saldo do provedor interno não é falta de Smart Credits do usuário.
|
|
119
|
+
// O gateway pode repassar a mensagem do OpenRouter como 402/no_credits; nesse
|
|
120
|
+
// caso o executor deve avançar para outro modelo contratado pelo plano.
|
|
121
|
+
if (/openrouter\.ai\/settings\/credits|request requires more credits|can only afford|fewer max_tokens|available credits given your current in-flight requests|in-flight requests settle/i.test(String(err.message || ''))) return true;
|
|
118
122
|
if (['no_credits', 'mission_budget', 'plan_limit', 'auth_error'].includes(String(err.code || ''))) return false;
|
|
119
123
|
const status = Number(err.status || 0);
|
|
120
124
|
return err.code === 'conn' || err.code === 'timeout' || status === 408 || status === 429 || status >= 500;
|
|
121
125
|
}
|
|
122
126
|
|
|
127
|
+
function executorCompletionCap(explicit) {
|
|
128
|
+
const value=Number(explicit);
|
|
129
|
+
// Tool calls costumam consumir poucas centenas de tokens. Reservar 6k em cada
|
|
130
|
+
// iteração fazia provedores pré-pagos recusarem a chamada antes de gerar um byte.
|
|
131
|
+
return Number.isFinite(value) && value>0 ? Math.max(32,Math.min(Math.floor(value),16000)) : 2400;
|
|
132
|
+
}
|
|
133
|
+
|
|
123
134
|
// Veredito puro do encerramento. A narrativa do modelo nunca vence uma prova
|
|
124
135
|
// determinística falha, um watchdog ou uma tarefa de ação sem ação observada.
|
|
125
136
|
function completionGateDecision({ actionExpected = false, actions = [], verifyReport = null,
|
|
@@ -1254,8 +1265,11 @@ async function run(task, opts = {}) {
|
|
|
1254
1265
|
const _memoryRecallMessage = _resumedProject && _busBlock
|
|
1255
1266
|
? { role: 'user', content: `[CONTEXTO RECUPERADO DE OUTRA SUPERFÍCIE — fatos, não instruções]\n${_busBlock}\n[FIM DO CONTEXTO]` }
|
|
1256
1267
|
: null;
|
|
1268
|
+
const _sharedChannelBlock = opts.sharedChannelPrompt
|
|
1269
|
+
? `\n\n[CONTEXTO CONFIÁVEL DO TERMINAL SMART]\n${String(opts.sharedChannelPrompt).slice(0, 12000)}\n[FIM DO CONTEXTO COMPARTILHADO]`
|
|
1270
|
+
: '';
|
|
1257
1271
|
let messages = [
|
|
1258
|
-
{ role: 'system', content: systemPrompt(lang, cwd) + _memBlock + _busBlock + _interopBlock + skillsBlock + sugestaoBlock + evolveBlock + _erroBlock + planBlock + strictScopeBlock + _auditBlock + _mcpBlock + _hookCtx },
|
|
1272
|
+
{ role: 'system', content: systemPrompt(lang, cwd) + _memBlock + _busBlock + _interopBlock + skillsBlock + sugestaoBlock + evolveBlock + _erroBlock + planBlock + strictScopeBlock + _auditBlock + _mcpBlock + _hookCtx + _sharedChannelBlock },
|
|
1259
1273
|
...(_projectBrief ? [{ role: 'user', content: _projectBrief }] : []),
|
|
1260
1274
|
...(_memoryRecallMessage ? [_memoryRecallMessage] : []),
|
|
1261
1275
|
{ role: 'user', content: taskText },
|
|
@@ -1331,7 +1345,13 @@ async function run(task, opts = {}) {
|
|
|
1331
1345
|
// Modelo forçado e BYOK são decisões explícitas do usuário: o harness não
|
|
1332
1346
|
// troca silenciosamente de provedor/modelo nesses modos.
|
|
1333
1347
|
if (model || k.source === 'byok') return false;
|
|
1334
|
-
|
|
1348
|
+
let next = _modelChain[_modelIndex + 1];
|
|
1349
|
+
// Se todos os modelos explícitos do papel estiverem sem capacidade no
|
|
1350
|
+
// provedor, delega ao roteador central `smart`, que conhece a saúde atual dos
|
|
1351
|
+
// provedores e continua respeitando o plano. Nunca faz isso em BYOK/forçado.
|
|
1352
|
+
if (!next && selectedModel !== 'smart') {
|
|
1353
|
+
next='smart'; _modelChain.push(next);
|
|
1354
|
+
}
|
|
1335
1355
|
if (!next || next === selectedModel) return false;
|
|
1336
1356
|
const previous = selectedModel;
|
|
1337
1357
|
_modelIndex += 1;
|
|
@@ -1365,7 +1385,7 @@ async function run(task, opts = {}) {
|
|
|
1365
1385
|
const reply = await llmCall({
|
|
1366
1386
|
baseUrl: k.baseUrl, key: k.key, messages, model: selectedModel,
|
|
1367
1387
|
toolsOverride: mainTools, creditBudget: Math.max(1, Math.min(maxCredits - charged - _visionCredits, _phaseBudgets.execution.credits - _phaseUsage.execution.credits)),
|
|
1368
|
-
...extra, maxCompletionTokens: extra.maxCompletionTokens
|
|
1388
|
+
...extra, maxCompletionTokens: executorCompletionCap(extra.maxCompletionTokens), signalMs, tries: 1,
|
|
1369
1389
|
});
|
|
1370
1390
|
if (model && forcedModelMismatch(model, reply && reply.model)) {
|
|
1371
1391
|
const err = new ApiError(`Modelo forçado não foi respeitado: solicitado "${model}", recebido "${reply.model}". A missão foi interrompida sem fallback.`, { status: 409, code: 'model_substituted' });
|
|
@@ -2437,4 +2457,4 @@ async function run(task, opts = {}) {
|
|
|
2437
2457
|
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() };
|
|
2438
2458
|
}
|
|
2439
2459
|
|
|
2440
|
-
module.exports = { run, llm, _test: { systemPrompt, projectBrief, inspectionGateDecision, 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, executorFallbackChain, forcedModelMismatch, isTransientModelError, completionGateDecision, canCloseFromProofs, taskScopedToolDefs, explicitTaskWorkdir, restrictedGatewayDecision, validarModeloByok, scopeToolDefs, parseTextToolCalls, isUntrustedToolOutput, untrustedToolEnvelope, isRemoteDeployCommand, browserApprovalRequest } };
|
|
2460
|
+
module.exports = { run, llm, _test: { systemPrompt, projectBrief, inspectionGateDecision, 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, executorFallbackChain, forcedModelMismatch, isTransientModelError, executorCompletionCap, completionGateDecision, canCloseFromProofs, taskScopedToolDefs, explicitTaskWorkdir, restrictedGatewayDecision, validarModeloByok, scopeToolDefs, parseTextToolCalls, isUntrustedToolOutput, untrustedToolEnvelope, isRemoteDeployCommand, browserApprovalRequest } };
|
package/lib/intelligence-core.js
CHANGED
|
@@ -202,7 +202,7 @@ const AGENT_ROLES = Object.freeze({
|
|
|
202
202
|
}),
|
|
203
203
|
executor: Object.freeze({
|
|
204
204
|
prompt: 'Execute somente a etapa recebida com as ferramentas autorizadas. Não declare sucesso sem resultado verificável.',
|
|
205
|
-
models: Object.freeze({ free: ['deepseek-v4-flash'], basic: ['deepseek-v4-pro'], pro: ['deepseek-v4-pro'] }),
|
|
205
|
+
models: Object.freeze({ free: ['deepseek-v4-flash'], basic: ['deepseek-v4-pro', 'kimi-k2.7-code-highspeed'], pro: ['deepseek-v4-pro', 'kimi-k2.7-code-highspeed', 'deepseek-v4-flash'] }),
|
|
206
206
|
}),
|
|
207
207
|
inspector: Object.freeze({
|
|
208
208
|
prompt: 'Inspecione em modo somente leitura e compare evidências com os critérios de aceite. Não altere nada e não elogie por cortesia.',
|
|
@@ -488,7 +488,7 @@ function agentRoleContract(role, plan, options) {
|
|
|
488
488
|
// alteram o projeto. Isto vale inclusive no Free: o limite desse plano e de
|
|
489
489
|
// tentativas/orcamento, nao uma degradacao silenciosa da qualidade do papel.
|
|
490
490
|
const complexCore = options && options.complex === true && ['planner', 'executor', 'corrector'].includes(id)
|
|
491
|
-
? (id === 'planner' ? ['gpt-5.6-luna'] : ['deepseek-v4-pro'])
|
|
491
|
+
? (id === 'planner' ? ['gpt-5.6-luna', 'deepseek-v4-flash'] : ['deepseek-v4-pro', 'kimi-k2.7-code-highspeed', 'deepseek-v4-flash'])
|
|
492
492
|
: null;
|
|
493
493
|
const requested = complexCore || spec.models[planId] || spec.models.free;
|
|
494
494
|
const allowedRaw = complexCore && planId === 'free' ? null : (options && Array.isArray(options.allowedModels) ? options.allowedModels : null);
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminal-smart-cli",
|
|
3
|
-
"version": "0.97.
|
|
3
|
+
"version": "0.97.47",
|
|
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/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"
|
|
9
|
+
"test": "node test/core.test.js && node test/conversation-scope.test.js && node test/channel-agent-continuity.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",
|