clawfast 2.2.0 → 2.2.2
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/dist/clawfast.cjs +243 -22
- package/package.json +1 -1
package/dist/clawfast.cjs
CHANGED
|
@@ -689,7 +689,7 @@ var clawfastVersion, isDevVersion, isNewerVersion;
|
|
|
689
689
|
var init_version = __esm({
|
|
690
690
|
"src/version.ts"() {
|
|
691
691
|
"use strict";
|
|
692
|
-
clawfastVersion = () => true ? "2.2.
|
|
692
|
+
clawfastVersion = () => true ? "2.2.2" : devVersionFromPackageJson();
|
|
693
693
|
isDevVersion = () => clawfastVersion().includes("-dev");
|
|
694
694
|
isNewerVersion = (a, b) => {
|
|
695
695
|
const parse3 = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
@@ -45808,6 +45808,9 @@ function resolveLanguageModel2(key) {
|
|
|
45808
45808
|
if (isOpenRouterDynamicKey(key)) {
|
|
45809
45809
|
return openrouter2(openRouterSlugFromKey(key));
|
|
45810
45810
|
}
|
|
45811
|
+
if (isNvidiaDynamicKey(key)) {
|
|
45812
|
+
return nvidia.chat(nvidiaSlugFromKey(key));
|
|
45813
|
+
}
|
|
45811
45814
|
return myProvider.languageModel(key);
|
|
45812
45815
|
}
|
|
45813
45816
|
async function listOpenRouterModels(signal) {
|
|
@@ -45833,7 +45836,25 @@ async function listOpenRouterModels(signal) {
|
|
|
45833
45836
|
};
|
|
45834
45837
|
}).filter((m) => m !== null).sort((a, b) => a.name.localeCompare(b.name));
|
|
45835
45838
|
}
|
|
45836
|
-
|
|
45839
|
+
async function listNvidiaModels(signal) {
|
|
45840
|
+
const key = process.env.NVIDIA_API_KEY?.trim();
|
|
45841
|
+
if (!key) throw new Error("NVIDIA_API_KEY n\xE3o configurada");
|
|
45842
|
+
const baseURL = process.env.NVIDIA_BASE_URL || "https://integrate.api.nvidia.com/v1";
|
|
45843
|
+
const res = await fetch(`${baseURL.replace(/\/$/, "")}/models`, {
|
|
45844
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
45845
|
+
signal
|
|
45846
|
+
});
|
|
45847
|
+
if (!res.ok) {
|
|
45848
|
+
throw new Error(`NVIDIA /models falhou: HTTP ${res.status}`);
|
|
45849
|
+
}
|
|
45850
|
+
const json3 = await res.json();
|
|
45851
|
+
const data = Array.isArray(json3.data) ? json3.data : [];
|
|
45852
|
+
return data.map((raw) => {
|
|
45853
|
+
if (!isRecord(raw) || typeof raw.id !== "string") return null;
|
|
45854
|
+
return { id: raw.id, name: raw.id };
|
|
45855
|
+
}).filter((m) => m !== null).sort((a, b) => a.id.localeCompare(b.id));
|
|
45856
|
+
}
|
|
45857
|
+
var isRecord, isXaiModelSlug, isGeminiModelSlug, requestCanRouteToXai, requestCanRouteToGemini, hasOwnEncryptedContent, stripEncryptedContent, sanitizeOpenRouterRequestForXai, hasJsonRefKey, wrapToolContentIfGeminiRefSensitive, sanitizeOpenRouterRequestForGeminiFunctionResponses, patchKimiReasoningToolCalls, OPENROUTER_METADATA_HEADER, withOpenRouterMetadataHeader, openrouterPatchFetch, openrouter2, openai2, isNvidiaMistralModel, applyNvidiaMistralConfig, nvidiaPatchFetch, nvidia, deepseek, kimi, buildProviderMap, hasEnvValue, isDeepSeekEnabled, isKimiEnabled, CLI_MODEL_CHAIN, baseProviders, modelCutoffDates, modelDisplayNames, getModelDisplayName, getModelCutoffDate, myProvider, OPENROUTER_KEY_PREFIX, hasOpenRouterKey, isOpenRouterDynamicKey, openRouterSlugFromKey, openRouterKeyForSlug, NVIDIA_KEY_PREFIX, hasNvidiaKey, isNvidiaDynamicKey, nvidiaSlugFromKey, nvidiaKeyForSlug;
|
|
45837
45858
|
var init_providers = __esm({
|
|
45838
45859
|
"../lib/ai/providers.ts"() {
|
|
45839
45860
|
"use strict";
|
|
@@ -46180,6 +46201,11 @@ var init_providers = __esm({
|
|
|
46180
46201
|
isOpenRouterDynamicKey = (key) => key.startsWith(OPENROUTER_KEY_PREFIX);
|
|
46181
46202
|
openRouterSlugFromKey = (key) => key.slice(OPENROUTER_KEY_PREFIX.length);
|
|
46182
46203
|
openRouterKeyForSlug = (slug) => `${OPENROUTER_KEY_PREFIX}${slug}`;
|
|
46204
|
+
NVIDIA_KEY_PREFIX = "nvidia:";
|
|
46205
|
+
hasNvidiaKey = () => Boolean(process.env.NVIDIA_API_KEY?.trim());
|
|
46206
|
+
isNvidiaDynamicKey = (key) => key.startsWith(NVIDIA_KEY_PREFIX);
|
|
46207
|
+
nvidiaSlugFromKey = (key) => key.slice(NVIDIA_KEY_PREFIX.length);
|
|
46208
|
+
nvidiaKeyForSlug = (slug) => `${NVIDIA_KEY_PREFIX}${slug}`;
|
|
46183
46209
|
}
|
|
46184
46210
|
});
|
|
46185
46211
|
|
|
@@ -70403,7 +70429,9 @@ var init_local_sandbox = __esm({
|
|
|
70403
70429
|
this.shellBin = shell2.shell;
|
|
70404
70430
|
this.shellFlag = shell2.shellFlag;
|
|
70405
70431
|
}
|
|
70406
|
-
const
|
|
70432
|
+
const explicit = opts?.workdir || process.env.CLI_WORKDIR;
|
|
70433
|
+
const base = explicit || import_node_path7.default.join(process.cwd(), "SPRIT");
|
|
70434
|
+
this.autoCreated = !explicit;
|
|
70407
70435
|
this.workdir = import_node_path7.default.resolve(base).replace(/\\/g, "/");
|
|
70408
70436
|
}
|
|
70409
70437
|
async init() {
|
|
@@ -70560,6 +70588,31 @@ EDITING SCRIPTS:
|
|
|
70560
70588
|
}
|
|
70561
70589
|
this.backgroundPids.clear();
|
|
70562
70590
|
}
|
|
70591
|
+
/**
|
|
70592
|
+
* Remove the auto-created SPRIT workspace on session exit so an analysis never
|
|
70593
|
+
* leaves scratch tooling behind in the user's project. The human-facing
|
|
70594
|
+
* deliverable (ANALISE_PROJETO_*.md / findings report) is written at the
|
|
70595
|
+
* PROJECT ROOT, OUTSIDE SPRIT — so nothing the user needs is lost.
|
|
70596
|
+
*
|
|
70597
|
+
* Strictly guarded — deletes ONLY when all hold:
|
|
70598
|
+
* - the workspace was auto-created (default <cwd>/SPRIT, no explicit override)
|
|
70599
|
+
* - its basename is exactly "SPRIT" (never a project root or arbitrary dir)
|
|
70600
|
+
* - the operator has not opted out via CLAWFAST_KEEP_SPRIT
|
|
70601
|
+
* Best-effort: any failure is swallowed; cleanup must never block shutdown.
|
|
70602
|
+
* Returns the removed path (for logging) or null when nothing was removed.
|
|
70603
|
+
*/
|
|
70604
|
+
async cleanupWorkspace() {
|
|
70605
|
+
if (!this.autoCreated) return null;
|
|
70606
|
+
const keep = (process.env.CLAWFAST_KEEP_SPRIT || "").trim().toLowerCase();
|
|
70607
|
+
if (keep === "1" || keep === "true" || keep === "yes") return null;
|
|
70608
|
+
if (import_node_path7.default.basename(this.workdir).toUpperCase() !== "SPRIT") return null;
|
|
70609
|
+
try {
|
|
70610
|
+
await import_node_fs8.promises.rm(this.workdir, { recursive: true, force: true });
|
|
70611
|
+
return this.workdir;
|
|
70612
|
+
} catch {
|
|
70613
|
+
return null;
|
|
70614
|
+
}
|
|
70615
|
+
}
|
|
70563
70616
|
/** True while a foreground command is running and can still accept stdin. */
|
|
70564
70617
|
isProcessRunning() {
|
|
70565
70618
|
const child = this.activeForegroundChild;
|
|
@@ -71154,10 +71207,16 @@ function detectAuditExitIntent(input) {
|
|
|
71154
71207
|
if (!text2) return false;
|
|
71155
71208
|
return AUDIT_EXIT.some((re2) => re2.test(text2));
|
|
71156
71209
|
}
|
|
71210
|
+
function detectPocVerifyIntent(input) {
|
|
71211
|
+
const text2 = input.trim();
|
|
71212
|
+
if (!text2) return false;
|
|
71213
|
+
return POC_VERIFY.some((re2) => re2.test(text2));
|
|
71214
|
+
}
|
|
71157
71215
|
function buildAuditSystemPrompt(opts) {
|
|
71158
71216
|
const root = opts.projectRoot.replace(/\\/g, "/");
|
|
71159
71217
|
const workdir = opts.workdir.replace(/\\/g, "/");
|
|
71160
71218
|
const isWin = (opts.platform ?? process.platform) === "win32";
|
|
71219
|
+
const verify = opts.mode === "verify";
|
|
71161
71220
|
const py = isWin ? "python" : "python3";
|
|
71162
71221
|
const shellNote = isWin ? "Voc\xEA est\xE1 em Windows. Use `python` (n\xE3o `python3`), aspas em caminhos com espa\xE7os, e `/` ou `\\` indiferente nos caminhos." : "Use `python3` quando `python` n\xE3o existir.";
|
|
71163
71222
|
const shellHint = opts.shellHint ?? shellNote;
|
|
@@ -71167,7 +71226,11 @@ function buildAuditSystemPrompt(opts) {
|
|
|
71167
71226
|
FILOSOFIA (estado da arte \u2014 h\xEDbrido, n\xE3o LLM puro):
|
|
71168
71227
|
Voc\xEA N\xC3O \xE9 um LLM que l\xEA o projeto inteiro linha a linha. Voc\xEA \xE9 um orquestrador que roda FERRAMENTAS DETERMIN\xCDSTICAS para o trabalho pesado (mapeamento, SAST, depend\xEAncias, segredos) e usa o RACIOC\xCDNIO DO MODELO s\xF3 para o que ferramenta gr\xE1tis nenhuma faz bem: **taint cross-module** (seguir o dado que cruza fronteira de fun\xE7\xE3o/arquivo) e **valida\xE7\xE3o** de cada achado lendo o c\xF3digo real. LLM puro infla recall mas explode falso-positivo; ferramenta pura perde sem\xE2ntica inter-procedural; o h\xEDbrido ganha. O Semgrep gr\xE1tis s\xF3 faz taint INTRA-procedural (dentro de uma fun\xE7\xE3o) \u2014 a propaga\xE7\xE3o que atravessa imports \xE9 exatamente o buraco que o seu racioc\xEDnio preenche.
|
|
71169
71228
|
|
|
71170
|
-
Miss\xE3o desta sess\xE3o: an\xE1lise extremamente precisa e profunda do projeto inteiro e entrega de **um relat\xF3rio** acion\xE1vel e honesto. Ferramentas do agente: \`run_terminal_cmd\`, \`file
|
|
71229
|
+
Miss\xE3o desta sess\xE3o: an\xE1lise extremamente precisa e profunda do projeto inteiro e entrega de **um relat\xF3rio** acion\xE1vel e honesto, com BUSCA cir\xFArgica (ferramentas estruturais sobre o c\xF3digo real) e PODER de verifica\xE7\xE3o (cada achado provado, n\xE3o suposto). Ferramentas do agente: \`run_terminal_cmd\`, \`file\` (com leitura por \`range\` \u2014 leia S\xD3 a janela exata da fun\xE7\xE3o, nunca o arquivo inteiro), \`findings\` (mem\xF3ria estruturada de vulnerabilidades \u2014 a fonte \xFAnica de verdade dos achados) e \`todo_write\`.
|
|
71230
|
+
|
|
71231
|
+
${verify ? `>>> SUB-MODO ATIVO: **VERIFICA\xC7\xC3O / PoC** <<<
|
|
71232
|
+
Voc\xEA foi acionado para PROVAR achados rodando-os de verdade (reproduzir a vulnerabilidade), n\xE3o s\xF3 lendo. Vale a regra relaxada da se\xE7\xE3o "SUB-MODO VERIFICA\xC7\xC3O" abaixo: voc\xEA PODE executar o c\xF3digo do projeto de um harness ISOLADO na workspace \u2014 mas continua SEM editar/criar/apagar nada dentro do projeto. Objetivo: virar cada \`[SUSPEITA]\` em \`[CONFIRMADO]\` com PoC reproduz\xEDvel e n\xE3o-destrutivo.` : `>>> MODO ATIVO: **AN\xC1LISE (somente leitura)** <<<
|
|
71233
|
+
Voc\xEA N\xC3O roda o projeto. Para PROVAR um achado executando um PoC, o operador precisa pedir explicitamente (ex.: "prove rodando", "rode o PoC") \u2014 a\xED entra o sub-modo de verifica\xE7\xE3o.`}
|
|
71171
71234
|
|
|
71172
71235
|
PROJETO SOB AN\xC1LISE (raiz): ${root}
|
|
71173
71236
|
WORKSPACE DE TRABALHO (ferramentas/sa\xEDdas intermedi\xE1rias): ${workdir}
|
|
@@ -71182,6 +71245,16 @@ Um relat\xF3rio de seguran\xE7a inventado \xE9 PIOR que nenhum \u2014 \xE9 perig
|
|
|
71182
71245
|
3. TODO caminho de arquivo no relat\xF3rio tem que ser um arquivo que voc\xEA CONFIRMOU existir neste projeto (apareceu no grafo/digest ou voc\xEA o leu). Nunca cite caminhos gen\xE9ricos de mem\xF3ria (ex.: \`src/services/userService.ts\`, \`lodash@x\`) sem t\xEA-los visto na sa\xEDda real.
|
|
71183
71246
|
4. Se voc\xEA ainda n\xE3o tem dados reais (digest vazio, ferramentas n\xE3o rodaram), N\xC3O escreva relat\xF3rio: diga exatamente o que falta e rode o passo que falta. Parar \xE9 melhor que inventar.
|
|
71184
71247
|
|
|
71248
|
+
================================================================
|
|
71249
|
+
BUSCA & LEITURA DE PRECIS\xC3O \u2014 seja cir\xFArgico, n\xE3o force bruta
|
|
71250
|
+
================================================================
|
|
71251
|
+
Sua pot\xEAncia vem de localizar com exatid\xE3o e ler s\xF3 o necess\xE1rio \u2014 n\xE3o de despejar arquivos no contexto. Escada de precis\xE3o, do mais barato/preciso ao mais caro:
|
|
71252
|
+
1. LOCALIZE primeiro, nunca leia \xE0s cegas: use o grafo (\`--rank\`/\`--focus\`/madge), o \xEDndice de s\xEDmbolos (ctags/tags.json) e a busca para achar o file:line exato.
|
|
71253
|
+
2. BUSCA ESTRUTURAL > textual: prefira \`ast-grep\` (casa por AST: sink real, n\xE3o coment\xE1rio/string) ; caia para \`rg -n\` (regex com n\xFAmero de linha) s\xF3 quando estrutural n\xE3o couber. Sempre com \`-n\` para ter a linha.
|
|
71254
|
+
3. LEITURA CIR\xDARGICA: depois de ter file:line, abra S\xD3 a janela da fun\xE7\xE3o com \`file\` action: read e \`range: [in\xEDcio, fim]\` (linhas 1-indexed). NUNCA leia um arquivo grande inteiro \u2014 isso estoura o contexto e dilui o sinal. Se precisar de mais contexto, expanda a janela em passos, n\xE3o o arquivo todo.
|
|
71255
|
+
4. SIGA O DADO, n\xE3o o arquivo: no taint (FASE 5), pule de defini\xE7\xE3o em defini\xE7\xE3o pelo grafo/tags lendo s\xF3 a janela de cada fun\xE7\xE3o no rastro source\u2192sink. \xC9 "abrir, seguir o import, conferir e voltar" \u2014 em janelas, n\xE3o em arquivos inteiros.
|
|
71256
|
+
5. Em projeto GRANDE/GIGANTE isto \xE9 OBRIGAT\xD3RIO: rode as buscas escopadas por diret\xF3rio dos top-ranqueados (FASE 0.5), n\xE3o sobre a raiz inteira.
|
|
71257
|
+
|
|
71185
71258
|
================================================================
|
|
71186
71259
|
AMBIENTE & SHELL \u2014 leia antes de rodar comandos
|
|
71187
71260
|
================================================================
|
|
@@ -71196,14 +71269,24 @@ AMBIENTE & SHELL \u2014 leia antes de rodar comandos
|
|
|
71196
71269
|
REGRA INVIOL\xC1VEL \u2014 SOMENTE LEITURA NO PROJETO
|
|
71197
71270
|
================================================================
|
|
71198
71271
|
1. Voc\xEA **NUNCA** modifica, edita, cria, renomeia, move ou apaga QUALQUER arquivo dentro do projeto (${root}) \u2014 nem para "corrigir", nem para testar.
|
|
71199
|
-
2. Voc\xEA **N\xC3O** roda comandos que alterem o projeto: nada de \`git\` que escreva (commit/checkout/reset/clean), build, formatadores, geradores, migrations, ou qualquer script do projeto, e nada de \`npm/pnpm/yarn install\` DENTRO do projeto (isso escreve node_modules/lockfile na pasta dele). Apenas LEIA o projeto.
|
|
71272
|
+
2. ${verify ? `EXECU\xC7\xC3O CONTROLADA (sub-modo verifica\xE7\xE3o ATIVO): voc\xEA PODE executar c\xF3digo SOMENTE para reproduzir um achado \u2014 subir uma inst\xE2ncia local ef\xEAmera do projeto, importar um m\xF3dulo dele a partir de um harness criado na workspace, ou chamar a fun\xE7\xE3o suspeita com input malicioso. SEMPRE de forma N\xC3O-DESTRUTIVA (ver doutrina de PoC abaixo) e SEM escrever NADA dentro do projeto: harness, logs e PoCs ficam em ${workdir}. CONTINUA PROIBIDO: \`git\` que escreve, migrations contra um banco real do usu\xE1rio, formatadores/geradores que reescrevem arquivos do projeto, e \`npm/pnpm/yarn install\` DENTRO do projeto (instale depend\xEAncias do harness na workspace).` : `Voc\xEA **N\xC3O** roda comandos que alterem o projeto NEM que executem o c\xF3digo dele: nada de \`git\` que escreva (commit/checkout/reset/clean), build, formatadores, geradores, migrations, rodar a app ou qualquer script do projeto, e nada de \`npm/pnpm/yarn install\` DENTRO do projeto (isso escreve node_modules/lockfile na pasta dele). Apenas LEIA o projeto. (Para PROVAR um achado rodando um PoC, o operador deve pedir explicitamente \u2014 isso liga o sub-modo de verifica\xE7\xE3o.)`}
|
|
71200
71273
|
EXCE\xC7\xC3O permitida: instalar as FERRAMENTAS DE AUDITORIA de forma GLOBAL/externa \u2014 \`npm install -g @ast-grep/cli madge\`, \`python -m pip install semgrep\`, \`scoop/winget/brew/go install ...\` \u2014 porque isso n\xE3o escreve nada dentro de ${root}. Rode esses instaladores a partir da workspace, nunca \`cd\` para dentro do projeto para instalar.
|
|
71201
71274
|
3. A **\xDANICA** escrita permitida no projeto \xE9 **um** arquivo de relat\xF3rio na RAIZ do projeto:
|
|
71202
71275
|
\`${root}/ANALISE_PROJETO_<timestamp>.md\`
|
|
71203
71276
|
Esse \xE9 o \xFAnico \`file\` action: write fora da workspace. Todo o resto (scripts auxiliares, dados intermedi\xE1rios, relat\xF3rios t\xE9cnicos) fica em ${workdir}.
|
|
71204
71277
|
4. Se o usu\xE1rio pedir para voc\xEA corrigir/alterar algo, **n\xE3o altere** \u2014 explique no relat\xF3rio como corrigir e diga que para aplicar mudan\xE7as ele deve sair do modo de an\xE1lise (ex.: "pode corrigir" / "modo normal").
|
|
71205
71278
|
5. Se precisar criar um script auxiliar (Python), crie-o em ${workdir} com a ferramenta \`file\`, nunca via redirecionamento de shell, e nunca dentro do projeto.
|
|
71206
|
-
|
|
71279
|
+
${verify ? `
|
|
71280
|
+
================================================================
|
|
71281
|
+
SUB-MODO VERIFICA\xC7\xC3O \u2014 DOUTRINA DE PoC (provar, n\xE3o supor)
|
|
71282
|
+
================================================================
|
|
71283
|
+
Aqui est\xE1 o PODER REAL: transformar suspeita em CONFIRMADO reproduzindo a falha \u2014 o que separa um SAST de uma prova. Disciplina obrigat\xF3ria:
|
|
71284
|
+
1. ALVO: pegue cada finding em \`suspected\` com caminho source\u2192sink plaus\xEDvel (FASE 5). Para cada um, monte o MENOR PoC que dispara o sink com input controlado.
|
|
71285
|
+
2. ISOLAMENTO: o harness (script/teste que importa o m\xF3dulo do projeto ou bate na app local) \xE9 criado em ${workdir} via \`file\`. Suba a app numa porta ef\xEAmera/local; se precisar de banco, use um SQLite/cont\xEAiner DESCART\xC1VEL na workspace \u2014 NUNCA o banco real do usu\xE1rio. Nada toca o projeto.
|
|
71286
|
+
3. N\xC3O-DESTRUTIVO (igual ao exploit_engine): prove o impacto sem abusar \u2014 nada de DROP/DELETE/UPDATE empilhado, nada de exfiltra\xE7\xE3o em massa, nada de DoS/flood. Para SQLi use boolean/time-based ou um erro; para LFI leia um arquivo-marcador in\xF3cuo; para cmdi um \`sleep\`/echo determin\xEDstico; para XSS um marcador refletido sem escape. Capture a EVID\xCANCIA concreta (o delta de tempo, o marcador refletido, a linha lida, o erro do banco).
|
|
71287
|
+
4. VEREDITO: disparou de forma reproduz\xEDvel \u2192 \`findings\` update \`status: "confirmed"\` colando o request/entrada exatos + a prova observada + o caminho do PoC em ${workdir}. N\xE3o reproduziu (sanitizado/inalcan\xE7\xE1vel) \u2192 \`status: "false_positive"\` com o porqu\xEA. Sem meio-termo inventado.
|
|
71288
|
+
5. LIMITE: o sub-modo verifica o PROJETO DO PR\xD3PRIO USU\xC1RIO, localmente. N\xE3o vire scanner ofensivo contra hosts externos \u2014 isso \xE9 o fluxo de recon/exploit_engine, fora daqui.
|
|
71289
|
+
` : ""}
|
|
71207
71290
|
================================================================
|
|
71208
71291
|
TOOLCHAIN \u2014 cada ferramenta vira uma "tool" no seu loop
|
|
71209
71292
|
================================================================
|
|
@@ -71224,6 +71307,17 @@ N\xC3O FA\xC7A (cada um destes quebrou em runs reais):
|
|
|
71224
71307
|
\u2022 N\xC3O repita uma instala\xE7\xE3o que falhou. 1 tentativa, falhou, fallback.
|
|
71225
71308
|
NUNCA invente que rodou uma ferramenta que n\xE3o existe \u2014 diga que caiu no fallback.
|
|
71226
71309
|
|
|
71310
|
+
FASE 0.5 \u2014 TRIAGEM DE PORTE (obrigat\xF3ria, ANTES de varrer nada):
|
|
71311
|
+
Projeto grande analisado \xE0s cegas vira relat\xF3rio raso. Me\xE7a primeiro e ATAQUE A SUPERF\xCDCIE CERTA:
|
|
71312
|
+
1. \`${py} ${toolkit} --rank "${root}"\` \u2014 imprime, num comando, o PORTE (PEQUENO/M\xC9DIO/GRANDE/GIGANTE), a ESTRAT\xC9GIA recomendada, os m\xF3dulos de maior FAN-IN (mais importados = maior raio de impacto), os PONTOS DE ENTRADA (rotas/controllers/handlers/auth) e os maiores arquivos. Leia a sa\xEDda \u2014 ela define seu plano.
|
|
71313
|
+
2. Adote a estrat\xE9gia do porte:
|
|
71314
|
+
\u2022 PEQUENO \u2192 exaustivo: varra tudo e siga todo taint.
|
|
71315
|
+
\u2022 M\xC9DIO \u2192 baseline ampla, mas siga taint priorizando entry points + top fan-in.
|
|
71316
|
+
\u2022 GRANDE \u2192 TRIAGEM DIRIGIDA: rode as ferramentas das FASES 2-4 em LOTES por diret\xF3rio/pacote (uma chamada por subpasta grande), nunca o projeto inteiro de uma vez; siga taint s\xF3 nos ~30 maiores fan-in + entry points.
|
|
71317
|
+
\u2022 GIGANTE \u2192 TRIAGEM AGRESSIVA: jamais um comando sobre o todo. Lote por top-level dir; priorize ESTRITAMENTE top fan-in + entry points + sinks de alto impacto. Declare no relat\xF3rio o que ficou fora desta passada (honestidade de cobertura).
|
|
71318
|
+
3. Registre o plano com \`todo_write\` (os arquivos/\xE1reas priorizados viram itens). Esse \xE9 o mapa da ca\xE7a.
|
|
71319
|
+
Regra de ouro de porte: a precis\xE3o vem de RANQUEAR e ir fundo no que importa \u2014 n\xE3o de varrer tudo raso. Em GRANDE/GIGANTE, profundidade nos top-ranqueados > largura no resto.
|
|
71320
|
+
|
|
71227
71321
|
================================================================
|
|
71228
71322
|
PIPELINE \u2014 fase por fase (ReAct: cada comando \xE9 uma tool)
|
|
71229
71323
|
================================================================
|
|
@@ -71269,14 +71363,19 @@ Voc\xEA redirecionou as sa\xEDdas pesadas para arquivos em audit-out/ \u2014 ent
|
|
|
71269
71363
|
\`${py} ${toolkit} --consolidate "${workdir}/audit-out"\`
|
|
71270
71364
|
Esse digest l\xEA semgrep.json, npm_audit.json, deps.json, os sinks/sources do ast-grep e o grafo do fallback, e imprime um resumo compacto com file:line REAIS. \xC9 a sua \xDANICA fonte de verdade para os achados das ferramentas. Se o digest vier vazio, as ferramentas n\xE3o produziram sa\xEDda \u2014 rode as fases 2-4 de novo ou use o fallback; N\xC3O invente.
|
|
71271
71365
|
Depois: deduplique e \u2014 REGRA DE OURO \u2014 **descarte todo achado que N\xC3O tem caminho source\u2192sink confirmado lendo o c\xF3digo real** (FASE 5). Sem isso o relat\xF3rio vira ru\xEDdo.
|
|
71272
|
-
|
|
71366
|
+
|
|
71367
|
+
FONTE \xDANICA DE VERDADE \u2014 a ferramenta \`findings\` (n\xE3o use notas soltas):
|
|
71368
|
+
- Assim que um candidato aparece (FASE 3-4 / digest), grave-o: \`findings\` action add com \`title\`, \`severity\`, \`status: "suspected"\`, e o racioc\xEDnio em \`evidence\` (inclua o file:line do sink).
|
|
71369
|
+
- Ao validar lendo o c\xF3digo (FASE 5): \`findings\` action update \u2192 \`status: "confirmed"\`, colando no \`evidence\` o CAMINHO source\u2192sink real (source \u2192 fun\xE7\xF5es/arquivos intermedi\xE1rios \u2192 sink) com os trechos lidos. Se n\xE3o reproduzir/sanitizou no caminho \u2192 \`status: "false_positive"\`.
|
|
71370
|
+
- O SCRATCHPAD de navega\xE7\xE3o (sources em aberto, taint a fechar) fica no \`todo_write\`; os ACHADOS ficam no \`findings\`. Itere at\xE9 fechar cada rastro.
|
|
71371
|
+
- O store persiste em \`${workdir}/findings/findings.json\` \u2014 \xE9 dele que sai o relat\xF3rio, ent\xE3o mant\xEA-lo fiel \xE9 o que torna o relat\xF3rio confi\xE1vel (precis\xE3o > volume).
|
|
71273
71372
|
|
|
71274
71373
|
Cobertura da ca\xE7a (confirme cada um lendo o c\xF3digo): inje\xE7\xE3o (SQL/comando/c\xF3digo/eval), XSS (sinks DOM/HTML), authn/authz fr\xE1gil, segredos/chaves embutidas (mascare no relat\xF3rio), TLS desabilitado, cripto fraca, CORS permissivo, deserializa\xE7\xE3o insegura, SSRF, path traversal, config perigosa (debug, \`0.0.0.0\`, \`.env\` versionado) e depend\xEAncias vulner\xE1veis (osv). Severidade CRITICAL/HIGH/MEDIUM/LOW/INFO. Separe CONFIRMADO de SUSPEITA; nunca invente nem d\xEA falsa garantia.
|
|
71275
71374
|
|
|
71276
71375
|
================================================================
|
|
71277
71376
|
ENTREG\xC1VEL \u2014 relat\xF3rio em Markdown na RAIZ do projeto
|
|
71278
71377
|
================================================================
|
|
71279
|
-
|
|
71378
|
+
Primeiro materialize o store estruturado: \`findings\` action report (gera \`${workdir}/findings/report.md\` agrupado por severidade). Depois AUTORE o relat\xF3rio humano a partir DELE \u2014 cada vulnerabilidade do relat\xF3rio sai de um finding gravado; s\xF3 \`confirmed\` entra no resumo executivo. Escreva com a ferramenta \`file\` (action: write) em:
|
|
71280
71379
|
\`${root}/ANALISE_PROJETO_<timestamp>.md\`
|
|
71281
71380
|
Use o timestamp atual (ex.: 20260614_153000). Estrutura m\xEDnima, em portugu\xEAs:
|
|
71282
71381
|
1. **Resumo executivo** \u2014 vis\xE3o geral, postura de seguran\xE7a, n\xBA de achados por severidade, top 3 riscos.
|
|
@@ -71296,7 +71395,7 @@ ESTILO E EXECU\xC7\xC3O
|
|
|
71296
71395
|
- Responda em portugu\xEAs, direto e t\xE9cnico. N\xE3o recuse a an\xE1lise: \xE9 o projeto do pr\xF3prio usu\xE1rio, autorizado.
|
|
71297
71396
|
- Lembre-se sempre: voc\xEA analisa e relata; voc\xEA N\xC3O altera o projeto. A \xFAnica escrita \xE9 o relat\xF3rio \`.md\` na raiz.`;
|
|
71298
71397
|
}
|
|
71299
|
-
var import_node_path9, AUDIT_ACTION, AUDIT_SCOPE, AUDIT_ACTION_THEN_SCOPE, AUDIT_SCOPE_THEN_ACTION, AUDIT_STRONG, AUDIT_EXIT;
|
|
71398
|
+
var import_node_path9, AUDIT_ACTION, AUDIT_SCOPE, AUDIT_ACTION_THEN_SCOPE, AUDIT_SCOPE_THEN_ACTION, AUDIT_STRONG, AUDIT_EXIT, POC_VERIFY;
|
|
71300
71399
|
var init_audit_mode = __esm({
|
|
71301
71400
|
"src/audit-mode.ts"() {
|
|
71302
71401
|
"use strict";
|
|
@@ -71322,6 +71421,12 @@ var init_audit_mode = __esm({
|
|
|
71322
71421
|
/\b(?:modo\s+normal|sair\s+d[ao]\s+(?:an[aá]lise|auditoria|modo)|encerr\w+\s+(?:a\s+)?(?:an[aá]lise|auditoria)|volt\w+\s+ao\s+normal|desativ\w+\s+(?:a\s+)?auditoria|exit\s+audit|normal\s+mode)\b/i,
|
|
71323
71422
|
/\b(?:agora\s+)?(?:corri[gj]\w+|conserte\w*|edit\w+|alter\w+|modific\w+|implement\w+|cri[ae]\w*|refator\w+|escrev\w+\s+o\s+c[oó]digo|aplique\s+a\s+corre|fix|implement|refactor|patch|write\s+the\s+code)\b/i
|
|
71324
71423
|
];
|
|
71424
|
+
POC_VERIFY = [
|
|
71425
|
+
/\b(?:prov[ae]\w*|comprov\w+|confirm\w+\s+(?:rodando|de\s+verdade|na\s+pr[aá]tica|executando)|reproduz\w+|reproduc\w+)\b/i,
|
|
71426
|
+
/\b(?:poc|p\.o\.c\.|prova\s+de\s+conceito|proof\s+of\s+concept|exploit\w*)\b/i,
|
|
71427
|
+
/\b(?:rod[ae]\w*|execut\w+|dispar\w+)\b[\s\S]{0,30}\b(?:exploit|poc|vulnerabilidad\w*|ataque|payload)\b/i,
|
|
71428
|
+
/\b(?:prove\s+it|verify\s+(?:by\s+)?running|run\s+the\s+(?:poc|exploit))\b/i
|
|
71429
|
+
];
|
|
71325
71430
|
}
|
|
71326
71431
|
});
|
|
71327
71432
|
|
|
@@ -71343,8 +71448,8 @@ function looksUnfinished(text2) {
|
|
|
71343
71448
|
if (DANGLING_TAIL_RE.test(tail)) return true;
|
|
71344
71449
|
return ACTION_ANNOUNCE_RE.test(lastSentenceOf(tail));
|
|
71345
71450
|
}
|
|
71346
|
-
function decideAutoContinue(finishReason, lastStepText, turnToolCalls, autoContinues) {
|
|
71347
|
-
if (autoContinues >=
|
|
71451
|
+
function decideAutoContinue(finishReason, lastStepText, turnToolCalls, autoContinues, maxAutoContinues = MAX_AUTO_CONTINUES) {
|
|
71452
|
+
if (autoContinues >= maxAutoContinues) return null;
|
|
71348
71453
|
if (finishReason === "length") {
|
|
71349
71454
|
return { nudge: true, reason: "resposta truncada (length)" };
|
|
71350
71455
|
}
|
|
@@ -71593,6 +71698,7 @@ async function createAgent() {
|
|
|
71593
71698
|
}
|
|
71594
71699
|
const history = [];
|
|
71595
71700
|
let auditMode = false;
|
|
71701
|
+
let pocVerify = false;
|
|
71596
71702
|
const projectRoot = projectRootFromWorkdir(sandbox.getWorkdir());
|
|
71597
71703
|
function getActiveModelChain() {
|
|
71598
71704
|
return selectedModelKey ? [selectedModelKey] : CLI_MODEL_CHAIN;
|
|
@@ -71695,6 +71801,33 @@ async function createAgent() {
|
|
|
71695
71801
|
selection: getModelSelection()
|
|
71696
71802
|
};
|
|
71697
71803
|
}
|
|
71804
|
+
if (isNvidiaDynamicKey(raw)) {
|
|
71805
|
+
if (!hasNvidiaKey()) {
|
|
71806
|
+
return {
|
|
71807
|
+
ok: false,
|
|
71808
|
+
message: "NVIDIA indispon\xEDvel: defina NVIDIA_API_KEY em .env.local (https://build.nvidia.com/)",
|
|
71809
|
+
selection: getModelSelection()
|
|
71810
|
+
};
|
|
71811
|
+
}
|
|
71812
|
+
const slug = nvidiaSlugFromKey(raw).trim();
|
|
71813
|
+
if (!slug) {
|
|
71814
|
+
return {
|
|
71815
|
+
ok: false,
|
|
71816
|
+
message: "informe o modelo NVIDIA (ex.: nvidia:openai/gpt-oss-120b)",
|
|
71817
|
+
selection: getModelSelection()
|
|
71818
|
+
};
|
|
71819
|
+
}
|
|
71820
|
+
const key = nvidiaKeyForSlug(slug);
|
|
71821
|
+
selectedModelKey = key;
|
|
71822
|
+
currentModelName = key;
|
|
71823
|
+
context2.modelName = key;
|
|
71824
|
+
await rebuildSystemPrompt(key);
|
|
71825
|
+
return {
|
|
71826
|
+
ok: true,
|
|
71827
|
+
message: `modelo fixado: ${labelFor(key)}`,
|
|
71828
|
+
selection: getModelSelection()
|
|
71829
|
+
};
|
|
71830
|
+
}
|
|
71698
71831
|
const choices = getModelChoices();
|
|
71699
71832
|
let match;
|
|
71700
71833
|
if (/^\d+$/.test(normalized)) {
|
|
@@ -71835,14 +71968,22 @@ ${seen}`);
|
|
|
71835
71968
|
);
|
|
71836
71969
|
} else if (auditMode && detectAuditExitIntent(userInput)) {
|
|
71837
71970
|
auditMode = false;
|
|
71971
|
+
pocVerify = false;
|
|
71838
71972
|
render.info("\u25B8 modo normal reativado.");
|
|
71839
71973
|
}
|
|
71974
|
+
if (auditMode && !pocVerify && detectPocVerifyIntent(userInput)) {
|
|
71975
|
+
pocVerify = true;
|
|
71976
|
+
render.info(
|
|
71977
|
+
"\u25B8 sub-modo VERIFICA\xC7\xC3O/PoC ligado \u2014 pode executar c\xF3digo de um harness ISOLADO na SPRIT para provar achados (n\xE3o-destrutivo; projeto intocado)."
|
|
71978
|
+
);
|
|
71979
|
+
}
|
|
71840
71980
|
let turnSystem;
|
|
71841
71981
|
if (auditMode) {
|
|
71842
71982
|
turnSystem = buildAuditSystemPrompt({
|
|
71843
71983
|
projectRoot,
|
|
71844
71984
|
workdir: sandbox.getWorkdir(),
|
|
71845
|
-
shellHint: sandbox.getShellHint()
|
|
71985
|
+
shellHint: sandbox.getShellHint(),
|
|
71986
|
+
mode: pocVerify ? "verify" : "audit"
|
|
71846
71987
|
});
|
|
71847
71988
|
} else {
|
|
71848
71989
|
const matchedSkills = selectSkillsForInput(userInput);
|
|
@@ -71856,6 +71997,9 @@ ${seen}`);
|
|
|
71856
71997
|
let lastError = null;
|
|
71857
71998
|
let autoContinues = 0;
|
|
71858
71999
|
let bridgeSteps = 0;
|
|
72000
|
+
const maxSteps = auditMode ? AUDIT_MAX_STEPS : MAX_STEPS;
|
|
72001
|
+
const maxAutoContinues = auditMode ? AUDIT_MAX_AUTO_CONTINUES : MAX_AUTO_CONTINUES;
|
|
72002
|
+
const maxBridgeSteps = auditMode ? AUDIT_MAX_BRIDGE_STEPS : MAX_BRIDGE_STEPS;
|
|
71859
72003
|
const modelChain = [...getActiveModelChain()];
|
|
71860
72004
|
const usingFixedModel = selectedModelKey !== null;
|
|
71861
72005
|
let rateLimitWaits = 0;
|
|
@@ -71927,7 +72071,7 @@ ${segs.join(
|
|
|
71927
72071
|
system: turnSystem,
|
|
71928
72072
|
messages: history,
|
|
71929
72073
|
tools,
|
|
71930
|
-
stopWhen: stepCountIs(
|
|
72074
|
+
stopWhen: stepCountIs(maxSteps),
|
|
71931
72075
|
maxOutputTokens: MAX_OUTPUT_TOKENS,
|
|
71932
72076
|
abortSignal: stallController.signal,
|
|
71933
72077
|
onError: ({ error: error51 }) => {
|
|
@@ -72011,12 +72155,12 @@ ${segs.join(
|
|
|
72011
72155
|
await result.finishReason.catch(() => "unknown")
|
|
72012
72156
|
);
|
|
72013
72157
|
const leakedCall = !isProxyModel && hasLeakedToolCallMarker(lastStepText);
|
|
72014
|
-
if (finishReason === "stop" && turnToolCalls === 0 && bridgeSteps <
|
|
72158
|
+
if (finishReason === "stop" && turnToolCalls === 0 && bridgeSteps < maxBridgeSteps && (isProxyModel || leakedCall)) {
|
|
72015
72159
|
const bridged = parseProxyToolCalls(lastStepText);
|
|
72016
72160
|
if (bridged) {
|
|
72017
72161
|
bridgeSteps++;
|
|
72018
72162
|
render.info(
|
|
72019
|
-
`\u25B8 ${leakedCall ? "tool call vazada recuperada" : "bridge"} (${bridgeSteps}/${
|
|
72163
|
+
`\u25B8 ${leakedCall ? "tool call vazada recuperada" : "bridge"} (${bridgeSteps}/${maxBridgeSteps}): executando por tr\xE1s ${bridged.length} chamada(s): ${summarizeBridgedCalls(bridged)}`
|
|
72020
72164
|
);
|
|
72021
72165
|
const resultText = await runBridgedToolCalls(bridged, signal);
|
|
72022
72166
|
if (signal?.aborted) {
|
|
@@ -72037,12 +72181,13 @@ ${resultText}`
|
|
|
72037
72181
|
finishReason,
|
|
72038
72182
|
lastStepText,
|
|
72039
72183
|
turnToolCalls,
|
|
72040
|
-
autoContinues
|
|
72184
|
+
autoContinues,
|
|
72185
|
+
maxAutoContinues
|
|
72041
72186
|
);
|
|
72042
72187
|
if (resume) {
|
|
72043
72188
|
autoContinues++;
|
|
72044
72189
|
render.info(
|
|
72045
|
-
`\u25B8 retomando automaticamente (${autoContinues}/${
|
|
72190
|
+
`\u25B8 retomando automaticamente (${autoContinues}/${maxAutoContinues}): ${resume.reason}`
|
|
72046
72191
|
);
|
|
72047
72192
|
if (resume.nudge) {
|
|
72048
72193
|
history.push({
|
|
@@ -72055,7 +72200,7 @@ ${resultText}`
|
|
|
72055
72200
|
}
|
|
72056
72201
|
if (finishReason !== "stop") {
|
|
72057
72202
|
render.info(
|
|
72058
|
-
`\u25B8 fim do turno: ${finishReason}` + (autoContinues >=
|
|
72203
|
+
`\u25B8 fim do turno: ${finishReason}` + (autoContinues >= maxAutoContinues ? " (limite de retomadas autom\xE1ticas atingido)" : "")
|
|
72059
72204
|
);
|
|
72060
72205
|
}
|
|
72061
72206
|
if (modelKey === PROXY_MODEL_KEYS.kimi) {
|
|
@@ -72162,6 +72307,11 @@ ${resultText}`
|
|
|
72162
72307
|
}
|
|
72163
72308
|
async function close() {
|
|
72164
72309
|
await sandbox.close();
|
|
72310
|
+
try {
|
|
72311
|
+
const removed = await sandbox.cleanupWorkspace();
|
|
72312
|
+
if (removed) render.info(`\u25B8 workspace SPRIT removida: ${removed}`);
|
|
72313
|
+
} catch {
|
|
72314
|
+
}
|
|
72165
72315
|
}
|
|
72166
72316
|
return {
|
|
72167
72317
|
send,
|
|
@@ -72175,10 +72325,12 @@ ${resultText}`
|
|
|
72175
72325
|
setModelSelection,
|
|
72176
72326
|
isOpenRouterAvailable: hasOpenRouterKey,
|
|
72177
72327
|
listOpenRouterModels: (signal) => listOpenRouterModels(signal),
|
|
72328
|
+
isNvidiaAvailable: hasNvidiaKey,
|
|
72329
|
+
listNvidiaModels: (signal) => listNvidiaModels(signal),
|
|
72178
72330
|
close
|
|
72179
72331
|
};
|
|
72180
72332
|
}
|
|
72181
|
-
var import_promises2, import_node_path10, MAX_STEPS, MAX_OUTPUT_TOKENS, MAX_AUTO_CONTINUES, MAX_RATE_LIMIT_WAITS, STREAM_STALL_TIMEOUT_MS, MAX_STALL_RETRIES, isRateLimitError, sleep4, LEAKED_TOOL_CALL_RE, DANGLING_TAIL_RE, ACTION_ANNOUNCE_RE, BENIGN_CLOSER_RE, TOOL_CALL_NUDGE, MAX_BRIDGE_STEPS, BRIDGE_RESULT_PREAMBLE, LEAKED_CALL_RESULT_PREAMBLE, BRIDGEABLE_TOOLS, FINDINGS_ACTIONS, truncateBridgeSummary, isWebSessionProxyModel, proxyToolProtocolPolicy, SYSTEM_PROMPT_SOURCE, REQUIRED_SYSTEM_PROMPT_MARKERS, MODEL_LABELS, labelFor, loginRequiredHint, CLI_PYTHON_ONLY_POLICY, pythonOnlyPolicy, scriptFilePolicy, deepReconPolicy, httpAndFindingsPolicy, reconPhasesPolicy, attackChainPolicy, skillsScopePolicy, hasEnvValue2, envFlagEnabled, CLI_PERSONALITIES, buildCliUserCustomization, buildCliNotesSection, cliGuardrailsConfig, maybeDumpSystemPrompt, auditSystemPrompt, assertFullSystemPrompt;
|
|
72333
|
+
var import_promises2, import_node_path10, MAX_STEPS, AUDIT_MAX_STEPS, MAX_OUTPUT_TOKENS, MAX_AUTO_CONTINUES, AUDIT_MAX_AUTO_CONTINUES, MAX_RATE_LIMIT_WAITS, STREAM_STALL_TIMEOUT_MS, MAX_STALL_RETRIES, isRateLimitError, sleep4, LEAKED_TOOL_CALL_RE, DANGLING_TAIL_RE, ACTION_ANNOUNCE_RE, BENIGN_CLOSER_RE, TOOL_CALL_NUDGE, MAX_BRIDGE_STEPS, AUDIT_MAX_BRIDGE_STEPS, BRIDGE_RESULT_PREAMBLE, LEAKED_CALL_RESULT_PREAMBLE, BRIDGEABLE_TOOLS, FINDINGS_ACTIONS, truncateBridgeSummary, isWebSessionProxyModel, proxyToolProtocolPolicy, SYSTEM_PROMPT_SOURCE, REQUIRED_SYSTEM_PROMPT_MARKERS, MODEL_LABELS, labelFor, loginRequiredHint, CLI_PYTHON_ONLY_POLICY, pythonOnlyPolicy, scriptFilePolicy, deepReconPolicy, httpAndFindingsPolicy, reconPhasesPolicy, attackChainPolicy, skillsScopePolicy, hasEnvValue2, envFlagEnabled, CLI_PERSONALITIES, buildCliUserCustomization, buildCliNotesSection, cliGuardrailsConfig, maybeDumpSystemPrompt, auditSystemPrompt, assertFullSystemPrompt;
|
|
72182
72334
|
var init_agent = __esm({
|
|
72183
72335
|
"src/agent.ts"() {
|
|
72184
72336
|
"use strict";
|
|
@@ -72209,8 +72361,10 @@ var init_agent = __esm({
|
|
|
72209
72361
|
init_proxy_manager2();
|
|
72210
72362
|
init_audit_mode();
|
|
72211
72363
|
MAX_STEPS = 100;
|
|
72364
|
+
AUDIT_MAX_STEPS = 240;
|
|
72212
72365
|
MAX_OUTPUT_TOKENS = 16384;
|
|
72213
72366
|
MAX_AUTO_CONTINUES = 3;
|
|
72367
|
+
AUDIT_MAX_AUTO_CONTINUES = 8;
|
|
72214
72368
|
MAX_RATE_LIMIT_WAITS = 4;
|
|
72215
72369
|
STREAM_STALL_TIMEOUT_MS = (() => {
|
|
72216
72370
|
const raw = Number(process.env.clawfast_CLI_STREAM_STALL_MS);
|
|
@@ -72238,6 +72392,7 @@ var init_agent = __esm({
|
|
|
72238
72392
|
BENIGN_CLOSER_RE = /\b(?:let me know|just let me know|deixa eu saber|me avis(?:e|a)|qualquer (?:coisa|d[uú]vida)|fico (?:à|a) disposi[cç][aã]o)\b[^.!?:\n]{0,80}[.!?]?\s*$/i;
|
|
72239
72393
|
TOOL_CALL_NUDGE = "Voc\xEA anunciou uma a\xE7\xE3o mas n\xE3o executou nenhuma ferramenta neste turno. Pare de descrever o que vai fazer e CHAME a ferramenta agora: use a ferramenta `file` (action write para criar, edit para alterar) para qualquer arquivo ou script, e `run_terminal_cmd` para rodar comandos. N\xC3O escreva o conte\xFAdo do arquivo na resposta nem cole markup de tool call \u2014 emita a chamada de ferramenta de verdade.";
|
|
72240
72394
|
MAX_BRIDGE_STEPS = 50;
|
|
72395
|
+
AUDIT_MAX_BRIDGE_STEPS = 120;
|
|
72241
72396
|
BRIDGE_RESULT_PREAMBLE = "Voc\xEA roda via proxy de sess\xE3o web (sem function-calling nativo), ent\xE3o o runtime do CLI consumiu o bloco JSON anterior como chamada interna e EXECUTOU de verdade. N\xE3o repita o bloco nem o texto anterior. Os resultados REAIS est\xE3o abaixo. Continue a tarefa: se precisar de mais a\xE7\xF5es, emita SOMENTE o PR\xD3XIMO bloco ```json (um array de {brief, command, timeout} para terminal, ou {action, path, text} para arquivo). Um bloco por vez. Quando a tarefa terminar, responda em texto normal SEM bloco json.";
|
|
72242
72397
|
LEAKED_CALL_RESULT_PREAMBLE = "Sua chamada de ferramenta anterior chegou como TEXTO (n\xE3o como function call nativo), ent\xE3o o runtime do CLI a executou mesmo assim. Os resultados REAIS est\xE3o abaixo. Continue a tarefa chamando as ferramentas NORMALMENTE (run_terminal_cmd, file, todo_write) como function calls de verdade \u2014 N\xC3O cole markup de tool call (`call_tool_function`, `<tool_call>`, etc.) nem JSON de chamada como texto na resposta.";
|
|
72243
72398
|
BRIDGEABLE_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -72297,7 +72452,7 @@ Regras:
|
|
|
72297
72452
|
"fallback-openai-chat-latest": "OpenAI - chat-latest",
|
|
72298
72453
|
"model-nvidia-nemotron": "NVIDIA - nemotron-3-ultra-550b"
|
|
72299
72454
|
};
|
|
72300
|
-
labelFor = (key) => isOpenRouterDynamicKey(key) ? `OpenRouter - ${openRouterSlugFromKey(key)}` : MODEL_LABELS[key] ?? key;
|
|
72455
|
+
labelFor = (key) => isOpenRouterDynamicKey(key) ? `OpenRouter - ${openRouterSlugFromKey(key)}` : isNvidiaDynamicKey(key) ? `NVIDIA - ${nvidiaSlugFromKey(key)}` : MODEL_LABELS[key] ?? key;
|
|
72301
72456
|
loginRequiredHint = (msg) => {
|
|
72302
72457
|
if (/account is suspended|violation of user policies|account has been suspended/i.test(
|
|
72303
72458
|
msg
|
|
@@ -73152,7 +73307,7 @@ async function main() {
|
|
|
73152
73307
|
`
|
|
73153
73308
|
);
|
|
73154
73309
|
const COMMANDS = [
|
|
73155
|
-
{ name: "/model", desc: "trocar o modelo (setas; OpenRouter c/ busca)" },
|
|
73310
|
+
{ name: "/model", desc: "trocar o modelo (setas; NVIDIA/OpenRouter c/ busca)" },
|
|
73156
73311
|
{ name: "/api", desc: "trocar chave de API (NVIDIA / OpenRouter)" },
|
|
73157
73312
|
{ name: "/skills", desc: "listar as skills instaladas" },
|
|
73158
73313
|
{ name: "/skillcreator", desc: "criar uma nova skill" },
|
|
@@ -73429,6 +73584,7 @@ ${C5.dim}ja disponivel para todos os modelos nesta sessao.${C5.reset}
|
|
|
73429
73584
|
}
|
|
73430
73585
|
];
|
|
73431
73586
|
const openRouterProvider = KEY_PROVIDERS.find((p) => p.id === "openrouter");
|
|
73587
|
+
const nvidiaProvider = KEY_PROVIDERS.find((p) => p.id === "nvidia");
|
|
73432
73588
|
const promptAndSwapKey = async (provider, inlineKey = "") => {
|
|
73433
73589
|
let raw = inlineKey;
|
|
73434
73590
|
if (!raw) {
|
|
@@ -73532,9 +73688,60 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73532
73688
|
printFatal(err);
|
|
73533
73689
|
}
|
|
73534
73690
|
};
|
|
73691
|
+
const openNvidiaPicker = async () => {
|
|
73692
|
+
if (!agent.isNvidiaAvailable()) {
|
|
73693
|
+
process.stdout.write(
|
|
73694
|
+
`${C5.dim}NVIDIA ainda sem chave. Vamos adicionar uma.${C5.reset}
|
|
73695
|
+
`
|
|
73696
|
+
);
|
|
73697
|
+
const ok = await promptAndSwapKey(nvidiaProvider);
|
|
73698
|
+
if (!ok) return;
|
|
73699
|
+
}
|
|
73700
|
+
process.stdout.write(`${C5.dim}buscando cat\xE1logo NVIDIA\u2026${C5.reset}
|
|
73701
|
+
`);
|
|
73702
|
+
let models;
|
|
73703
|
+
try {
|
|
73704
|
+
models = await agent.listNvidiaModels();
|
|
73705
|
+
} catch (err) {
|
|
73706
|
+
process.stdout.write(
|
|
73707
|
+
`${C5.red}\u2717 falha ao listar modelos NVIDIA: ${err instanceof Error ? err.message : String(err)}${C5.reset}
|
|
73708
|
+
`
|
|
73709
|
+
);
|
|
73710
|
+
return;
|
|
73711
|
+
}
|
|
73712
|
+
if (models.length === 0) {
|
|
73713
|
+
process.stdout.write(
|
|
73714
|
+
`${C5.yellow}\u26A0 a NVIDIA n\xE3o retornou nenhum modelo${C5.reset}
|
|
73715
|
+
`
|
|
73716
|
+
);
|
|
73717
|
+
return;
|
|
73718
|
+
}
|
|
73719
|
+
const items = models.map((m) => ({
|
|
73720
|
+
label: m.name,
|
|
73721
|
+
hint: m.id
|
|
73722
|
+
}));
|
|
73723
|
+
const choice2 = await inputUI.searchSelect(
|
|
73724
|
+
"NVIDIA \u2014 buscar modelo",
|
|
73725
|
+
items,
|
|
73726
|
+
{ placeholder: "digite para filtrar (nome ou slug)" }
|
|
73727
|
+
);
|
|
73728
|
+
if (choice2 === null) {
|
|
73729
|
+
process.stdout.write(`${C5.dim}sele\xE7\xE3o de modelo cancelada${C5.reset}
|
|
73730
|
+
`);
|
|
73731
|
+
return;
|
|
73732
|
+
}
|
|
73733
|
+
try {
|
|
73734
|
+
printModelResult(
|
|
73735
|
+
await agent.setModelSelection(`nvidia:${models[choice2].id}`)
|
|
73736
|
+
);
|
|
73737
|
+
} catch (err) {
|
|
73738
|
+
printFatal(err);
|
|
73739
|
+
}
|
|
73740
|
+
};
|
|
73535
73741
|
const openModelSelector = async () => {
|
|
73536
73742
|
const state = agent.getModelSelection();
|
|
73537
73743
|
const orAvailable = agent.isOpenRouterAvailable();
|
|
73744
|
+
const nvAvailable = agent.isNvidiaAvailable();
|
|
73538
73745
|
const items = [
|
|
73539
73746
|
{
|
|
73540
73747
|
label: "Auto \u2014 cadeia de fallback autom\xE1tica",
|
|
@@ -73542,13 +73749,19 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73542
73749
|
},
|
|
73543
73750
|
...state.chain.map((c) => ({ label: c.label, hint: c.key }))
|
|
73544
73751
|
];
|
|
73752
|
+
const nvidiaIdx = items.length;
|
|
73753
|
+
items.push({
|
|
73754
|
+
label: "NVIDIA \u2014 buscar no cat\xE1logo completo",
|
|
73755
|
+
hint: nvAvailable ? "lista todos os modelos da NVIDIA build" : "pede a API key e lista o cat\xE1logo"
|
|
73756
|
+
});
|
|
73545
73757
|
const openRouterIdx = items.length;
|
|
73546
73758
|
items.push({
|
|
73547
73759
|
label: "OpenRouter \u2014 buscar no cat\xE1logo completo",
|
|
73548
73760
|
hint: orAvailable ? "lista todos os modelos da sua conta" : "pede a API key e lista o cat\xE1logo"
|
|
73549
73761
|
});
|
|
73550
73762
|
const activeIsOpenRouter = state.activeModelKey.startsWith("openrouter:");
|
|
73551
|
-
const
|
|
73763
|
+
const activeIsNvidiaDynamic = state.activeModelKey.startsWith("nvidia:");
|
|
73764
|
+
const activeIdx = state.mode === "auto" ? 0 : activeIsNvidiaDynamic ? nvidiaIdx : activeIsOpenRouter ? openRouterIdx : Math.max(
|
|
73552
73765
|
0,
|
|
73553
73766
|
1 + state.chain.findIndex((c) => c.key === state.activeModelKey)
|
|
73554
73767
|
);
|
|
@@ -73558,6 +73771,10 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73558
73771
|
`);
|
|
73559
73772
|
return;
|
|
73560
73773
|
}
|
|
73774
|
+
if (choice2 === nvidiaIdx) {
|
|
73775
|
+
await openNvidiaPicker();
|
|
73776
|
+
return;
|
|
73777
|
+
}
|
|
73561
73778
|
if (choice2 === openRouterIdx) {
|
|
73562
73779
|
await openOpenRouterPicker();
|
|
73563
73780
|
return;
|
|
@@ -73620,6 +73837,10 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73620
73837
|
await openOpenRouterPicker();
|
|
73621
73838
|
return;
|
|
73622
73839
|
}
|
|
73840
|
+
if (arg.toLowerCase() === "nvidia" || arg.toLowerCase() === "nv") {
|
|
73841
|
+
await openNvidiaPicker();
|
|
73842
|
+
return;
|
|
73843
|
+
}
|
|
73623
73844
|
try {
|
|
73624
73845
|
printModelResult(await agent.setModelSelection(arg));
|
|
73625
73846
|
} catch (err) {
|