terminal-smart-cli 0.97.67 → 0.97.69
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/lib/agent.js +12 -5
- package/lib/conversation-scope.js +7 -3
- package/lib/core.js +2 -2
- package/lib/intelligence-core.js +56 -44
- package/lib/tools.js +2 -1
- package/package.json +7 -3
package/lib/agent.js
CHANGED
|
@@ -103,11 +103,12 @@ function executorFallbackChain({ selectedModel, forced = false, source = 'cloud'
|
|
|
103
103
|
const first = intelligence.supportedModelId(String(selectedModel || DEFAULT_EXECUTOR).trim());
|
|
104
104
|
if (forced) return [first];
|
|
105
105
|
const role = intelligence.agentRoleContract('executor', plan, { complex });
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
106
|
+
// No modo Automático, a ordem do papel/plano é o contrato. O modelo sugerido
|
|
107
|
+
// pelo roteador pode ser um candidato válido e ainda assim representar um
|
|
108
|
+
// rebaixamento silencioso (por exemplo, V4.1 no lugar do Pro). Escolhas manuais
|
|
109
|
+
// já retornaram acima por `forced`; aqui usamos somente a cadeia contratada.
|
|
109
110
|
const candidates = role.candidates.filter(Boolean);
|
|
110
|
-
return [...new Set(
|
|
111
|
+
return [...new Set(candidates)]
|
|
111
112
|
.slice(0, 1 + planUpgradeLimit(plan));
|
|
112
113
|
}
|
|
113
114
|
|
|
@@ -486,7 +487,13 @@ function explicitTaskWorkdir(taskText, exists = fs.existsSync) {
|
|
|
486
487
|
// existente, preservando nomes de diretório que tenham espaços.
|
|
487
488
|
while (candidate) {
|
|
488
489
|
try {
|
|
489
|
-
|
|
490
|
+
// `exists` é injetável para que o parser de caminhos Windows possa ser
|
|
491
|
+
// testado também no Linux. A implementação padrão continua validando no
|
|
492
|
+
// disco; validadores customizados assumem a responsabilidade pelo tipo.
|
|
493
|
+
if (exists(candidate)) {
|
|
494
|
+
if (exists === fs.existsSync && !fs.statSync(candidate).isDirectory()) throw new Error('not-directory');
|
|
495
|
+
return /^[A-Za-z]:[\\/]/.test(candidate) ? path.win32.normalize(candidate) : path.resolve(candidate);
|
|
496
|
+
}
|
|
490
497
|
} catch (_) {}
|
|
491
498
|
const cut = candidate.lastIndexOf(' ');
|
|
492
499
|
if (cut < 0) break;
|
|
@@ -7,14 +7,18 @@ const crypto = require('crypto');
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
|
|
9
9
|
function workspaceScope(cwd = process.cwd(), kind = 'chat') {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
const raw = String(cwd || process.cwd());
|
|
11
|
+
const isWindowsPath = /^[A-Za-z]:[\\/]/.test(raw) || /^\\\\/.test(raw);
|
|
12
|
+
const absolute = isWindowsPath ? path.win32.resolve(raw) : path.resolve(raw);
|
|
13
|
+
const normalized = (process.platform === 'win32' || isWindowsPath) ? absolute.toLowerCase() : absolute;
|
|
12
14
|
const digest = crypto.createHash('sha256').update(normalized).digest('hex').slice(0, 16);
|
|
13
15
|
return `${String(kind || 'chat').toLowerCase()}:${digest}`;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
function conversationTitle(cwd = process.cwd(), kind = 'CLI') {
|
|
17
|
-
const
|
|
19
|
+
const raw = String(cwd || process.cwd());
|
|
20
|
+
const isWindowsPath = /^[A-Za-z]:[\\/]/.test(raw) || /^\\\\/.test(raw);
|
|
21
|
+
const name = (isWindowsPath ? path.win32.basename(path.win32.resolve(raw)) : path.basename(path.resolve(raw))) || 'início';
|
|
18
22
|
return `${kind} · ${name}`.slice(0, 120);
|
|
19
23
|
}
|
|
20
24
|
|
package/lib/core.js
CHANGED
|
@@ -158,7 +158,7 @@ function classifyError(msg) {
|
|
|
158
158
|
// A classe precisa sobreviver a isso: o recovery correto depende dela e não
|
|
159
159
|
// pode cair em unknown só por causa do encoding do terminal.
|
|
160
160
|
if (/is not recognized as (an )?(internal|the name of)|command not found|no such command|n[^a-z\s]{0,3}o (?:foi )?encontrad[oa] o comando|n[^a-z\s]{0,3}o [^\r\n]{0,80}reconhecid[oa]|invalid switch|unrecognized option|syntax of the command is incorrect|unexpectedtoken|parsererror|terminator.*string/i.test(s)) return 'invalid_command';
|
|
161
|
-
if (/working directory|invalid directory|directory name is invalid|system cannot find the path specified|n[^a-z\s]{0,3}o pode encontrar o caminho especificado|enoent.*(?:spawn|chdir)|chdir.*enoent/i.test(s)) return 'invalid_workdir';
|
|
161
|
+
if (/working directory|invalid directory|directory name is invalid|system cannot find the path specified|n[^a-z\s]{0,3}o pode encontrar o caminho especificado|enoent.*(?:spawn|chdir)|chdir.*enoent|(?:can(?:not|'t)|could not) cd\b|\bcd: .*no such (?:file|directory)/i.test(s)) return 'invalid_workdir';
|
|
162
162
|
if (/enoent|no such file|não encontrad|not found|arquivo inexistente|404/i.test(s)) return 'not_found';
|
|
163
163
|
if (/etimedout|timed out|timeout|excedeu o tempo/i.test(s)) return 'timeout';
|
|
164
164
|
if (/econnrefused|enotfound|getaddrinfo|network|connection refused|conexão recusada|conn|dns/i.test(s)) return 'network';
|
|
@@ -229,7 +229,7 @@ function classifyToolResult(raw) {
|
|
|
229
229
|
const exitCode = exit != null && Number.isFinite(Number(exit)) ? Number(exit) : -1;
|
|
230
230
|
const hadStderr = !!(raw.stderr && String(raw.stderr).trim());
|
|
231
231
|
if (failed) {
|
|
232
|
-
const errorClass = classifyError(errMsg);
|
|
232
|
+
const errorClass = exitCode === 127 ? 'invalid_command' : classifyError(errMsg);
|
|
233
233
|
return {
|
|
234
234
|
ok: false,
|
|
235
235
|
status: errorClass === 'blocked' ? 'blocked' : 'failed',
|
package/lib/intelligence-core.js
CHANGED
|
@@ -8,10 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
const crypto = require('crypto');
|
|
10
10
|
|
|
11
|
-
const INTELLIGENCE_CONTRACT =
|
|
12
|
-
|
|
13
|
-
// catalogFreshness appends an ISO time before parsing this value.
|
|
14
|
-
const PRICE_REVISION = '2026-08-11';
|
|
11
|
+
const INTELLIGENCE_CONTRACT = 3;
|
|
12
|
+
const PRICE_REVISION = '2026-09-13';
|
|
15
13
|
|
|
16
14
|
const MODEL_CATALOG = Object.freeze({
|
|
17
15
|
smart: {
|
|
@@ -23,6 +21,11 @@ const MODEL_CATALOG = Object.freeze({
|
|
|
23
21
|
provider: 'deepseek', contextWindow: 1048576, price: { input: 0.14, output: 0.28, cachedInput: 0.0028 },
|
|
24
22
|
capabilities: ['tools', 'code', 'planning', 'execution', 'long-context'], toolReliability: 0.94, quality: 0.86,
|
|
25
23
|
},
|
|
24
|
+
'deepseek-v4.1-flash': {
|
|
25
|
+
upstreamId: 'deepseek/deepseek-v4.1-flash',
|
|
26
|
+
provider: 'openrouter', contextWindow: 1048576, price: { input: 0.30, output: 1.20, cachedInput: 0.006 },
|
|
27
|
+
capabilities: ['tools', 'vision', 'code', 'planning', 'execution', 'review', 'classification', 'summarization', 'long-context'], toolReliability: 0.95, quality: 0.92,
|
|
28
|
+
},
|
|
26
29
|
'deepseek-chat': {
|
|
27
30
|
upstreamId: 'deepseek/deepseek-chat',
|
|
28
31
|
provider: 'deepseek', contextWindow: 163840, price: { input: 0.2002, output: 0.8001, cachedInput: 0.2002 },
|
|
@@ -63,6 +66,11 @@ const MODEL_CATALOG = Object.freeze({
|
|
|
63
66
|
provider: 'zai', contextWindow: 1048576, price: { input: 0.76, output: 2.42, cachedInput: 0.152 },
|
|
64
67
|
capabilities: ['tools', 'planning', 'code', 'long-context'], toolReliability: 0.88, quality: 0.89,
|
|
65
68
|
},
|
|
69
|
+
'glm-5.3': {
|
|
70
|
+
upstreamId: 'z-ai/glm-5.3',
|
|
71
|
+
provider: 'openrouter', contextWindow: 1310720, price: { input: 1.40, output: 4.40, cachedInput: 0.26 },
|
|
72
|
+
capabilities: ['tools', 'planning', 'code', 'review', 'long-context'], toolReliability: 0.91, quality: 0.92,
|
|
73
|
+
},
|
|
66
74
|
'mimo-v2.5': {
|
|
67
75
|
upstreamId: 'xiaomi/mimo-v2.5',
|
|
68
76
|
provider: 'xiaomi', contextWindow: 1050000, price: { input: 0.14, output: 0.28, cachedInput: 0.0028 },
|
|
@@ -104,8 +112,6 @@ const MODEL_CATALOG = Object.freeze({
|
|
|
104
112
|
capabilities: ['tools', 'code', 'planning', 'review'], toolReliability: 0.96, quality: 0.95,
|
|
105
113
|
},
|
|
106
114
|
'claude-haiku-4-5': {
|
|
107
|
-
// ID canônico exposto pelo OpenRouter. O alias interno permanece estável
|
|
108
|
-
// para planos e histórico, mas o gateway precisa receber este identificador.
|
|
109
115
|
upstreamId: 'anthropic/claude-4.5-haiku-20251001',
|
|
110
116
|
provider: 'anthropic', contextWindow: 200000, price: { input: 1.00, output: 5.00, cachedInput: 0.10 },
|
|
111
117
|
capabilities: ['tools', 'code', 'planning', 'execution', 'review', 'vision'], toolReliability: 0.94, quality: 0.88,
|
|
@@ -171,7 +177,9 @@ const MODEL_CATALOG = Object.freeze({
|
|
|
171
177
|
});
|
|
172
178
|
|
|
173
179
|
const MODEL_ALIASES = Object.freeze({
|
|
174
|
-
deepseek: 'deepseek-v4-
|
|
180
|
+
deepseek: 'deepseek-v4.1-flash',
|
|
181
|
+
'deepseek-v4.1': 'deepseek-v4.1-flash',
|
|
182
|
+
'deepseek-4.1': 'deepseek-v4.1-flash',
|
|
175
183
|
'deepseek-v4': 'deepseek-v4-pro',
|
|
176
184
|
glm: 'glm-4.6',
|
|
177
185
|
mimo: 'mimo-v2.5',
|
|
@@ -188,58 +196,60 @@ const MODEL_ALIASES = Object.freeze({
|
|
|
188
196
|
// proxy — foi exatamente o caso do CLI, cuja cadeia de executor do plano Free
|
|
189
197
|
// apontava inteira para os dois ids abaixo.
|
|
190
198
|
const RETIRED_MODELS = Object.freeze({
|
|
191
|
-
'deepseek-v4-flash': 'deepseek-v4-
|
|
199
|
+
'deepseek-v4-flash': 'deepseek-v4.1-flash',
|
|
192
200
|
'gemini-2.5-flash-lite': 'gemini-2.5-flash',
|
|
193
201
|
});
|
|
194
202
|
|
|
195
|
-
// Equipe oficial do modo Automático
|
|
196
|
-
// de
|
|
203
|
+
// Equipe oficial do modo Automático. Papéis são deliberadamente poucos: a
|
|
204
|
+
// qualidade vem de especialização + provas objetivas, não de trocar de modelo
|
|
205
|
+
// a cada etapa. Modelos premium continuam fora desta cascata até validação real.
|
|
197
206
|
const OFFICIAL_AUTOMATIC_TEAM = Object.freeze({
|
|
198
207
|
planner: Object.freeze({ model: 'gpt-5.6-luna', label: 'Luna', responsibility: 'planejamento' }),
|
|
199
208
|
executor: Object.freeze({ model: 'deepseek-v4-pro', label: 'DeepSeek Pro', responsibility: 'execução' }),
|
|
200
209
|
corrector: Object.freeze({ model: 'deepseek-v4-pro', label: 'DeepSeek Pro', responsibility: 'correção' }),
|
|
201
|
-
multimodal: Object.freeze({ model: '
|
|
210
|
+
multimodal: Object.freeze({ model: 'deepseek-v4.1-flash', fallback: 'gpt-5.6-luna', label: 'DeepSeek V4.1', responsibility: 'imagem, arquivo e documento visual' }),
|
|
202
211
|
verifier: Object.freeze({ model: null, label: 'Verificadores determinísticos', responsibility: 'prova objetiva de entrega' }),
|
|
203
212
|
});
|
|
204
213
|
|
|
205
214
|
// Contrato dos agentes funcionais. Isto não é fine-tuning: cada papel recebe um
|
|
206
|
-
// prompt curto e continua sujeito
|
|
215
|
+
// prompt curto e continua sujeito às provas das ferramentas. Para planos pagos,
|
|
216
|
+
// a equipe oficial não muda sem uma falha objetiva registrada.
|
|
207
217
|
const AGENT_ROLES = Object.freeze({
|
|
208
218
|
classifier: Object.freeze({
|
|
209
219
|
prompt: 'Classifique a intenção e devolva somente a estrutura pedida. Não execute ferramentas nem invente dados.',
|
|
210
|
-
models: Object.freeze({ free: ['deepseek-v4-
|
|
220
|
+
models: Object.freeze({ free: ['deepseek-v4.1-flash', 'gpt-5.6-luna'], basic: ['deepseek-v4.1-flash', 'gpt-5.6-luna'], pro: ['deepseek-v4.1-flash', 'gpt-5.6-luna'] }),
|
|
211
221
|
}),
|
|
212
222
|
planner: Object.freeze({
|
|
213
223
|
prompt: 'Decomponha o objetivo em etapas executáveis, dependências, riscos, critérios de aceite e provas. Não execute a tarefa.',
|
|
214
|
-
models: Object.freeze({ free: ['
|
|
224
|
+
models: Object.freeze({ free: ['gpt-5.6-luna', 'deepseek-v4.1-flash'], basic: ['gpt-5.6-luna', 'deepseek-v4.1-flash', 'deepseek-v4-pro'], pro: ['gpt-5.6-luna', 'glm-5.3', 'deepseek-v4-pro'] }),
|
|
215
225
|
}),
|
|
216
226
|
executor: Object.freeze({
|
|
217
227
|
prompt: 'Execute somente a etapa recebida com as ferramentas autorizadas. Não declare sucesso sem resultado verificável.',
|
|
218
|
-
models: Object.freeze({ free: ['deepseek-v4-
|
|
228
|
+
models: Object.freeze({ free: ['deepseek-v4.1-flash', 'gpt-5.6-luna'], basic: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'], pro: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'] }),
|
|
219
229
|
}),
|
|
220
230
|
inspector: Object.freeze({
|
|
221
231
|
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.',
|
|
222
|
-
models: Object.freeze({ free: ['
|
|
232
|
+
models: Object.freeze({ free: ['gpt-5.6-luna', 'deepseek-v4.1-flash'], basic: ['gpt-5.6-luna', 'deepseek-v4.1-flash'], pro: ['glm-5.3', 'gpt-5.6-luna', 'deepseek-v4-pro'] }),
|
|
223
233
|
}),
|
|
224
234
|
corrector: Object.freeze({
|
|
225
235
|
prompt: 'Corrija apenas falhas confirmadas pelo inspetor, preserve o que funciona e repita as provas afetadas. Não amplie o escopo.',
|
|
226
|
-
models: Object.freeze({ free: ['deepseek-v4-
|
|
236
|
+
models: Object.freeze({ free: ['deepseek-v4.1-flash', 'gpt-5.6-luna'], basic: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'], pro: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'] }),
|
|
227
237
|
}),
|
|
228
238
|
vision: Object.freeze({
|
|
229
239
|
prompt: 'Extraia fatos observáveis da imagem e separe leitura, inferência e incerteza. Não invente texto ilegível.',
|
|
230
|
-
models: Object.freeze({ free: ['
|
|
240
|
+
models: Object.freeze({ free: ['deepseek-v4.1-flash', 'gpt-5.6-luna'], basic: ['deepseek-v4.1-flash', 'gpt-5.6-luna', 'mimo-v2.5'], pro: ['deepseek-v4.1-flash', 'gpt-5.6-luna', 'mimo-v2.5'] }),
|
|
231
241
|
}),
|
|
232
242
|
document: Object.freeze({
|
|
233
243
|
prompt: 'Produza conteúdo estruturado e use o motor nativo do formato solicitado. Preserve editabilidade e valide o arquivo gerado.',
|
|
234
|
-
models: Object.freeze({ free: ['
|
|
244
|
+
models: Object.freeze({ free: ['deepseek-v4.1-flash', 'gpt-5.6-luna'], basic: ['deepseek-v4.1-flash', 'gpt-5.6-luna', 'mimo-v2.5'], pro: ['deepseek-v4.1-flash', 'gpt-5.6-luna', 'mimo-v2.5'] }),
|
|
235
245
|
}),
|
|
236
246
|
site_builder: Object.freeze({
|
|
237
247
|
prompt: 'Crie ou edite o site completo, responsivo e acessível. Preserve o existente quando editar e valide a URL publicada.',
|
|
238
|
-
models: Object.freeze({ free: ['deepseek-v4-
|
|
248
|
+
models: Object.freeze({ free: ['deepseek-v4.1-flash', 'gpt-5.6-luna'], basic: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'], pro: ['deepseek-v4-pro', 'gpt-5.6-luna', 'deepseek-v4.1-flash'] }),
|
|
239
249
|
}),
|
|
240
250
|
cloud_box: Object.freeze({
|
|
241
251
|
prompt: 'Opere a box com mudanças mínimas, registre comandos e valide serviço, porta e URL. Nunca exponha segredos.',
|
|
242
|
-
models: Object.freeze({ free: ['deepseek-v4-
|
|
252
|
+
models: Object.freeze({ free: ['deepseek-v4.1-flash', 'gpt-5.6-luna'], basic: ['deepseek-v4-pro', 'deepseek-v4.1-flash'], pro: ['deepseek-v4-pro', 'gpt-5.6-luna', 'deepseek-v4.1-flash'] }),
|
|
243
253
|
}),
|
|
244
254
|
});
|
|
245
255
|
|
|
@@ -389,9 +399,6 @@ function _safeModelId(value) {
|
|
|
389
399
|
return MODEL_CATALOG[normalized] || normalized === 'smart' ? normalized : _safeToolName(value);
|
|
390
400
|
}
|
|
391
401
|
|
|
392
|
-
// Contrato compacto para painéis e comparação de execuções. É deliberadamente
|
|
393
|
-
// agregado: o painel sabe se a missão funcionou e onde falhou, sem receber o
|
|
394
|
-
// pedido do usuário, conteúdo de e-mail, arquivo, comando ou diretório.
|
|
395
402
|
function buildOperationalSummary(input) {
|
|
396
403
|
const x = input || {};
|
|
397
404
|
const usage = x.tokens || x.usage || {};
|
|
@@ -412,21 +419,12 @@ function buildOperationalSummary(input) {
|
|
|
412
419
|
}
|
|
413
420
|
const verification = x.verification || {};
|
|
414
421
|
return {
|
|
415
|
-
version: 1,
|
|
416
|
-
surface: _safeToolName(x.surface || 'cli'),
|
|
417
|
-
model: _safeModelId(x.model || 'smart'),
|
|
422
|
+
version: 1, surface: _safeToolName(x.surface || 'cli'), model: _safeModelId(x.model || 'smart'),
|
|
418
423
|
status: x.completion && x.completion.ok ? 'completed' : (x.guard ? 'stopped_by_guard' : 'blocked'),
|
|
419
424
|
completionReason: _safeToolName(x.completion && x.completion.reason || 'unknown'),
|
|
420
|
-
steps: Math.max(0, Number(x.steps) || 0),
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
tokens: {
|
|
424
|
-
input: Math.max(0, Number(usage.inTok || usage.input_tokens) || 0),
|
|
425
|
-
output: Math.max(0, Number(usage.outTok || usage.output_tokens) || 0),
|
|
426
|
-
cached: Math.max(0, Number(usage.cachedTok || usage.cacheTok || usage.cached_tokens) || 0),
|
|
427
|
-
},
|
|
428
|
-
actions,
|
|
429
|
-
failures: [...failures.values()].sort((a, b) => b.count - a.count || a.tool.localeCompare(b.tool)).slice(0, 20),
|
|
425
|
+
steps: Math.max(0, Number(x.steps) || 0), durationMs: Math.max(0, Number(x.durationMs) || 0), credits: Math.max(0, Number(x.credits) || 0),
|
|
426
|
+
tokens: { input: Math.max(0, Number(usage.inTok || usage.input_tokens) || 0), output: Math.max(0, Number(usage.outTok || usage.output_tokens) || 0), cached: Math.max(0, Number(usage.cachedTok || usage.cacheTok || usage.cached_tokens) || 0) },
|
|
427
|
+
actions, failures: [...failures.values()].sort((a, b) => b.count - a.count || a.tool.localeCompare(b.tool)).slice(0, 20),
|
|
430
428
|
verification: { total: Math.max(0, Number(verification.total) || 0), passed: Math.max(0, Number(verification.passed) || 0), allOk: verification.allOk === true },
|
|
431
429
|
cache: Object.assign({ hits: 0, misses: 0, entries: 0 }, x.missionCache || {}),
|
|
432
430
|
};
|
|
@@ -505,13 +503,28 @@ function agentRoleContract(role, plan, options) {
|
|
|
505
503
|
const id = Object.prototype.hasOwnProperty.call(AGENT_ROLES, role) ? role : 'executor';
|
|
506
504
|
const planId = normalizeAgentPlan(plan);
|
|
507
505
|
const spec = AGENT_ROLES[id];
|
|
506
|
+
const complexTeams = {
|
|
507
|
+
free: {
|
|
508
|
+
planner: ['gpt-5.6-luna', 'deepseek-v4.1-flash'],
|
|
509
|
+
executor: ['deepseek-v4.1-flash', 'gpt-5.6-luna'],
|
|
510
|
+
corrector: ['deepseek-v4.1-flash', 'gpt-5.6-luna'],
|
|
511
|
+
},
|
|
512
|
+
basic: {
|
|
513
|
+
planner: ['gpt-5.6-luna', 'deepseek-v4.1-flash', 'deepseek-v4-pro'],
|
|
514
|
+
executor: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'],
|
|
515
|
+
corrector: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'],
|
|
516
|
+
},
|
|
517
|
+
pro: {
|
|
518
|
+
planner: ['gpt-5.6-luna', 'glm-5.3', 'deepseek-v4-pro'],
|
|
519
|
+
executor: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'],
|
|
520
|
+
corrector: ['deepseek-v4-pro', 'deepseek-v4.1-flash', 'gpt-5.6-luna'],
|
|
521
|
+
},
|
|
522
|
+
};
|
|
508
523
|
const complexCore = options && options.complex === true && ['planner', 'executor', 'corrector'].includes(id)
|
|
509
|
-
?
|
|
510
|
-
? ['gpt-5.6-luna', 'glm-5.2', 'deepseek-v4-pro']
|
|
511
|
-
: ['deepseek-v4-pro', 'gpt-5.6-luna', 'glm-5.2'])
|
|
524
|
+
? complexTeams[planId][id]
|
|
512
525
|
: null;
|
|
513
526
|
const requested = complexCore || spec.models[planId] || spec.models.free;
|
|
514
|
-
const allowedRaw =
|
|
527
|
+
const allowedRaw = options && Array.isArray(options.allowedModels) ? options.allowedModels : null;
|
|
515
528
|
const allowAll = !allowedRaw || allowedRaw.includes('*');
|
|
516
529
|
const allowed = allowAll ? null : new Set(allowedRaw.map(normalizeModelId));
|
|
517
530
|
const candidates = requested.map(normalizeModelId).filter(model => model === 'smart' || MODEL_CATALOG[model])
|
|
@@ -533,9 +546,8 @@ function routeModel(task, reliability) {
|
|
|
533
546
|
if (t.kind === 'code') required.add('code');
|
|
534
547
|
if (t.kind === 'review') required.add('review');
|
|
535
548
|
if (t.kind === 'vision') required.add('vision');
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
// reescrever depois — o que nao acontece em BYOK nem offline.
|
|
549
|
+
// Era um Set escrito a mao aqui dentro. Agora le a MESMA tabela que o CLI e
|
|
550
|
+
// o App leem, para os tres nao divergirem de novo.
|
|
539
551
|
const candidates = (t.candidates || Object.keys(MODEL_CATALOG)).map(supportedModelId)
|
|
540
552
|
.filter(id => MODEL_CATALOG[id] && id !== 'smart')
|
|
541
553
|
.filter((id, i, list) => list.indexOf(id) === i);
|
package/lib/tools.js
CHANGED
|
@@ -546,7 +546,8 @@ function _commandScopeViolation(cmd, confineDir) {
|
|
|
546
546
|
// `findstr /c:"texto"`. Não são caminhos Unix nem tentativas de escapar da
|
|
547
547
|
// raiz. Sem esta exceção uma busca contendo `</script>` era lida como
|
|
548
548
|
// redirecionamento e o `/c:` seguinte virava um falso caminho externo.
|
|
549
|
-
if (
|
|
549
|
+
if (/^\/[a-z](?::|$)/i.test(raw)
|
|
550
|
+
&& (process.platform === 'win32' || /(?:^|[&|]\s*)findstr\b/i.test(text))) continue;
|
|
550
551
|
const abs = path.resolve(root, raw);
|
|
551
552
|
if (!_scopeContains(root, abs)) {
|
|
552
553
|
return `CAPABILITY_DENIED: comando mutante referencia "${raw}", fora da raiz autorizada "${root}".`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "terminal-smart-cli",
|
|
3
|
-
"version": "0.97.
|
|
3
|
+
"version": "0.97.69",
|
|
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"
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"README.md"
|
|
15
15
|
],
|
|
16
16
|
"engines": {
|
|
17
|
-
"node": ">=
|
|
17
|
+
"node": ">=22.12"
|
|
18
18
|
},
|
|
19
19
|
"keywords": [
|
|
20
20
|
"devops",
|
|
@@ -33,8 +33,12 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"exceljs": "^4.4.0",
|
|
35
35
|
"jszip": "^3.10.1",
|
|
36
|
-
"puppeteer-core": "^
|
|
36
|
+
"puppeteer-core": "^25.11.0",
|
|
37
37
|
"qrcode-terminal": "^0.12.0",
|
|
38
38
|
"ssh2": "^1.17.0"
|
|
39
|
+
},
|
|
40
|
+
"overrides": {
|
|
41
|
+
"ip-address": "^10.7.0",
|
|
42
|
+
"uuid": "^11.1.1"
|
|
39
43
|
}
|
|
40
44
|
}
|