clawfast 1.0.3 → 2.0.1

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.
Files changed (3) hide show
  1. package/README.md +4 -4
  2. package/dist/clawfast.cjs +1584 -629
  3. package/package.json +1 -1
package/dist/clawfast.cjs CHANGED
@@ -86,8 +86,8 @@ var require_main = __commonJS({
86
86
  "../node_modules/.pnpm/dotenv@17.4.2/node_modules/dotenv/lib/main.js"(exports2, module2) {
87
87
  "use strict";
88
88
  var fs6 = require("fs");
89
- var path8 = require("path");
90
- var os5 = require("os");
89
+ var path10 = require("path");
90
+ var os7 = require("os");
91
91
  var crypto2 = require("crypto");
92
92
  var TIPS = [
93
93
  "\u25C8 encrypted .env [www.dotenvx.com]",
@@ -225,7 +225,7 @@ var require_main = __commonJS({
225
225
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
226
226
  }
227
227
  } else {
228
- possibleVaultPath = path8.resolve(process.cwd(), ".env.vault");
228
+ possibleVaultPath = path10.resolve(process.cwd(), ".env.vault");
229
229
  }
230
230
  if (fs6.existsSync(possibleVaultPath)) {
231
231
  return possibleVaultPath;
@@ -233,7 +233,7 @@ var require_main = __commonJS({
233
233
  return null;
234
234
  }
235
235
  function _resolveHome(envPath) {
236
- return envPath[0] === "~" ? path8.join(os5.homedir(), envPath.slice(1)) : envPath;
236
+ return envPath[0] === "~" ? path10.join(os7.homedir(), envPath.slice(1)) : envPath;
237
237
  }
238
238
  function _configVault(options) {
239
239
  const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
@@ -250,7 +250,7 @@ var require_main = __commonJS({
250
250
  return { parsed };
251
251
  }
252
252
  function configDotenv(options) {
253
- const dotenvPath = path8.resolve(process.cwd(), ".env");
253
+ const dotenvPath = path10.resolve(process.cwd(), ".env");
254
254
  let encoding = "utf8";
255
255
  let processEnv = process.env;
256
256
  if (options && options.processEnv != null) {
@@ -278,13 +278,13 @@ var require_main = __commonJS({
278
278
  }
279
279
  let lastError;
280
280
  const parsedAll = {};
281
- for (const path9 of optionPaths) {
281
+ for (const path11 of optionPaths) {
282
282
  try {
283
- const parsed = DotenvModule.parse(fs6.readFileSync(path9, { encoding }));
283
+ const parsed = DotenvModule.parse(fs6.readFileSync(path11, { encoding }));
284
284
  DotenvModule.populate(parsedAll, parsed, options);
285
285
  } catch (e) {
286
286
  if (debug) {
287
- _debug(`failed to load ${path9} ${e.message}`);
287
+ _debug(`failed to load ${path11} ${e.message}`);
288
288
  }
289
289
  lastError = e;
290
290
  }
@@ -297,7 +297,7 @@ var require_main = __commonJS({
297
297
  const shortPaths = [];
298
298
  for (const filePath of optionPaths) {
299
299
  try {
300
- const relative2 = path8.relative(process.cwd(), filePath);
300
+ const relative2 = path10.relative(process.cwd(), filePath);
301
301
  shortPaths.push(relative2);
302
302
  } catch (e) {
303
303
  if (debug) {
@@ -426,6 +426,52 @@ ${line}
426
426
  }
427
427
  import_node_fs.default.writeFileSync(filePath, content, { encoding: "utf8", mode: 384 });
428
428
  }
429
+ function fileDefines(filePath, key) {
430
+ try {
431
+ const content = import_node_fs.default.readFileSync(filePath, "utf8");
432
+ return new RegExp(`^${key}=`, "m").test(content);
433
+ } catch {
434
+ return false;
435
+ }
436
+ }
437
+ function swapNvidiaKey(key) {
438
+ const local = import_node_path.default.resolve(process.cwd(), ".env.local");
439
+ const target = fileDefines(local, "NVIDIA_API_KEY") ? local : clawfastEnvPath();
440
+ setEnvVar(target, "NVIDIA_API_KEY", key);
441
+ process.env.NVIDIA_API_KEY = key;
442
+ return target;
443
+ }
444
+ async function testNvidiaKey(key) {
445
+ const baseURL = process.env.NVIDIA_BASE_URL || "https://integrate.api.nvidia.com/v1";
446
+ try {
447
+ const res = await fetch(`${baseURL.replace(/\/$/, "")}/chat/completions`, {
448
+ method: "POST",
449
+ headers: {
450
+ Authorization: `Bearer ${key}`,
451
+ "Content-Type": "application/json"
452
+ },
453
+ body: JSON.stringify({
454
+ model: "openai/gpt-oss-120b",
455
+ messages: [{ role: "user", content: "hi" }],
456
+ max_tokens: 1
457
+ })
458
+ });
459
+ if (res.ok) return { ok: true, status: res.status, detail: "OK" };
460
+ let detail = res.statusText || `HTTP ${res.status}`;
461
+ try {
462
+ const body = await res.json();
463
+ detail = body.detail || body.error?.message || body.title || detail;
464
+ } catch {
465
+ }
466
+ return { ok: false, status: res.status, detail };
467
+ } catch (err) {
468
+ return {
469
+ ok: false,
470
+ status: 0,
471
+ detail: err instanceof Error ? err.message : String(err)
472
+ };
473
+ }
474
+ }
429
475
  function promptLine(question) {
430
476
  const rl = import_node_readline.default.createInterface({
431
477
  input: process.stdin,
@@ -502,7 +548,7 @@ var clawfastVersion, isDevVersion, isNewerVersion;
502
548
  var init_version = __esm({
503
549
  "src/version.ts"() {
504
550
  "use strict";
505
- clawfastVersion = () => true ? "1.0.3" : "0.0.0-dev";
551
+ clawfastVersion = () => true ? "2.0.1" : "0.0.0-dev";
506
552
  isDevVersion = () => clawfastVersion().includes("-dev");
507
553
  isNewerVersion = (a, b) => {
508
554
  const parse3 = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
@@ -699,14 +745,14 @@ var init_paste_input = __esm({
699
745
  /** Replace any paste chips in a submitted line with their real content. */
700
746
  expand(line) {
701
747
  if (this.pastes.size === 0) return line;
702
- let out2 = line;
748
+ let out3 = line;
703
749
  for (const [chip, content] of this.pastes) {
704
- if (out2.includes(chip)) {
705
- out2 = out2.split(chip).join(content);
750
+ if (out3.includes(chip)) {
751
+ out3 = out3.split(chip).join(content);
706
752
  this.pastes.delete(chip);
707
753
  }
708
754
  }
709
- return out2;
755
+ return out3;
710
756
  }
711
757
  /** How many captured pastes are still waiting to be expanded. */
712
758
  pendingCount() {
@@ -869,19 +915,153 @@ var init_skills = __esm({
869
915
  }
870
916
  });
871
917
 
918
+ // src/ui.ts
919
+ var ui_exports = {};
920
+ __export(ui_exports, {
921
+ C: () => C2,
922
+ agentHeader: () => agentHeader,
923
+ buildBanner: () => buildBanner,
924
+ shellPrompt: () => shellPrompt,
925
+ shortCwd: () => shortCwd,
926
+ ui: () => ui,
927
+ vlen: () => vlen
928
+ });
929
+ function shortCwd() {
930
+ const cwd = process.cwd();
931
+ const home = import_node_os2.default.homedir();
932
+ const rel = cwd.startsWith(home) ? "~" + cwd.slice(home.length) : cwd;
933
+ const norm = rel.replace(/\\/g, "/");
934
+ if (norm.length <= 30) return norm;
935
+ const parts = norm.split("/");
936
+ return parts.length > 3 ? `${parts[0]}/\u2026/${parts[parts.length - 1]}` : norm.slice(-30);
937
+ }
938
+ function asciiTitle(text2) {
939
+ const rows = 6;
940
+ const out3 = [];
941
+ for (let r = 0; r < rows; r++) {
942
+ out3.push(
943
+ [...text2].map((ch) => GLYPHS[ch] ? GLYPHS[ch][r] : " ").join(" ")
944
+ );
945
+ }
946
+ return out3;
947
+ }
948
+ function buildBanner(_systemPromptChars, version3 = "1") {
949
+ const user = (import_node_os2.default.userInfo().username || "hacker").toLowerCase();
950
+ const host = (import_node_os2.default.hostname() || "localhost").split(".")[0].toLowerCase();
951
+ const art = asciiTitle("CLAWFAST");
952
+ const artW = vlen(art[0]);
953
+ const slogan = "Com o clawfast voc\xEA faz tudo";
954
+ const header = [
955
+ "",
956
+ ...art.map((line) => `${C2.greenB}${C2.bold}${line}${C2.reset}`),
957
+ "",
958
+ `${C2.cyanB}${C2.bold}${center(slogan, artW)}${C2.reset}`,
959
+ ""
960
+ ];
961
+ const info = [
962
+ { text: "" },
963
+ { text: `Bem-vindo de volta, ${user}!`, accent: true },
964
+ { text: "" },
965
+ { text: "clawfast usa a pasta SPRIT/ para criar" },
966
+ { text: "arquivos, scripts e tudo mais." },
967
+ { text: "" },
968
+ { text: `${user}@${host} \xB7 sem limites` },
969
+ { text: shortCwd() },
970
+ { text: "" }
971
+ ];
972
+ const title = `clawfast v${version3}`;
973
+ const topFill = "\u2500".repeat(Math.max(0, BOX_W - vlen(title) - 5));
974
+ const top = `${C2.green}\u256D\u2500 ${C2.greenB}${C2.bold}${title}${C2.reset}${C2.green} ${topFill}\u256E${C2.reset}`;
975
+ const bottom = `${C2.green}\u2570${"\u2500".repeat(BOX_W - 2)}\u256F${C2.reset}`;
976
+ const cardLines = info.map(({ text: text2, accent }) => {
977
+ const color = accent ? `${C2.greenB}${C2.bold}` : C2.green;
978
+ const body = `${color}${padEndV(text2, INNER)}${C2.reset}`;
979
+ return `${C2.green}\u2502 ${C2.reset}${body}${C2.green} \u2502${C2.reset}`;
980
+ });
981
+ const card = [top, ...cardLines, bottom];
982
+ return "\n" + [...header, ...card].join("\n") + "\n";
983
+ }
984
+ function shellPrompt() {
985
+ const user = (import_node_os2.default.userInfo().username || "hacker").toLowerCase();
986
+ const host = (import_node_os2.default.hostname() || "localhost").split(".")[0].toLowerCase();
987
+ const W = 52;
988
+ const label = " \u2709 mensagem ";
989
+ const topFill = "\u2500".repeat(Math.max(0, W - vlen(label) - 3));
990
+ const top = `${C2.green}\u256D\u2500${C2.greenB}${C2.bold}${label}${C2.reset}${C2.green}${topFill}\u256E${C2.reset}`;
991
+ const id = `${user}\u327F${host} \xB7 ${shortCwd()}`;
992
+ const mid = `${C2.green}\u2502 ${C2.dim}${id}${C2.reset}`;
993
+ const bottom = `${C2.green}\u2570\u2500${C2.greenB}${C2.bold}\u276F${C2.reset} `;
994
+ return `
995
+ ${top}
996
+ ${mid}
997
+ ${bottom}`;
998
+ }
999
+ function agentHeader() {
1000
+ return `${C2.magenta}\u256D\u2500 clawfast ${"\u2500".repeat(20)}${C2.reset}
1001
+ `;
1002
+ }
1003
+ var import_node_os2, ESC, C2, INNER, BOX_W, vlen, padEndV, center, GLYPHS, ui;
1004
+ var init_ui = __esm({
1005
+ "src/ui.ts"() {
1006
+ "use strict";
1007
+ import_node_os2 = __toESM(require("node:os"));
1008
+ ESC = "\x1B[";
1009
+ C2 = {
1010
+ reset: `${ESC}0m`,
1011
+ bold: `${ESC}1m`,
1012
+ dim: `${ESC}90m`,
1013
+ green: `${ESC}32m`,
1014
+ greenB: `${ESC}92m`,
1015
+ cyan: `${ESC}36m`,
1016
+ cyanB: `${ESC}96m`,
1017
+ magenta: `${ESC}95m`,
1018
+ yellow: `${ESC}93m`,
1019
+ red: `${ESC}91m`
1020
+ };
1021
+ INNER = 42;
1022
+ BOX_W = INNER + 4;
1023
+ vlen = (s) => [...s.replace(/\x1b\[[0-9;]*m/g, "")].length;
1024
+ padEndV = (s, w) => s + " ".repeat(Math.max(0, w - vlen(s)));
1025
+ center = (s, w) => {
1026
+ const pad = Math.max(0, w - vlen(s));
1027
+ const left = Math.floor(pad / 2);
1028
+ return " ".repeat(left) + s + " ".repeat(pad - left);
1029
+ };
1030
+ GLYPHS = {
1031
+ C: [" \u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588\u2588"],
1032
+ L: ["\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588\u2588"],
1033
+ A: [" \u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588"],
1034
+ W: ["\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588 \u2588\u2588", "\u2588\u2588 \u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 \u2588\u2588 "],
1035
+ F: ["\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 "],
1036
+ S: [" \u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588 ", " \u2588\u2588", " \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588 "],
1037
+ T: ["\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 "]
1038
+ };
1039
+ ui = { C: C2, buildBanner, shellPrompt, agentHeader };
1040
+ }
1041
+ });
1042
+
872
1043
  // src/news.ts
873
- var import_node_fs4, import_node_path4, NEWS, latestNewsVersion, renderNews, stateFile, readState, writeState, consumePostUpdateLaunch;
1044
+ var import_node_fs4, import_node_path4, NEWS, latestNewsVersion, wrapText, renderNews, stateFile, readState, writeState, consumePostUpdateLaunch;
874
1045
  var init_news = __esm({
875
1046
  "src/news.ts"() {
876
1047
  "use strict";
877
1048
  import_node_fs4 = __toESM(require("node:fs"));
878
1049
  import_node_path4 = __toESM(require("node:path"));
879
1050
  init_config();
1051
+ init_ui();
880
1052
  NEWS = {
1053
+ "2.0.0": [
1054
+ 'Modo ANALISE DE PROJETO (somente leitura): peca "analise/varredura/auditoria do meu projeto" e o clawfast troca sozinho para um auditor dedicado \u2014 sem /comando. Diga "modo normal" para sair.',
1055
+ "Ele mapeia o projeto inteiro: grafo de imports nos dois sentidos (o que cada arquivo importa E quem o importa), achando imports quebrados, ciclos e arquivos orfaos.",
1056
+ "Motor hibrido (estado da arte): orquestra ferramentas deterministicas (ast-grep, semgrep, osv-scanner v2, gitleaks, madge, ctags, rg) para o trabalho pesado e usa o modelo so para o taint cross-module e a validacao. Roda `--preflight` e instala o que falta; cai em fallback (Python + rg) quando uma ferramenta nao existe.",
1057
+ "Caca agressiva de vulnerabilidades e segredos: SQLi, injecao de comando/codigo, XSS, TLS desligado, cripto fraca, CORS aberto, chaves/tokens embutidos (mascarados no relatorio). Regra de ouro: descarta achado sem caminho source->sink confirmado no codigo real.",
1058
+ "Garantia de seguranca: nesse modo ele NUNCA edita/cria/apaga nada no seu projeto \u2014 a unica escrita e UM relatorio ANALISE_PROJETO_<data>.md na raiz do projeto.",
1059
+ "Motor Python somente-leitura semeado a cada sessao (audit/project_audit.py); modo --focus mostra a vizinhanca de import de um arquivo especifico."
1060
+ ],
881
1061
  "1.0.3": [
882
1062
  "Atualizacao: `clawfast update` atualiza o CLI e mostra as boas-vindas; aparece um aviso quando ha versao nova; /nov lista as novidades.",
883
1063
  "Skills: /skillcreator cria ou cola uma skill (de qualquer tamanho), /skills lista e /skill delete remove. As skills viram conhecimento disponivel para TODOS os modelos.",
884
- "Modelos na NVIDIA build: minimax-m3, kimi-k2.6, glm-5.1 e qwen3.5-397b \u2014 todos com function calling de verdade (as ferramentas disparam).",
1064
+ "Modelos na NVIDIA build: mistral-medium-3.5, gpt-oss-120b, glm-5.1 e qwen3.5-397b \u2014 todos com function calling de verdade (as ferramentas disparam).",
885
1065
  "Resiliencia a rate limit (429): cai para os outros modelos como contingencia e espera/retenta a cadeia automaticamente."
886
1066
  ]
887
1067
  };
@@ -897,14 +1077,50 @@ var init_news = __esm({
897
1077
  return 0;
898
1078
  })[0];
899
1079
  };
1080
+ wrapText = (text2, width) => {
1081
+ const words = text2.split(/\s+/).filter(Boolean);
1082
+ const lines = [];
1083
+ let line = "";
1084
+ for (const word of words) {
1085
+ if (line && vlen(line) + 1 + vlen(word) > width) {
1086
+ lines.push(line);
1087
+ line = word;
1088
+ } else {
1089
+ line = line ? `${line} ${word}` : word;
1090
+ }
1091
+ }
1092
+ if (line) lines.push(line);
1093
+ return lines.length ? lines : [""];
1094
+ };
900
1095
  renderNews = (version3) => {
901
1096
  const key = NEWS[version3] ? version3 : latestNewsVersion();
902
1097
  if (!key || !NEWS[key]) {
903
- return "Sem novidades registradas para esta versao.";
904
- }
905
- const lines = NEWS[key].map((item) => ` \u2022 ${item}`).join("\n");
906
- return `Novidades da versao ${key}:
907
- ${lines}`;
1098
+ return `${C2.dim}Sem novidades registradas para esta versao.${C2.reset}`;
1099
+ }
1100
+ const cols2 = process.stdout.columns || 80;
1101
+ const BOX = Math.min(Math.max(cols2 - 2, 48), 80);
1102
+ const INNER2 = BOX - 4;
1103
+ const BULLET = "\u2022 ";
1104
+ const INDENT = " ".repeat(BULLET.length);
1105
+ const title = `Novidades \xB7 v${key}`;
1106
+ const topFill = "\u2500".repeat(Math.max(0, BOX - vlen(title) - 5));
1107
+ const top = `${C2.green}\u256D\u2500 ${C2.greenB}${C2.bold}${title}${C2.reset}${C2.green} ${topFill}\u256E${C2.reset}`;
1108
+ const bottom = `${C2.green}\u2570${"\u2500".repeat(BOX - 2)}\u256F${C2.reset}`;
1109
+ const row = (content) => {
1110
+ const pad = " ".repeat(Math.max(0, INNER2 - vlen(content)));
1111
+ return `${C2.green}\u2502 ${C2.reset}${content}${pad}${C2.green} \u2502${C2.reset}`;
1112
+ };
1113
+ const body = [row("")];
1114
+ NEWS[key].forEach((item, idx) => {
1115
+ if (idx > 0) body.push(row(""));
1116
+ const wrapped = wrapText(item, INNER2 - BULLET.length);
1117
+ wrapped.forEach((line, i) => {
1118
+ const prefix = i === 0 ? `${C2.cyanB}${BULLET}${C2.reset}` : INDENT;
1119
+ body.push(row(`${prefix}${line}`));
1120
+ });
1121
+ });
1122
+ body.push(row(""));
1123
+ return [top, ...body, bottom].join("\n");
908
1124
  };
909
1125
  stateFile = () => import_node_path4.default.join(clawfastHome(), "state.json");
910
1126
  readState = () => {
@@ -1505,10 +1721,10 @@ function mergeDefs(...defs) {
1505
1721
  function cloneDef(schema) {
1506
1722
  return mergeDefs(schema._zod.def);
1507
1723
  }
1508
- function getElementAtPath(obj, path8) {
1509
- if (!path8)
1724
+ function getElementAtPath(obj, path10) {
1725
+ if (!path10)
1510
1726
  return obj;
1511
- return path8.reduce((acc, key) => acc?.[key], obj);
1727
+ return path10.reduce((acc, key) => acc?.[key], obj);
1512
1728
  }
1513
1729
  function promiseAllObject(promisesObj) {
1514
1730
  const keys = Object.keys(promisesObj);
@@ -1836,11 +2052,11 @@ function explicitlyAborted(x, startIndex = 0) {
1836
2052
  }
1837
2053
  return false;
1838
2054
  }
1839
- function prefixIssues(path8, issues) {
2055
+ function prefixIssues(path10, issues) {
1840
2056
  return issues.map((iss) => {
1841
2057
  var _a25;
1842
2058
  (_a25 = iss).path ?? (_a25.path = []);
1843
- iss.path.unshift(path8);
2059
+ iss.path.unshift(path10);
1844
2060
  return iss;
1845
2061
  });
1846
2062
  }
@@ -2058,16 +2274,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
2058
2274
  }
2059
2275
  function formatError(error51, mapper = (issue2) => issue2.message) {
2060
2276
  const fieldErrors = { _errors: [] };
2061
- const processError = (error52, path8 = []) => {
2277
+ const processError = (error52, path10 = []) => {
2062
2278
  for (const issue2 of error52.issues) {
2063
2279
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2064
- issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
2280
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
2065
2281
  } else if (issue2.code === "invalid_key") {
2066
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
2282
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
2067
2283
  } else if (issue2.code === "invalid_element") {
2068
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
2284
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
2069
2285
  } else {
2070
- const fullpath = [...path8, ...issue2.path];
2286
+ const fullpath = [...path10, ...issue2.path];
2071
2287
  if (fullpath.length === 0) {
2072
2288
  fieldErrors._errors.push(mapper(issue2));
2073
2289
  } else {
@@ -2094,17 +2310,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
2094
2310
  }
2095
2311
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
2096
2312
  const result = { errors: [] };
2097
- const processError = (error52, path8 = []) => {
2313
+ const processError = (error52, path10 = []) => {
2098
2314
  var _a25, _b18;
2099
2315
  for (const issue2 of error52.issues) {
2100
2316
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2101
- issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
2317
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
2102
2318
  } else if (issue2.code === "invalid_key") {
2103
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
2319
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
2104
2320
  } else if (issue2.code === "invalid_element") {
2105
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
2321
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
2106
2322
  } else {
2107
- const fullpath = [...path8, ...issue2.path];
2323
+ const fullpath = [...path10, ...issue2.path];
2108
2324
  if (fullpath.length === 0) {
2109
2325
  result.errors.push(mapper(issue2));
2110
2326
  continue;
@@ -2136,8 +2352,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
2136
2352
  }
2137
2353
  function toDotPath(_path) {
2138
2354
  const segs = [];
2139
- const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2140
- for (const seg of path8) {
2355
+ const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2356
+ for (const seg of path10) {
2141
2357
  if (typeof seg === "number")
2142
2358
  segs.push(`[${seg}]`);
2143
2359
  else if (typeof seg === "symbol")
@@ -12449,11 +12665,11 @@ function _catch(Class2, innerType, catchValue) {
12449
12665
  });
12450
12666
  }
12451
12667
  // @__NO_SIDE_EFFECTS__
12452
- function _pipe(Class2, in_, out2) {
12668
+ function _pipe(Class2, in_, out3) {
12453
12669
  return new Class2({
12454
12670
  type: "pipe",
12455
12671
  in: in_,
12456
- out: out2
12672
+ out: out3
12457
12673
  });
12458
12674
  }
12459
12675
  // @__NO_SIDE_EFFECTS__
@@ -14689,19 +14905,19 @@ function _catch2(innerType, catchValue) {
14689
14905
  function nan(params) {
14690
14906
  return _nan(ZodNaN, params);
14691
14907
  }
14692
- function pipe(in_, out2) {
14908
+ function pipe(in_, out3) {
14693
14909
  return new ZodPipe({
14694
14910
  type: "pipe",
14695
14911
  in: in_,
14696
- out: out2
14912
+ out: out3
14697
14913
  // ...util.normalizeParams(params),
14698
14914
  });
14699
14915
  }
14700
- function codec(in_, out2, params) {
14916
+ function codec(in_, out3, params) {
14701
14917
  return new ZodCodec({
14702
14918
  type: "pipe",
14703
14919
  in: in_,
14704
- out: out2,
14920
+ out: out3,
14705
14921
  transform: params.decode,
14706
14922
  reverseTransform: params.encode
14707
14923
  });
@@ -15640,13 +15856,13 @@ function resolveRef(ref, ctx) {
15640
15856
  if (!ref.startsWith("#")) {
15641
15857
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
15642
15858
  }
15643
- const path8 = ref.slice(1).split("/").filter(Boolean);
15644
- if (path8.length === 0) {
15859
+ const path10 = ref.slice(1).split("/").filter(Boolean);
15860
+ if (path10.length === 0) {
15645
15861
  return ctx.rootSchema;
15646
15862
  }
15647
15863
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
15648
- if (path8[0] === defsKey) {
15649
- const key = path8[1];
15864
+ if (path10[0] === defsKey) {
15865
+ const key = path10[1];
15650
15866
  if (!key || !ctx.defs[key]) {
15651
15867
  throw new Error(`Reference not found: ${ref}`);
15652
15868
  }
@@ -16835,8 +17051,8 @@ var init_parseUtil = __esm({
16835
17051
  init_errors3();
16836
17052
  init_en2();
16837
17053
  makeIssue = (params) => {
16838
- const { data, path: path8, errorMaps, issueData } = params;
16839
- const fullPath = [...path8, ...issueData.path || []];
17054
+ const { data, path: path10, errorMaps, issueData } = params;
17055
+ const fullPath = [...path10, ...issueData.path || []];
16840
17056
  const fullIssue = {
16841
17057
  ...issueData,
16842
17058
  path: fullPath
@@ -17119,11 +17335,11 @@ var init_types = __esm({
17119
17335
  init_parseUtil();
17120
17336
  init_util2();
17121
17337
  ParseInputLazyPath = class {
17122
- constructor(parent, value, path8, key) {
17338
+ constructor(parent, value, path10, key) {
17123
17339
  this._cachedPath = [];
17124
17340
  this.parent = parent;
17125
17341
  this.data = value;
17126
- this._path = path8;
17342
+ this._path = path10;
17127
17343
  this._key = key;
17128
17344
  }
17129
17345
  get path() {
@@ -23163,7 +23379,7 @@ var require_auth_config = __commonJS({
23163
23379
  });
23164
23380
  module2.exports = __toCommonJS(auth_config_exports);
23165
23381
  var fs6 = __toESM2(require("fs"));
23166
- var path8 = __toESM2(require("path"));
23382
+ var path10 = __toESM2(require("path"));
23167
23383
  var import_token_util = require_token_util();
23168
23384
  function getAuthConfigPath() {
23169
23385
  const dataDir = (0, import_token_util.getVercelDataDir)();
@@ -23172,7 +23388,7 @@ var require_auth_config = __commonJS({
23172
23388
  `Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`
23173
23389
  );
23174
23390
  }
23175
- return path8.join(dataDir, "auth.json");
23391
+ return path10.join(dataDir, "auth.json");
23176
23392
  }
23177
23393
  function readAuthConfig() {
23178
23394
  try {
@@ -23191,7 +23407,7 @@ var require_auth_config = __commonJS({
23191
23407
  }
23192
23408
  function writeAuthConfig(config3) {
23193
23409
  const authPath = getAuthConfigPath();
23194
- const authDir = path8.dirname(authPath);
23410
+ const authDir = path10.dirname(authPath);
23195
23411
  if (!fs6.existsSync(authDir)) {
23196
23412
  fs6.mkdirSync(authDir, { mode: 504, recursive: true });
23197
23413
  }
@@ -23386,7 +23602,7 @@ var require_token_util = __commonJS({
23386
23602
  saveToken: () => saveToken
23387
23603
  });
23388
23604
  module2.exports = __toCommonJS(token_util_exports);
23389
- var path8 = __toESM2(require("path"));
23605
+ var path10 = __toESM2(require("path"));
23390
23606
  var fs6 = __toESM2(require("fs"));
23391
23607
  var import_token_error = require_token_error();
23392
23608
  var import_token_io = require_token_io();
@@ -23399,7 +23615,7 @@ var require_token_util = __commonJS({
23399
23615
  if (!dataDir) {
23400
23616
  return null;
23401
23617
  }
23402
- return path8.join(dataDir, vercelFolder);
23618
+ return path10.join(dataDir, vercelFolder);
23403
23619
  }
23404
23620
  async function getVercelToken2(options) {
23405
23621
  const authConfig = (0, import_auth_config.readAuthConfig)();
@@ -23475,7 +23691,7 @@ var require_token_util = __commonJS({
23475
23691
  "Unable to find project root directory. Have you linked your project with `vc link?`"
23476
23692
  );
23477
23693
  }
23478
- const prjPath = path8.join(dir, ".vercel", "project.json");
23694
+ const prjPath = path10.join(dir, ".vercel", "project.json");
23479
23695
  if (!fs6.existsSync(prjPath)) {
23480
23696
  throw new import_token_error.VercelOidcTokenError(
23481
23697
  "project.json not found, have you linked your project with `vc link?`"
@@ -23496,9 +23712,9 @@ var require_token_util = __commonJS({
23496
23712
  "Unable to find user data directory. Please reach out to Vercel support."
23497
23713
  );
23498
23714
  }
23499
- const tokenPath = path8.join(dir, "com.vercel.token", `${projectId}.json`);
23715
+ const tokenPath = path10.join(dir, "com.vercel.token", `${projectId}.json`);
23500
23716
  const tokenJson = JSON.stringify(token);
23501
- fs6.mkdirSync(path8.dirname(tokenPath), { mode: 504, recursive: true });
23717
+ fs6.mkdirSync(path10.dirname(tokenPath), { mode: 504, recursive: true });
23502
23718
  fs6.writeFileSync(tokenPath, tokenJson);
23503
23719
  fs6.chmodSync(tokenPath, 432);
23504
23720
  return;
@@ -23510,7 +23726,7 @@ var require_token_util = __commonJS({
23510
23726
  "Unable to find user data directory. Please reach out to Vercel support."
23511
23727
  );
23512
23728
  }
23513
- const tokenPath = path8.join(dir, "com.vercel.token", `${projectId}.json`);
23729
+ const tokenPath = path10.join(dir, "com.vercel.token", `${projectId}.json`);
23514
23730
  if (!fs6.existsSync(tokenPath)) {
23515
23731
  return null;
23516
23732
  }
@@ -35540,7 +35756,7 @@ function createOpenRouter(options = {}) {
35540
35756
  );
35541
35757
  const createChatModel = (modelId, settings = {}) => new OpenRouterChatLanguageModel(modelId, settings, {
35542
35758
  provider: "openrouter.chat",
35543
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35759
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35544
35760
  headers: getHeaders,
35545
35761
  compatibility,
35546
35762
  fetch: options.fetch,
@@ -35548,7 +35764,7 @@ function createOpenRouter(options = {}) {
35548
35764
  });
35549
35765
  const createCompletionModel = (modelId, settings = {}) => new OpenRouterCompletionLanguageModel(modelId, settings, {
35550
35766
  provider: "openrouter.completion",
35551
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35767
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35552
35768
  headers: getHeaders,
35553
35769
  compatibility,
35554
35770
  fetch: options.fetch,
@@ -35556,21 +35772,21 @@ function createOpenRouter(options = {}) {
35556
35772
  });
35557
35773
  const createEmbeddingModel = (modelId, settings = {}) => new OpenRouterEmbeddingModel(modelId, settings, {
35558
35774
  provider: "openrouter.embedding",
35559
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35775
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35560
35776
  headers: getHeaders,
35561
35777
  fetch: options.fetch,
35562
35778
  extraBody: options.extraBody
35563
35779
  });
35564
35780
  const createImageModel = (modelId, settings = {}) => new OpenRouterImageModel(modelId, settings, {
35565
35781
  provider: "openrouter.image",
35566
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35782
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35567
35783
  headers: getHeaders,
35568
35784
  fetch: options.fetch,
35569
35785
  extraBody: options.extraBody
35570
35786
  });
35571
35787
  const createVideoModel = (modelId, settings = {}) => new OpenRouterVideoModel(modelId, settings, {
35572
35788
  provider: "openrouter.video",
35573
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35789
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35574
35790
  headers: getHeaders,
35575
35791
  fetch: options.fetch,
35576
35792
  extraBody: options.extraBody
@@ -40106,37 +40322,37 @@ function createOpenAI(options = {}) {
40106
40322
  );
40107
40323
  const createChatModel = (modelId) => new OpenAIChatLanguageModel(modelId, {
40108
40324
  provider: `${providerName}.chat`,
40109
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40325
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40110
40326
  headers: getHeaders,
40111
40327
  fetch: options.fetch
40112
40328
  });
40113
40329
  const createCompletionModel = (modelId) => new OpenAICompletionLanguageModel(modelId, {
40114
40330
  provider: `${providerName}.completion`,
40115
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40331
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40116
40332
  headers: getHeaders,
40117
40333
  fetch: options.fetch
40118
40334
  });
40119
40335
  const createEmbeddingModel = (modelId) => new OpenAIEmbeddingModel(modelId, {
40120
40336
  provider: `${providerName}.embedding`,
40121
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40337
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40122
40338
  headers: getHeaders,
40123
40339
  fetch: options.fetch
40124
40340
  });
40125
40341
  const createImageModel = (modelId) => new OpenAIImageModel(modelId, {
40126
40342
  provider: `${providerName}.image`,
40127
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40343
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40128
40344
  headers: getHeaders,
40129
40345
  fetch: options.fetch
40130
40346
  });
40131
40347
  const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
40132
40348
  provider: `${providerName}.transcription`,
40133
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40349
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40134
40350
  headers: getHeaders,
40135
40351
  fetch: options.fetch
40136
40352
  });
40137
40353
  const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
40138
40354
  provider: `${providerName}.speech`,
40139
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40355
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40140
40356
  headers: getHeaders,
40141
40357
  fetch: options.fetch
40142
40358
  });
@@ -40151,7 +40367,7 @@ function createOpenAI(options = {}) {
40151
40367
  const createResponsesModel = (modelId) => {
40152
40368
  return new OpenAIResponsesLanguageModel(modelId, {
40153
40369
  provider: `${providerName}.responses`,
40154
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40370
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40155
40371
  headers: getHeaders,
40156
40372
  fetch: options.fetch,
40157
40373
  fileIdPrefixes: ["file-"]
@@ -45372,7 +45588,7 @@ function supportsMultimodalToolResults(modelName) {
45372
45588
  const normalized = modelName.toLowerCase();
45373
45589
  return normalized === "ask-model" || normalized.includes("gemini") || normalized.includes("google/") || isAnthropicModel(normalized) || normalized.includes("anthropic/") || normalized.includes("claude") || normalized.includes("openai") || normalized.includes("openai/") || normalized.includes("gpt-") || normalized.includes("o1") || normalized.includes("o3") || normalized.includes("o4") || normalized.includes("x-ai/") || normalized.includes("grok");
45374
45590
  }
45375
- var isRecord, isXaiModelSlug, isGeminiModelSlug, requestCanRouteToXai, requestCanRouteToGemini, hasOwnEncryptedContent, stripEncryptedContent, sanitizeOpenRouterRequestForXai, hasJsonRefKey, wrapToolContentIfGeminiRefSensitive, sanitizeOpenRouterRequestForGeminiFunctionResponses, patchKimiReasoningToolCalls, OPENROUTER_METADATA_HEADER, withOpenRouterMetadataHeader, openrouterPatchFetch, openrouter2, openai2, nvidia, deepseek, kimi, buildProviderMap, hasEnvValue, isDeepSeekEnabled, isKimiEnabled, CLI_MODEL_CHAIN, baseProviders, modelCutoffDates, modelDisplayNames, getModelDisplayName, getModelCutoffDate, myProvider;
45591
+ 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;
45376
45592
  var init_providers = __esm({
45377
45593
  "../lib/ai/providers.ts"() {
45378
45594
  "use strict";
@@ -45532,10 +45748,47 @@ var init_providers = __esm({
45532
45748
  name: "openai",
45533
45749
  apiKey: process.env.OPENAI_API_KEY
45534
45750
  });
45751
+ isNvidiaMistralModel = (value) => typeof value === "string" && value.toLowerCase().startsWith("mistralai/mistral");
45752
+ applyNvidiaMistralConfig = (body) => {
45753
+ if (!isRecord(body) || !isNvidiaMistralModel(body.model)) {
45754
+ return { body, changed: false };
45755
+ }
45756
+ return {
45757
+ body: {
45758
+ ...body,
45759
+ reasoning_effort: "none",
45760
+ temperature: 1,
45761
+ top_p: 1,
45762
+ max_tokens: 16384
45763
+ },
45764
+ changed: true
45765
+ };
45766
+ };
45767
+ nvidiaPatchFetch = async (url2, init) => {
45768
+ const key = process.env.NVIDIA_API_KEY?.trim();
45769
+ const headers = new Headers(init?.headers);
45770
+ if (key) headers.set("Authorization", `Bearer ${key}`);
45771
+ let nextInit = { ...init, headers };
45772
+ if (typeof nextInit.body === "string") {
45773
+ try {
45774
+ const parsed = JSON.parse(nextInit.body);
45775
+ const patched = applyNvidiaMistralConfig(parsed);
45776
+ if (patched.changed) {
45777
+ nextInit = { ...nextInit, body: JSON.stringify(patched.body) };
45778
+ }
45779
+ } catch {
45780
+ }
45781
+ }
45782
+ return globalThis.fetch(url2, nextInit);
45783
+ };
45535
45784
  nvidia = createOpenAI({
45536
45785
  name: "nvidia",
45537
45786
  baseURL: process.env.NVIDIA_BASE_URL || "https://integrate.api.nvidia.com/v1",
45538
- apiKey: process.env.NVIDIA_API_KEY
45787
+ // Placeholder so the SDK never throws "missing API key" at request build time
45788
+ // when the env is empty at load — nvidiaPatchFetch sets the real Authorization
45789
+ // header from process.env on every request (see above).
45790
+ apiKey: process.env.NVIDIA_API_KEY || "nvapi-clawfast-runtime",
45791
+ fetch: nvidiaPatchFetch
45539
45792
  });
45540
45793
  deepseek = createOpenAI({
45541
45794
  name: "deepseek",
@@ -45563,8 +45816,10 @@ var init_providers = __esm({
45563
45816
  "model-opus-4.6": nvidia("nvidia/nemotron-3-ultra-550b-a55b"),
45564
45817
  "model-kimi-k2.6": or("qwen/qwen3-coder:free"),
45565
45818
  // NVIDIA build models — primary provider for the local CLI (chat-completions).
45566
- "model-nvidia-minimax-m3": nvidia.chat("minimaxai/minimax-m3"),
45567
- "model-nvidia-kimi-k2.6": nvidia.chat("moonshotai/kimi-k2.6"),
45819
+ "model-nvidia-mistral-medium-3.5": nvidia.chat(
45820
+ "mistralai/mistral-medium-3.5-128b"
45821
+ ),
45822
+ "model-nvidia-gpt-oss-120b": nvidia.chat("openai/gpt-oss-120b"),
45568
45823
  "model-nvidia-glm-5.1": nvidia.chat("z-ai/glm-5.1"),
45569
45824
  "model-nvidia-qwen3.5-397b": nvidia.chat("qwen/qwen3.5-397b-a17b"),
45570
45825
  // Extra explicit keys for the CLI.
@@ -45600,10 +45855,10 @@ var init_providers = __esm({
45600
45855
  };
45601
45856
  CLI_MODEL_CHAIN = [
45602
45857
  ...hasEnvValue("NVIDIA_API_KEY") ? [
45603
- "model-nvidia-minimax-m3",
45604
- // NVIDIA minimaxai/minimax-m3
45605
- "model-nvidia-kimi-k2.6",
45606
- // NVIDIA moonshotai/kimi-k2.6
45858
+ "model-nvidia-mistral-medium-3.5",
45859
+ // NVIDIA mistralai/mistral-medium-3.5-128b
45860
+ "model-nvidia-gpt-oss-120b",
45861
+ // NVIDIA openai/gpt-oss-120b
45607
45862
  "model-nvidia-glm-5.1",
45608
45863
  // NVIDIA z-ai/glm-5.1
45609
45864
  "model-nvidia-qwen3.5-397b"
@@ -45628,8 +45883,8 @@ var init_providers = __esm({
45628
45883
  "model-deepseek-v4-flash": "May 2025",
45629
45884
  "model-opus-4.6": "May 2025",
45630
45885
  "model-kimi-k2.6": "April 2024",
45631
- "model-nvidia-minimax-m3": "Unknown",
45632
- "model-nvidia-kimi-k2.6": "April 2024",
45886
+ "model-nvidia-mistral-medium-3.5": "Unknown",
45887
+ "model-nvidia-gpt-oss-120b": "June 2024",
45633
45888
  "model-nvidia-glm-5.1": "Unknown",
45634
45889
  "model-nvidia-qwen3.5-397b": "Unknown",
45635
45890
  "model-deepseek-proxy": "July 2024",
@@ -45652,8 +45907,8 @@ var init_providers = __esm({
45652
45907
  "model-deepseek-v4-flash": "DeepSeek V4 Flash",
45653
45908
  "model-opus-4.6": "Anthropic Claude Opus 4.6",
45654
45909
  "model-kimi-k2.6": "Moonshot Kimi K2.6",
45655
- "model-nvidia-minimax-m3": "NVIDIA - MiniMax M3",
45656
- "model-nvidia-kimi-k2.6": "NVIDIA - Moonshot Kimi K2.6",
45910
+ "model-nvidia-mistral-medium-3.5": "NVIDIA - Mistral Medium 3.5",
45911
+ "model-nvidia-gpt-oss-120b": "NVIDIA - OpenAI GPT-OSS 120B",
45657
45912
  "model-nvidia-glm-5.1": "NVIDIA - Z.ai GLM 5.1",
45658
45913
  "model-nvidia-qwen3.5-397b": "NVIDIA - Qwen3.5 397B A17B",
45659
45914
  "model-deepseek-proxy": "DeepSeek (sessao web logada / deepsproxy)",
@@ -48687,8 +48942,8 @@ var init_background_process_tracker = __esm({
48687
48942
  /**
48688
48943
  * Normalize file path for comparison
48689
48944
  */
48690
- normalizePath(path8) {
48691
- let normalized = path8.trim().replace(/\/+/g, "/");
48945
+ normalizePath(path10) {
48946
+ let normalized = path10.trim().replace(/\/+/g, "/");
48692
48947
  if (normalized.startsWith("./")) {
48693
48948
  normalized = normalized.slice(2);
48694
48949
  }
@@ -48926,8 +49181,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
48926
49181
  return decodedFile;
48927
49182
  };
48928
49183
  }
48929
- function normalizeWindowsPath(path8) {
48930
- return path8.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
49184
+ function normalizeWindowsPath(path10) {
49185
+ return path10.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
48931
49186
  }
48932
49187
  var import_path;
48933
49188
  var init_module_node = __esm({
@@ -51816,9 +52071,9 @@ async function addSourceContext(frames) {
51816
52071
  LRU_FILE_CONTENTS_CACHE.reduce();
51817
52072
  return frames;
51818
52073
  }
51819
- function getContextLinesFromFile(path8, ranges, output) {
52074
+ function getContextLinesFromFile(path10, ranges, output) {
51820
52075
  return new Promise((resolve2) => {
51821
- const stream = (0, import_node_fs5.createReadStream)(path8);
52076
+ const stream = (0, import_node_fs5.createReadStream)(path10);
51822
52077
  const lineReaded = (0, import_node_readline2.createInterface)({
51823
52078
  input: stream
51824
52079
  });
@@ -51833,7 +52088,7 @@ function getContextLinesFromFile(path8, ranges, output) {
51833
52088
  let rangeStart = range[0];
51834
52089
  let rangeEnd = range[1];
51835
52090
  function onStreamError() {
51836
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path8, 1);
52091
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path10, 1);
51837
52092
  lineReaded.close();
51838
52093
  lineReaded.removeAllListeners();
51839
52094
  destroyStreamAndResolve();
@@ -51894,8 +52149,8 @@ function clearLineContext(frame2) {
51894
52149
  delete frame2.context_line;
51895
52150
  delete frame2.post_context;
51896
52151
  }
51897
- function shouldSkipContextLinesForFile(path8) {
51898
- return path8.startsWith("node:") || path8.endsWith(".min.js") || path8.endsWith(".min.cjs") || path8.endsWith(".min.mjs") || path8.startsWith("data:");
52152
+ function shouldSkipContextLinesForFile(path10) {
52153
+ return path10.startsWith("node:") || path10.endsWith(".min.js") || path10.endsWith(".min.cjs") || path10.endsWith(".min.mjs") || path10.startsWith("data:");
51899
52154
  }
51900
52155
  function shouldSkipContextLinesForFrame(frame2) {
51901
52156
  if (void 0 !== frame2.lineno && frame2.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -51914,22 +52169,22 @@ function makeLineReaderRanges(lines) {
51914
52169
  const line = lines[0];
51915
52170
  if ("number" != typeof line) return [];
51916
52171
  let current = makeContextRange(line);
51917
- const out2 = [];
52172
+ const out3 = [];
51918
52173
  while (true) {
51919
52174
  if (i === lines.length - 1) {
51920
- out2.push(current);
52175
+ out3.push(current);
51921
52176
  break;
51922
52177
  }
51923
52178
  const next = lines[i + 1];
51924
52179
  if ("number" != typeof next) break;
51925
52180
  if (next <= current[1]) current[1] = next + DEFAULT_LINES_OF_CONTEXT;
51926
52181
  else {
51927
- out2.push(current);
52182
+ out3.push(current);
51928
52183
  current = makeContextRange(next);
51929
52184
  }
51930
52185
  i++;
51931
52186
  }
51932
- return out2;
52187
+ return out3;
51933
52188
  }
51934
52189
  function makeContextRange(line) {
51935
52190
  return [
@@ -55447,8 +55702,8 @@ async function createE2BPtyHandle(sandbox, opts) {
55447
55702
  sendInput(bytes) {
55448
55703
  return pty.sendInput(pid, bytes);
55449
55704
  },
55450
- async resize(cols, rows) {
55451
- await pty.resize(pid, { cols, rows });
55705
+ async resize(cols2, rows) {
55706
+ await pty.resize(pid, { cols: cols2, rows });
55452
55707
  },
55453
55708
  async kill() {
55454
55709
  const killed = await pty.kill(pid);
@@ -55589,9 +55844,9 @@ var init_pty_session_manager = __esm({
55589
55844
  consumeDelta(session) {
55590
55845
  const total = this.totalBufferBytes(session);
55591
55846
  const start = Math.min(session.readCursor, total);
55592
- const out2 = this.sliceBuffer(session, start, total);
55847
+ const out3 = this.sliceBuffer(session, start, total);
55593
55848
  session.readCursor = total;
55594
- return out2;
55849
+ return out3;
55595
55850
  }
55596
55851
  /**
55597
55852
  * Returns the full accumulated buffer without advancing `readCursor`.
@@ -55649,7 +55904,7 @@ var init_pty_session_manager = __esm({
55649
55904
  }
55650
55905
  sliceBuffer(session, start, end) {
55651
55906
  if (end <= start) return new Uint8Array(0);
55652
- const out2 = new Uint8Array(end - start);
55907
+ const out3 = new Uint8Array(end - start);
55653
55908
  let outOffset = 0;
55654
55909
  let cursor = 0;
55655
55910
  for (const chunk of session.buffer) {
@@ -55662,11 +55917,11 @@ var init_pty_session_manager = __esm({
55662
55917
  if (chunkStart >= end) break;
55663
55918
  const sliceStart = Math.max(0, start - chunkStart);
55664
55919
  const sliceEnd = Math.min(chunk.byteLength, end - chunkStart);
55665
- out2.set(chunk.subarray(sliceStart, sliceEnd), outOffset);
55920
+ out3.set(chunk.subarray(sliceStart, sliceEnd), outOffset);
55666
55921
  outOffset += sliceEnd - sliceStart;
55667
55922
  cursor = chunkEnd;
55668
55923
  }
55669
- return out2;
55924
+ return out3;
55670
55925
  }
55671
55926
  async killAndRemove(session, _reason) {
55672
55927
  if (session.closing) {
@@ -55924,7 +56179,7 @@ var require_xterm_headless = __commonJS({
55924
56179
  };
55925
56180
  Object.defineProperty(t2, "__esModule", { value: true }), t2.InputHandler = t2.WindowsOptionsReportType = void 0, t2.isValidColorIndex = k;
55926
56181
  const n2 = s2(3534), o = s2(6760), a = s2(6717), h = s2(7150), c = s2(726), l = s2(6107), u = s2(8938), d = s2(3055), f = s2(5451), _ = s2(6501), p = s2(6415), g = s2(1346), v = s2(9823), m = s2(8693), b = s2(802), S = { "(": 0, ")": 1, "*": 2, "+": 3, "-": 1, ".": 2 }, y = 131072;
55927
- function C4(e3, t3) {
56182
+ function C5(e3, t3) {
55928
56183
  if (e3 > 24) return t3.setWinLines || false;
55929
56184
  switch (e3) {
55930
56185
  case 1:
@@ -56059,7 +56314,7 @@ var require_xterm_headless = __commonJS({
56059
56314
  this._parser.precedingJoinState = g2, this._activeBuffer.x < a2 && s3 - t3 > 0 && 0 === _2.getWidth(this._activeBuffer.x) && !_2.hasContent(this._activeBuffer.x) && _2.setCellFromCodepoint(this._activeBuffer.x, 0, 1, f2), this._dirtyRowTracker.markDirty(this._activeBuffer.y);
56060
56315
  }
56061
56316
  registerCsiHandler(e3, t3) {
56062
- return "t" !== e3.final || e3.prefix || e3.intermediates ? this._parser.registerCsiHandler(e3, t3) : this._parser.registerCsiHandler(e3, ((e4) => !C4(e4.params[0], this._optionsService.rawOptions.windowOptions) || t3(e4)));
56317
+ return "t" !== e3.final || e3.prefix || e3.intermediates ? this._parser.registerCsiHandler(e3, t3) : this._parser.registerCsiHandler(e3, ((e4) => !C5(e4.params[0], this._optionsService.rawOptions.windowOptions) || t3(e4)));
56063
56318
  }
56064
56319
  registerDcsHandler(e3, t3) {
56065
56320
  return this._parser.registerDcsHandler(e3, new v.DcsHandler(t3));
@@ -56573,7 +56828,7 @@ var require_xterm_headless = __commonJS({
56573
56828
  return (e3.length < 2 || (s3 = e3.params[1]) > this._bufferService.rows || 0 === s3) && (s3 = this._bufferService.rows), s3 > t3 && (this._activeBuffer.scrollTop = t3 - 1, this._activeBuffer.scrollBottom = s3 - 1, this._setCursor(0, 0)), true;
56574
56829
  }
56575
56830
  windowOptions(e3) {
56576
- if (!C4(e3.params[0], this._optionsService.rawOptions.windowOptions)) return true;
56831
+ if (!C5(e3.params[0], this._optionsService.rawOptions.windowOptions)) return true;
56577
56832
  const t3 = e3.length > 1 ? e3.params[1] : 0;
56578
56833
  switch (e3.params[0]) {
56579
56834
  case 14:
@@ -61700,12 +61955,12 @@ function applyDelta(source, delta) {
61700
61955
  zDelta.pos += cnt;
61701
61956
  break;
61702
61957
  case ";": {
61703
- const out2 = zOut.toByteArray(source);
61704
- if (cnt !== checksum(out2))
61958
+ const out3 = zOut.toByteArray(source);
61959
+ if (cnt !== checksum(out3))
61705
61960
  throw new Error("bad checksum");
61706
61961
  if (total !== limit)
61707
61962
  throw new Error("generated size does not match predicted size");
61708
- return out2;
61963
+ return out3;
61709
61964
  }
61710
61965
  default:
61711
61966
  throw new Error("unknown delta operator");
@@ -66279,11 +66534,11 @@ async function createCentrifugoPtyHandle(sandbox, opts) {
66279
66534
  };
66280
66535
  await publish(payload);
66281
66536
  },
66282
- async resize(cols, rows) {
66537
+ async resize(cols2, rows) {
66283
66538
  const payload = {
66284
66539
  type: "pty_resize",
66285
66540
  sessionId,
66286
- cols,
66541
+ cols: cols2,
66287
66542
  rows,
66288
66543
  targetConnectionId: connectionId
66289
66544
  };
@@ -66518,7 +66773,7 @@ In using these tools, adhere to the following guidelines:
66518
66773
  timeout,
66519
66774
  interactive
66520
66775
  }, { toolCallId, abortSignal }) => {
66521
- const cols = DEFAULT_PTY_COLS;
66776
+ const cols2 = DEFAULT_PTY_COLS;
66522
66777
  const rows = DEFAULT_PTY_ROWS;
66523
66778
  let activePtySessionId;
66524
66779
  let emitQueue = Promise.resolve();
@@ -66613,20 +66868,20 @@ In using these tools, adhere to the following guidelines:
66613
66868
  }
66614
66869
  }
66615
66870
  const session = await ptySessionManager2.create(chatId, {
66616
- cols,
66871
+ cols: cols2,
66617
66872
  rows,
66618
66873
  createHandle: async () => {
66619
66874
  if (isCentrifugo) {
66620
66875
  const { createCentrifugoPtyHandle: createCentrifugoPtyHandle2 } = await Promise.resolve().then(() => (init_centrifugo_pty_adapter(), centrifugo_pty_adapter_exports));
66621
66876
  return createCentrifugoPtyHandle2(sandbox, {
66622
66877
  command,
66623
- cols,
66878
+ cols: cols2,
66624
66879
  rows,
66625
66880
  envs: caidoEnvVars
66626
66881
  });
66627
66882
  }
66628
66883
  return createE2BPtyHandle(sandbox, {
66629
- cols,
66884
+ cols: cols2,
66630
66885
  rows,
66631
66886
  envs: caidoEnvVars
66632
66887
  });
@@ -67305,8 +67560,8 @@ var init_logger2 = __esm({
67305
67560
  });
67306
67561
 
67307
67562
  // ../lib/ai/tools/file.ts
67308
- function isSpritPath(path8) {
67309
- return path8.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
67563
+ function isSpritPath(path10) {
67564
+ return path10.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
67310
67565
  }
67311
67566
  function getViewSandboxType(sandbox) {
67312
67567
  return isCentrifugoSandbox(sandbox) ? "centrifugo" : "e2b";
@@ -67337,7 +67592,7 @@ function captureFileViewImageUsage(args) {
67337
67592
  const {
67338
67593
  context: context2,
67339
67594
  sandbox,
67340
- path: path8,
67595
+ path: path10,
67341
67596
  outcome,
67342
67597
  durationMs,
67343
67598
  mediaType,
@@ -67355,7 +67610,7 @@ function captureFileViewImageUsage(args) {
67355
67610
  model: getActiveModelName(context2),
67356
67611
  configured_model: context2.modelName,
67357
67612
  sandbox_type: getViewSandboxType(sandbox),
67358
- file_extension: getFileExtension(path8),
67613
+ file_extension: getFileExtension(path10),
67359
67614
  outcome,
67360
67615
  success: outcome === "success",
67361
67616
  duration_ms: durationMs,
@@ -67429,22 +67684,22 @@ async function runSandboxCommand(sandbox, command, envVars, timeoutMs = 6e4) {
67429
67684
  function isWindowsSandbox(sandbox) {
67430
67685
  return isCentrifugoSandbox(sandbox) && sandbox.isWindows();
67431
67686
  }
67432
- function getWindowsNativePath(path8) {
67433
- if (/^[A-Za-z]:[\\/]/.test(path8)) return path8;
67434
- if (path8.startsWith("/tmp/")) {
67435
- return `C:\\temp${path8.slice(4).replace(/\//g, "\\")}`;
67687
+ function getWindowsNativePath(path10) {
67688
+ if (/^[A-Za-z]:[\\/]/.test(path10)) return path10;
67689
+ if (path10.startsWith("/tmp/")) {
67690
+ return `C:\\temp${path10.slice(4).replace(/\//g, "\\")}`;
67436
67691
  }
67437
- return path8.replace(/\//g, "\\");
67692
+ return path10.replace(/\//g, "\\");
67438
67693
  }
67439
- function getPythonPathForSandbox(sandbox, path8) {
67440
- return isWindowsSandbox(sandbox) ? getWindowsNativePath(path8) : path8;
67694
+ function getPythonPathForSandbox(sandbox, path10) {
67695
+ return isWindowsSandbox(sandbox) ? getWindowsNativePath(path10) : path10;
67441
67696
  }
67442
- function toWindowsBashPath(path8) {
67443
- const drive = path8.match(/^([A-Za-z]):[\\/](.*)$/);
67697
+ function toWindowsBashPath(path10) {
67698
+ const drive = path10.match(/^([A-Za-z]):[\\/](.*)$/);
67444
67699
  if (drive) {
67445
67700
  return `/${drive[1].toLowerCase()}/${drive[2].replace(/\\/g, "/")}`;
67446
67701
  }
67447
- return path8.replace(/\\/g, "/");
67702
+ return path10.replace(/\\/g, "/");
67448
67703
  }
67449
67704
  async function detectSandboxShell(sandbox) {
67450
67705
  if (!isWindowsSandbox(sandbox)) return "bash";
@@ -67483,8 +67738,8 @@ PY`;
67483
67738
  }
67484
67739
  }
67485
67740
  }
67486
- async function getSandboxFileState(sandbox, path8) {
67487
- const pythonPath = getPythonPathForSandbox(sandbox, path8);
67741
+ async function getSandboxFileState(sandbox, path10) {
67742
+ const pythonPath = getPythonPathForSandbox(sandbox, path10);
67488
67743
  const result = await runPythonScript(
67489
67744
  sandbox,
67490
67745
  FILE_STATE_SCRIPT,
@@ -67501,23 +67756,23 @@ async function getSandboxFileState(sandbox, path8) {
67501
67756
  if (result.exitCode !== 0) {
67502
67757
  return {
67503
67758
  kind: "unknown",
67504
- path: path8,
67759
+ path: path10,
67505
67760
  error: result.stderr || result.stdout || "file state command failed"
67506
67761
  };
67507
67762
  }
67508
67763
  try {
67509
67764
  const payload = JSON.parse(result.stdout.trim());
67510
67765
  if (payload.kind === "file" && typeof payload.sizeBytes === "number" && Number.isFinite(payload.sizeBytes)) {
67511
- return { ...payload, path: path8 };
67766
+ return { ...payload, path: path10 };
67512
67767
  }
67513
67768
  if (payload.kind === "missing" || payload.kind === "not_file") {
67514
- return { ...payload, path: path8 };
67769
+ return { ...payload, path: path10 };
67515
67770
  }
67516
67771
  } catch {
67517
67772
  }
67518
67773
  return {
67519
67774
  kind: "unknown",
67520
- path: path8,
67775
+ path: path10,
67521
67776
  error: result.stderr || result.stdout || "invalid file state response"
67522
67777
  };
67523
67778
  }
@@ -67549,8 +67804,8 @@ ${numberedContent}${truncatedNotice}${footerNotice}`;
67549
67804
  })
67550
67805
  };
67551
67806
  }
67552
- async function readSandboxTextFile(sandbox, path8, range) {
67553
- const pythonPath = getPythonPathForSandbox(sandbox, path8);
67807
+ async function readSandboxTextFile(sandbox, path10, range) {
67808
+ const pythonPath = getPythonPathForSandbox(sandbox, path10);
67554
67809
  const envVars = {
67555
67810
  HACKERAI_FILE_READ_PATH: pythonPath,
67556
67811
  HACKERAI_FILE_READ_RANGE_START: String(range?.[0] ?? 0),
@@ -67578,40 +67833,40 @@ async function readSandboxTextFile(sandbox, path8, range) {
67578
67833
  }
67579
67834
  return payload;
67580
67835
  }
67581
- async function readSandboxTextFileWithFallback(sandbox, path8, range) {
67836
+ async function readSandboxTextFileWithFallback(sandbox, path10, range) {
67582
67837
  try {
67583
- return await readSandboxTextFile(sandbox, path8, range);
67838
+ return await readSandboxTextFile(sandbox, path10, range);
67584
67839
  } catch (error51) {
67585
67840
  const errorMessage = error51 instanceof Error ? error51.message : String(error51);
67586
67841
  if (errorMessage.startsWith("Invalid ") || errorMessage.includes("File not found")) {
67587
67842
  throw error51;
67588
67843
  }
67589
- const state = await getSandboxFileState(sandbox, path8);
67844
+ const state = await getSandboxFileState(sandbox, path10);
67590
67845
  if (state.kind === "unknown") {
67591
67846
  throw new Error(
67592
- `Unable to determine file size for ${path8}; refusing to load the file into memory. ${state.error}`
67847
+ `Unable to determine file size for ${path10}; refusing to load the file into memory. ${state.error}`
67593
67848
  );
67594
67849
  }
67595
67850
  if (state.kind === "missing") {
67596
- throw new Error(`File not found or is not a regular file: ${path8}`);
67851
+ throw new Error(`File not found or is not a regular file: ${path10}`);
67597
67852
  }
67598
67853
  if (state.kind === "not_file") {
67599
- throw new Error(`File is not a regular file: ${path8}`);
67854
+ throw new Error(`File is not a regular file: ${path10}`);
67600
67855
  }
67601
67856
  if (state.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
67602
67857
  if (range) {
67603
67858
  throw new Error(
67604
- `Unable to perform a bounded range read for ${path8}, and the file is too large to load safely (${formatBytes(state.sizeBytes)}). Use a targeted terminal command that writes a small result to a separate file.`
67859
+ `Unable to perform a bounded range read for ${path10}, and the file is too large to load safely (${formatBytes(state.sizeBytes)}). Use a targeted terminal command that writes a small result to a separate file.`
67605
67860
  );
67606
67861
  }
67607
67862
  return {
67608
- path: path8,
67863
+ path: path10,
67609
67864
  sizeBytes: state.sizeBytes,
67610
67865
  totalLines: 0,
67611
67866
  tooLarge: true
67612
67867
  };
67613
67868
  }
67614
- const fileContent = await sandbox.files.read(path8, {
67869
+ const fileContent = await sandbox.files.read(path10, {
67615
67870
  user: "user"
67616
67871
  });
67617
67872
  const lines = fileContent.split("\n");
@@ -67640,7 +67895,7 @@ async function readSandboxTextFileWithFallback(sandbox, path8, range) {
67640
67895
  const startIndex = start - 1;
67641
67896
  const endIndex = end === -1 ? lines.length : end;
67642
67897
  return {
67643
- path: path8,
67898
+ path: path10,
67644
67899
  sizeBytes: Buffer.byteLength(fileContent),
67645
67900
  totalLines: lines.length,
67646
67901
  content: lines.slice(startIndex, endIndex).join("\n"),
@@ -67648,7 +67903,7 @@ async function readSandboxTextFileWithFallback(sandbox, path8, range) {
67648
67903
  };
67649
67904
  }
67650
67905
  return {
67651
- path: path8,
67906
+ path: path10,
67652
67907
  sizeBytes: Buffer.byteLength(fileContent),
67653
67908
  totalLines: lines.length,
67654
67909
  content: fileContent,
@@ -67656,7 +67911,7 @@ async function readSandboxTextFileWithFallback(sandbox, path8, range) {
67656
67911
  };
67657
67912
  }
67658
67913
  }
67659
- async function appendSandboxTextFile(sandbox, path8, text2) {
67914
+ async function appendSandboxTextFile(sandbox, path10, text2) {
67660
67915
  const tempPath = `/tmp/hackerai_append_${Date.now()}_${Math.random().toString(36).slice(2)}.tmp`;
67661
67916
  await sandbox.files.write(tempPath, text2, {
67662
67917
  user: "user"
@@ -67665,7 +67920,7 @@ async function appendSandboxTextFile(sandbox, path8, text2) {
67665
67920
  sandbox,
67666
67921
  APPEND_TEXT_FILE_SCRIPT,
67667
67922
  {
67668
- HACKERAI_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path8),
67923
+ HACKERAI_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path10),
67669
67924
  HACKERAI_FILE_APPEND_SOURCE_PATH: getPythonPathForSandbox(
67670
67925
  sandbox,
67671
67926
  tempPath
@@ -67677,13 +67932,13 @@ async function appendSandboxTextFile(sandbox, path8, text2) {
67677
67932
  throw new Error(result.stderr || result.stdout || "Failed to append file");
67678
67933
  }
67679
67934
  }
67680
- async function readSandboxFileForView(sandbox, path8, includeData) {
67935
+ async function readSandboxFileForView(sandbox, path10, includeData) {
67681
67936
  if (isCentrifugoSandbox(sandbox) && sandbox.isWindows()) {
67682
67937
  throw new Error(
67683
67938
  "The view action is not available for Windows local sandboxes yet. Use a Linux/E2B sandbox or inspect the image manually."
67684
67939
  );
67685
67940
  }
67686
- const sandboxPath = getSandboxViewPath(sandbox, path8);
67941
+ const sandboxPath = getSandboxViewPath(sandbox, path10);
67687
67942
  const viewEnvVars = {
67688
67943
  HACKERAI_FILE_VIEW_PATH: sandboxPath,
67689
67944
  HACKERAI_FILE_VIEW_INCLUDE_DATA: includeData ? "1" : "0",
@@ -68026,19 +68281,19 @@ try:
68026
68281
  except OSError:
68027
68282
  pass
68028
68283
  `;
68029
- getFilename = (path8) => path8.split("/").pop() || path8;
68030
- getFileExtension = (path8) => {
68031
- const filename = getFilename(path8);
68284
+ getFilename = (path10) => path10.split("/").pop() || path10;
68285
+ getFileExtension = (path10) => {
68286
+ const filename = getFilename(path10);
68032
68287
  const dotIndex = filename.lastIndexOf(".");
68033
68288
  if (dotIndex <= 0 || dotIndex === filename.length - 1) return void 0;
68034
68289
  return filename.slice(dotIndex + 1).toLowerCase();
68035
68290
  };
68036
- getSandboxViewPath = (sandbox, path8) => {
68291
+ getSandboxViewPath = (sandbox, path10) => {
68037
68292
  const maybeSandbox = sandbox;
68038
- if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path8.startsWith("/tmp/")) {
68039
- return `C:\\temp${path8.slice(4).replace(/\//g, "\\")}`;
68293
+ if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path10.startsWith("/tmp/")) {
68294
+ return `C:\\temp${path10.slice(4).replace(/\//g, "\\")}`;
68040
68295
  }
68041
- return path8;
68296
+ return path10;
68042
68297
  };
68043
68298
  stripTrailingWs = (line) => line.replace(/[ \t]+$/u, "");
68044
68299
  editSchema = external_exports.object({
@@ -68112,7 +68367,7 @@ ${instructionsDescription}`,
68112
68367
  "A list of edits to be sequentially applied to the file. Required for `edit` action."
68113
68368
  )
68114
68369
  }),
68115
- execute: async ({ action, path: path8, text: text2, range, edits }) => {
68370
+ execute: async ({ action, path: path10, text: text2, range, edits }) => {
68116
68371
  try {
68117
68372
  const { sandbox } = await sandboxManager.getSandbox();
68118
68373
  switch (action) {
@@ -68122,7 +68377,7 @@ ${instructionsDescription}`,
68122
68377
  captureFileViewImageUsage({
68123
68378
  context: context2,
68124
68379
  sandbox,
68125
- path: path8,
68380
+ path: path10,
68126
68381
  outcome: "unsupported_model",
68127
68382
  durationMs: Date.now() - viewStartedAt,
68128
68383
  failureReason: "unsupported_model"
@@ -68131,26 +68386,26 @@ ${instructionsDescription}`,
68131
68386
  }
68132
68387
  let viewPayload;
68133
68388
  try {
68134
- viewPayload = await readSandboxFileForView(sandbox, path8, false);
68389
+ viewPayload = await readSandboxFileForView(sandbox, path10, false);
68135
68390
  } catch (error51) {
68136
68391
  captureFileViewImageUsage({
68137
68392
  context: context2,
68138
68393
  sandbox,
68139
- path: path8,
68394
+ path: path10,
68140
68395
  outcome: "inspection_failed",
68141
68396
  durationMs: Date.now() - viewStartedAt,
68142
68397
  failureReason: classifyFileViewError(error51)
68143
68398
  });
68144
68399
  throw error51;
68145
68400
  }
68146
- const filename = getFilename(path8);
68401
+ const filename = getFilename(path10);
68147
68402
  let previewFiles = [];
68148
68403
  let previewUploadError;
68149
68404
  try {
68150
68405
  previewFiles = await uploadViewPreviewFiles({
68151
68406
  context: context2,
68152
68407
  sandbox,
68153
- sourcePath: path8,
68408
+ sourcePath: path10,
68154
68409
  payload: viewPayload
68155
68410
  });
68156
68411
  } catch (error51) {
@@ -68164,7 +68419,7 @@ ${instructionsDescription}`,
68164
68419
  user_id: context2.userID,
68165
68420
  sandbox_type: getViewSandboxType(sandbox),
68166
68421
  file_name: filename,
68167
- source_path: path8,
68422
+ source_path: path10,
68168
68423
  kind: viewPayload.kind,
68169
68424
  media_type: viewPayload.mediaType,
68170
68425
  size_bytes: viewPayload.sizeBytes,
@@ -68175,7 +68430,7 @@ ${instructionsDescription}`,
68175
68430
  captureFileViewImageUsage({
68176
68431
  context: context2,
68177
68432
  sandbox,
68178
- path: path8,
68433
+ path: path10,
68179
68434
  outcome: "success",
68180
68435
  durationMs: Date.now() - viewStartedAt,
68181
68436
  mediaType: viewPayload.mediaType,
@@ -68185,7 +68440,7 @@ ${instructionsDescription}`,
68185
68440
  return {
68186
68441
  action: "view",
68187
68442
  content: `Viewing image file: ${filename} (${viewPayload.mediaType}, ${viewPayload.sizeBytes} bytes).`,
68188
- path: path8,
68443
+ path: path10,
68189
68444
  filename,
68190
68445
  mediaType: viewPayload.mediaType,
68191
68446
  sizeBytes: viewPayload.sizeBytes,
@@ -68195,8 +68450,8 @@ ${instructionsDescription}`,
68195
68450
  };
68196
68451
  }
68197
68452
  case "read": {
68198
- const filename = path8.split("/").pop() || path8;
68199
- const spritChunked = isSpritPath(path8);
68453
+ const filename = path10.split("/").pop() || path10;
68454
+ const spritChunked = isSpritPath(path10);
68200
68455
  let effectiveRange = range;
68201
68456
  if (spritChunked) {
68202
68457
  const start = range && range[0] > 0 ? range[0] : 1;
@@ -68209,7 +68464,7 @@ ${instructionsDescription}`,
68209
68464
  }
68210
68465
  const readPayload = await readSandboxTextFileWithFallback(
68211
68466
  sandbox,
68212
- path8,
68467
+ path10,
68213
68468
  effectiveRange
68214
68469
  );
68215
68470
  if (readPayload.tooLarge) {
@@ -68246,46 +68501,46 @@ File is too large to read in full (${formatBytes(readPayload.sizeBytes)}, ${tota
68246
68501
  if (text2 === void 0) {
68247
68502
  return { error: "text is required for write action" };
68248
68503
  }
68249
- await sandbox.files.write(path8, text2, {
68504
+ await sandbox.files.write(path10, text2, {
68250
68505
  user: "user"
68251
68506
  });
68252
- return `File written: ${path8}`;
68507
+ return `File written: ${path10}`;
68253
68508
  }
68254
68509
  case "append": {
68255
68510
  if (text2 === void 0) {
68256
68511
  return { error: "text is required for append action" };
68257
68512
  }
68258
- const existingState = await getSandboxFileState(sandbox, path8);
68513
+ const existingState = await getSandboxFileState(sandbox, path10);
68259
68514
  if (existingState.kind === "unknown") {
68260
68515
  return {
68261
- error: `Cannot append safely because the existing file size could not be determined for ${path8}. ${existingState.error}`
68516
+ error: `Cannot append safely because the existing file size could not be determined for ${path10}. ${existingState.error}`
68262
68517
  };
68263
68518
  }
68264
68519
  if (existingState.kind === "not_file") {
68265
68520
  return {
68266
- error: `Cannot append to ${path8} because it is not a file.`
68521
+ error: `Cannot append to ${path10} because it is not a file.`
68267
68522
  };
68268
68523
  }
68269
68524
  if (existingState.kind === "file" && existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68270
- await appendSandboxTextFile(sandbox, path8, text2);
68525
+ await appendSandboxTextFile(sandbox, path10, text2);
68271
68526
  return {
68272
- content: `File appended: ${path8}
68527
+ content: `File appended: ${path10}
68273
68528
  Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff preview was skipped to avoid loading the entire file into memory.`
68274
68529
  };
68275
68530
  }
68276
68531
  let existingContent = "";
68277
68532
  try {
68278
- existingContent = await sandbox.files.read(path8, {
68533
+ existingContent = await sandbox.files.read(path10, {
68279
68534
  user: "user"
68280
68535
  });
68281
68536
  } catch {
68282
68537
  }
68283
68538
  const newContent = existingContent + text2;
68284
- await sandbox.files.write(path8, newContent, {
68539
+ await sandbox.files.write(path10, newContent, {
68285
68540
  user: "user"
68286
68541
  });
68287
68542
  return {
68288
- content: `File appended: ${path8}`,
68543
+ content: `File appended: ${path10}`,
68289
68544
  originalContent: truncateOutput({
68290
68545
  content: existingContent,
68291
68546
  mode: "read-file"
@@ -68300,31 +68555,31 @@ Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff previ
68300
68555
  if (!edits || edits.length === 0) {
68301
68556
  return { error: "edits array is required for edit action" };
68302
68557
  }
68303
- const existingState = await getSandboxFileState(sandbox, path8);
68558
+ const existingState = await getSandboxFileState(sandbox, path10);
68304
68559
  if (existingState.kind === "unknown") {
68305
68560
  return {
68306
- error: `Cannot edit ${path8} safely because the file size could not be determined. ${existingState.error}`
68561
+ error: `Cannot edit ${path10} safely because the file size could not be determined. ${existingState.error}`
68307
68562
  };
68308
68563
  }
68309
68564
  if (existingState.kind === "missing") {
68310
68565
  return {
68311
- error: `Cannot edit file ${path8} - file is empty or does not exist`
68566
+ error: `Cannot edit file ${path10} - file is empty or does not exist`
68312
68567
  };
68313
68568
  }
68314
68569
  if (existingState.kind === "not_file") {
68315
- return { error: `Cannot edit ${path8} because it is not a file.` };
68570
+ return { error: `Cannot edit ${path10} because it is not a file.` };
68316
68571
  }
68317
68572
  if (existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68318
68573
  return {
68319
- error: `File ${path8} is too large for the edit action (${formatBytes(existingState.sizeBytes)}). Use a targeted shell command, restore the file from a clean source, or replace it with the write action instead of loading the whole file into memory.`
68574
+ error: `File ${path10} is too large for the edit action (${formatBytes(existingState.sizeBytes)}). Use a targeted shell command, restore the file from a clean source, or replace it with the write action instead of loading the whole file into memory.`
68320
68575
  };
68321
68576
  }
68322
- const originalContent = await sandbox.files.read(path8, {
68577
+ const originalContent = await sandbox.files.read(path10, {
68323
68578
  user: "user"
68324
68579
  });
68325
68580
  if (!originalContent) {
68326
68581
  return {
68327
- error: `Cannot edit file ${path8} - file is empty or does not exist`
68582
+ error: `Cannot edit file ${path10} - file is empty or does not exist`
68328
68583
  };
68329
68584
  }
68330
68585
  const resolvedEdits = [];
@@ -68369,7 +68624,7 @@ ${hint}` : "")
68369
68624
  }
68370
68625
  }
68371
68626
  }
68372
- await sandbox.files.write(path8, content, {
68627
+ await sandbox.files.write(path10, content, {
68373
68628
  user: "user"
68374
68629
  });
68375
68630
  const lines = content.split("\n");
@@ -68609,11 +68864,11 @@ function findGitBash() {
68609
68864
  if ((0, import_fs.existsSync)(c)) return c;
68610
68865
  }
68611
68866
  try {
68612
- const out2 = (0, import_child_process.execSync)("where git", {
68867
+ const out3 = (0, import_child_process.execSync)("where git", {
68613
68868
  encoding: "utf8",
68614
68869
  stdio: ["ignore", "pipe", "ignore"]
68615
68870
  });
68616
- const gitExe = out2.split(/\r?\n/).find((l) => l.trim().endsWith("git.exe"));
68871
+ const gitExe = out3.split(/\r?\n/).find((l) => l.trim().endsWith("git.exe"));
68617
68872
  if (gitExe) {
68618
68873
  const bash = (0, import_path3.join)((0, import_path3.dirname)((0, import_path3.dirname)(gitExe.trim())), "bin", "bash.exe");
68619
68874
  if ((0, import_fs.existsSync)(bash)) return bash;
@@ -68652,14 +68907,14 @@ function inferShellFlag(shell2) {
68652
68907
  }
68653
68908
  return "-c";
68654
68909
  }
68655
- var import_node_child_process2, import_node_fs6, import_node_path5, import_node_os2, import_node_url, import_meta, LocalSandbox;
68910
+ var import_node_child_process2, import_node_fs6, import_node_path5, import_node_os3, import_node_url, import_meta, LocalSandbox;
68656
68911
  var init_local_sandbox = __esm({
68657
68912
  "src/local-sandbox.ts"() {
68658
68913
  "use strict";
68659
68914
  import_node_child_process2 = require("node:child_process");
68660
68915
  import_node_fs6 = require("node:fs");
68661
68916
  import_node_path5 = __toESM(require("node:path"));
68662
- import_node_os2 = __toESM(require("node:os"));
68917
+ import_node_os3 = __toESM(require("node:os"));
68663
68918
  import_node_url = require("node:url");
68664
68919
  init_utils4();
68665
68920
  import_meta = {};
@@ -68784,7 +69039,7 @@ var init_local_sandbox = __esm({
68784
69039
  this.shellBin = shellOverride;
68785
69040
  this.shellFlag = process.env.CLI_SHELL_FLAG || inferShellFlag(shellOverride);
68786
69041
  } else {
68787
- const shell2 = getDefaultShell(import_node_os2.default.platform());
69042
+ const shell2 = getDefaultShell(import_node_os3.default.platform());
68788
69043
  this.shellBin = shell2.shell;
68789
69044
  this.shellFlag = shell2.shellFlag;
68790
69045
  }
@@ -68794,6 +69049,7 @@ var init_local_sandbox = __esm({
68794
69049
  async init() {
68795
69050
  await import_node_fs6.promises.mkdir(this.workdir, { recursive: true });
68796
69051
  await this.seedReconToolkit();
69052
+ await this.seedAuditToolkit();
68797
69053
  }
68798
69054
  /**
68799
69055
  * Seed the deep-recon toolkit (recon_deep.py + console_recon.js + README)
@@ -68834,27 +69090,50 @@ var init_local_sandbox = __esm({
68834
69090
  } catch {
68835
69091
  }
68836
69092
  }
69093
+ /**
69094
+ * Seed the read-only project-audit toolkit (project_audit.py + README) into
69095
+ * <workdir>/audit so the agent can deeply analyze the user's own project on
69096
+ * demand. Tooling files are refreshed each session so fixes propagate.
69097
+ * Best-effort: a failure here must never block the session.
69098
+ */
69099
+ async seedAuditToolkit() {
69100
+ try {
69101
+ const assetsDir = (0, import_node_url.fileURLToPath)(
69102
+ new URL("../assets/audit", import_meta.url)
69103
+ );
69104
+ const destDir = import_node_path5.default.join(this.workdir, "audit");
69105
+ await import_node_fs6.promises.mkdir(destDir, { recursive: true });
69106
+ for (const name25 of ["project_audit.py", "README.md"]) {
69107
+ try {
69108
+ const content = await import_node_fs6.promises.readFile(import_node_path5.default.join(assetsDir, name25));
69109
+ await import_node_fs6.promises.writeFile(import_node_path5.default.join(destDir, name25), content);
69110
+ } catch {
69111
+ }
69112
+ }
69113
+ } catch {
69114
+ }
69115
+ }
68837
69116
  getConnectionId() {
68838
69117
  return "local";
68839
69118
  }
68840
69119
  getConnectionName() {
68841
- return `local:${import_node_os2.default.hostname()}`;
69120
+ return `local:${import_node_os3.default.hostname()}`;
68842
69121
  }
68843
69122
  getUserId() {
68844
69123
  return "local";
68845
69124
  }
68846
69125
  isWindows() {
68847
- return import_node_os2.default.platform() === "win32" && !this.isBashLikeShell();
69126
+ return import_node_os3.default.platform() === "win32" && !this.isBashLikeShell();
68848
69127
  }
68849
69128
  supportsPty() {
68850
69129
  return false;
68851
69130
  }
68852
69131
  getSandboxContext() {
68853
- const platform = `${import_node_os2.default.type()} ${import_node_os2.default.release()} (${import_node_os2.default.arch()})`;
69132
+ const platform = `${import_node_os3.default.type()} ${import_node_os3.default.release()} (${import_node_os3.default.arch()})`;
68854
69133
  const shellInvocation = `${this.shellBin} ${this.shellFlag}`;
68855
- const windowsNotes = import_node_os2.default.platform() === "win32" ? this.getWindowsShellNotes() : "";
69134
+ const windowsNotes = import_node_os3.default.platform() === "win32" ? this.getWindowsShellNotes() : "";
68856
69135
  const pentestToolingNotes = this.getLocalPentestToolingNotes();
68857
- return `You are executing commands directly on the user's local host (${platform}, hostname "${import_node_os2.default.hostname()}") in DANGEROUS MODE: there is NO sandbox isolation.
69136
+ return `You are executing commands directly on the user's local host (${platform}, hostname "${import_node_os3.default.hostname()}") in DANGEROUS MODE: there is NO sandbox isolation.
68858
69137
  Commands are invoked via \`${shellInvocation}\`. The working directory is "${this.workdir}".
68859
69138
  Be careful: file system, network and process operations all affect the real host system.
68860
69139
  A real human user is present at this terminal. When a command prompts for input \u2014 a password, a y/n confirmation, an interactive installer, a REPL prompt (python, mysql, ftp), an ssh/sudo prompt, etc. \u2014 the user types the answer and it is forwarded to the command's stdin. So you MAY run commands that prompt for input; just run the command and the user will respond when asked. Prefer non-interactive flags (like --yes) when they exist and are convenient, but interactive prompts are fully supported. Only full-screen / raw-mode TUI programs (vim, top, htop, less without \`| cat\`) are unsupported, since there is no PTY \u2014 avoid those and use line-oriented alternatives.
@@ -68879,6 +69158,21 @@ EDITING SCRIPTS:
68879
69158
  getOsContext() {
68880
69159
  return this.getSandboxContext();
68881
69160
  }
69161
+ /**
69162
+ * One concise paragraph about the shell the agent's commands run in, plus the
69163
+ * critical "each command is a fresh shell" rule. Used by the standalone audit
69164
+ * prompt, which doesn't carry the full sandbox context.
69165
+ */
69166
+ getShellHint() {
69167
+ const persist = "IMPORTANTE: cada comando roda num shell NOVO \u2014 vari\xE1veis, `export`/`set` e mudan\xE7as de PATH N\xC3O persistem para o pr\xF3ximo comando. Chame cada ferramenta pelo caminho completo, por um lan\xE7ador que resolve o PATH (`npx <pkg>`), ou via `python -m <modulo>`.";
69168
+ if (this.isBashLikeShell()) {
69169
+ return `Shell: ${this.shellBin} (POSIX, tipo Git Bash). Use sintaxe bash: \`export VAR=...\`, \`command -v ferramenta\`, \`which\`. N\xC3O use \`set VAR=\` nem \`where\` do cmd. ${persist}`;
69170
+ }
69171
+ if (this.isCmdShell()) {
69172
+ return `Shell: cmd.exe. Use \`where ferramenta\` e \`set VAR=...\`; evite sintaxe bash (\`export\`, \`$(...)\`, heredoc). ${persist}`;
69173
+ }
69174
+ return `Shell: ${this.shellBin}. Verifique a sintaxe antes de assumir bash ou cmd. ${persist}`;
69175
+ }
68882
69176
  getWorkdir() {
68883
69177
  return this.workdir;
68884
69178
  }
@@ -68928,7 +69222,7 @@ EDITING SCRIPTS:
68928
69222
  // alive — `taskkill /T` tears down the whole tree so Ctrl+C truly stops it.
68929
69223
  killChildTree(child) {
68930
69224
  const pid = child.pid;
68931
- if (pid && import_node_os2.default.platform() === "win32") {
69225
+ if (pid && import_node_os3.default.platform() === "win32") {
68932
69226
  try {
68933
69227
  (0, import_node_child_process2.spawn)("taskkill", ["/PID", String(pid), "/T", "/F"], {
68934
69228
  windowsHide: true
@@ -68983,7 +69277,7 @@ WINDOWS SHELL NOTES:
68983
69277
  - For HTTP, prefer \`curl.exe\` if available; for DNS use \`nslookup\`.`;
68984
69278
  }
68985
69279
  getLocalPentestToolingNotes() {
68986
- if (import_node_os2.default.platform() === "win32") {
69280
+ if (import_node_os3.default.platform() === "win32") {
68987
69281
  return `
68988
69282
 
68989
69283
  LOCAL PENTEST TOOLING:
@@ -69102,10 +69396,10 @@ function createRenderer() {
69102
69396
  reasoning(delta) {
69103
69397
  sep3("reasoning");
69104
69398
  if (!reasoningHeaderShown) {
69105
- out(`${C2.dim}pensando: `);
69399
+ out(`${C3.dim}pensando: `);
69106
69400
  reasoningHeaderShown = true;
69107
69401
  }
69108
- out(`${C2.dim}${delta}${C2.reset}`);
69402
+ out(`${C3.dim}${delta}${C3.reset}`);
69109
69403
  },
69110
69404
  toolCall(toolName, input) {
69111
69405
  sep3("tool");
@@ -69117,23 +69411,23 @@ function createRenderer() {
69117
69411
  const note = summarizeResult(toolName, output);
69118
69412
  if (note) {
69119
69413
  sep3("tool");
69120
- out(`${C2.dim} ok ${note}${C2.reset}
69414
+ out(`${C3.dim} ok ${note}${C3.reset}
69121
69415
  `);
69122
69416
  }
69123
69417
  },
69124
69418
  info(msg) {
69125
69419
  sep3("info");
69126
- out(`${C2.dim}${msg}${C2.reset}
69420
+ out(`${C3.dim}${msg}${C3.reset}
69127
69421
  `);
69128
69422
  },
69129
69423
  fallback(msg) {
69130
69424
  sep3("info");
69131
- out(`${C2.yellow}-> ${msg}${C2.reset}
69425
+ out(`${C3.yellow}-> ${msg}${C3.reset}
69132
69426
  `);
69133
69427
  },
69134
69428
  error(msg) {
69135
69429
  sep3("info");
69136
- out(`${C2.red}x ${msg}${C2.reset}
69430
+ out(`${C3.red}x ${msg}${C3.reset}
69137
69431
  `);
69138
69432
  },
69139
69433
  endTurn() {
@@ -69151,31 +69445,31 @@ function formatToolCall(toolName, input) {
69151
69445
  switch (toolName) {
69152
69446
  case "run_terminal_cmd": {
69153
69447
  const cmd = String(i.command ?? "").trim();
69154
- const bg = i.is_background ? `${C2.dim} (background)${C2.reset}` : "";
69155
- return `${C2.cyan}executando${C2.reset} ${C2.bold}$ ${truncate3(cmd, 400)}${C2.reset}${bg}`;
69448
+ const bg = i.is_background ? `${C3.dim} (background)${C3.reset}` : "";
69449
+ return `${C3.cyan}executando${C3.reset} ${C3.bold}$ ${truncate3(cmd, 400)}${C3.reset}${bg}`;
69156
69450
  }
69157
69451
  case "file": {
69158
- const path8 = String(i.path ?? "");
69159
- const brief = i.brief ? `${C2.dim} - ${truncate3(String(i.brief))}${C2.reset}` : "";
69452
+ const path10 = String(i.path ?? "");
69453
+ const brief = i.brief ? `${C3.dim} - ${truncate3(String(i.brief))}${C3.reset}` : "";
69160
69454
  const map2 = {
69161
- write: `${C2.green}criando arquivo${C2.reset}`,
69162
- edit: `${C2.yellow}editando arquivo${C2.reset}`,
69163
- append: `${C2.green}anexando arquivo${C2.reset}`,
69164
- read: `${C2.blue}lendo arquivo${C2.reset}`,
69165
- view: `${C2.blue}visualizando arquivo${C2.reset}`
69455
+ write: `${C3.green}criando arquivo${C3.reset}`,
69456
+ edit: `${C3.yellow}editando arquivo${C3.reset}`,
69457
+ append: `${C3.green}anexando arquivo${C3.reset}`,
69458
+ read: `${C3.blue}lendo arquivo${C3.reset}`,
69459
+ view: `${C3.blue}visualizando arquivo${C3.reset}`
69166
69460
  };
69167
69461
  const action = typeof i.action === "string" ? i.action : "";
69168
- const label = map2[action] ?? (action ? `${C2.blue}arquivo (${action})${C2.reset}` : `${C2.blue}preparando operacao de arquivo${C2.reset}`);
69169
- const target = path8 ? ` ${C2.bold}${path8}${C2.reset}` : "";
69462
+ const label = map2[action] ?? (action ? `${C3.blue}arquivo (${action})${C3.reset}` : `${C3.blue}preparando operacao de arquivo${C3.reset}`);
69463
+ const target = path10 ? ` ${C3.bold}${path10}${C3.reset}` : "";
69170
69464
  return `${label}${target}${brief}`;
69171
69465
  }
69172
69466
  case "todo_write":
69173
- return `${C2.magenta}atualizando lista de tarefas${C2.reset}`;
69467
+ return `${C3.magenta}atualizando lista de tarefas${C3.reset}`;
69174
69468
  default:
69175
- return `${C2.cyan}${toolName}${C2.reset} ${C2.dim}${truncate3(
69469
+ return `${C3.cyan}${toolName}${C3.reset} ${C3.dim}${truncate3(
69176
69470
  JSON.stringify(i),
69177
69471
  200
69178
- )}${C2.reset}`;
69472
+ )}${C3.reset}`;
69179
69473
  }
69180
69474
  }
69181
69475
  function summarizeResult(toolName, output) {
@@ -69189,11 +69483,11 @@ function summarizeResult(toolName, output) {
69189
69483
  if (toolName === "todo_write") return "tarefas salvas";
69190
69484
  return null;
69191
69485
  }
69192
- var C2, out, truncate3;
69486
+ var C3, out, truncate3;
69193
69487
  var init_render = __esm({
69194
69488
  "src/render.ts"() {
69195
69489
  "use strict";
69196
- C2 = {
69490
+ C3 = {
69197
69491
  reset: "\x1B[0m",
69198
69492
  dim: "\x1B[90m",
69199
69493
  red: "\x1B[31m",
@@ -69331,11 +69625,11 @@ async function ensureProxyReady(id, log2) {
69331
69625
  message: `${def.label}: o proxy n\xE3o respondeu em 90s. Tente de novo, ou rode 'npm run login' em ${dir}.`
69332
69626
  };
69333
69627
  }
69334
- var import_node_os3, import_node_path6, import_node_fs7, import_node_child_process3, DEFS, PROXY_MODEL_KEYS, proxyIdForModelKey, proxiesRoot, dirFor, healthUrl, baseUrl, wait, started, exitHooksInstalled, quoteArg, asShellCommand, run, hasCommand;
69628
+ var import_node_os4, import_node_path6, import_node_fs7, import_node_child_process3, DEFS, PROXY_MODEL_KEYS, proxyIdForModelKey, proxiesRoot, dirFor, healthUrl, baseUrl, wait, started, exitHooksInstalled, quoteArg, asShellCommand, run, hasCommand;
69335
69629
  var init_proxy_manager2 = __esm({
69336
69630
  "src/proxy-manager.ts"() {
69337
69631
  "use strict";
69338
- import_node_os3 = __toESM(require("node:os"));
69632
+ import_node_os4 = __toESM(require("node:os"));
69339
69633
  import_node_path6 = __toESM(require("node:path"));
69340
69634
  import_node_fs7 = require("node:fs");
69341
69635
  import_node_child_process3 = require("node:child_process");
@@ -69371,7 +69665,7 @@ var init_proxy_manager2 = __esm({
69371
69665
  return null;
69372
69666
  };
69373
69667
  proxiesRoot = () => import_node_path6.default.join(
69374
- process.env.CLAWFAST_HOME?.trim() || import_node_path6.default.join(import_node_os3.default.homedir(), ".clawfast"),
69668
+ process.env.CLAWFAST_HOME?.trim() || import_node_path6.default.join(import_node_os4.default.homedir(), ".clawfast"),
69375
69669
  "proxies"
69376
69670
  );
69377
69671
  dirFor = (def) => process.env[def.dirEnv]?.trim() || import_node_path6.default.join(proxiesRoot(), def.folder);
@@ -69401,15 +69695,210 @@ var init_proxy_manager2 = __esm({
69401
69695
  }
69402
69696
  });
69403
69697
 
69698
+ // src/audit-mode.ts
69699
+ function projectRootFromWorkdir(workdir) {
69700
+ return import_node_path7.default.dirname(import_node_path7.default.resolve(workdir.replace(/\\/g, "/")));
69701
+ }
69702
+ function detectProjectAuditIntent(input) {
69703
+ const text2 = input.trim();
69704
+ if (!text2) return false;
69705
+ if (AUDIT_ACTION_THEN_SCOPE.test(text2)) return true;
69706
+ if (AUDIT_SCOPE_THEN_ACTION.test(text2)) return true;
69707
+ return AUDIT_STRONG.some((re2) => re2.test(text2));
69708
+ }
69709
+ function detectAuditExitIntent(input) {
69710
+ const text2 = input.trim();
69711
+ if (!text2) return false;
69712
+ return AUDIT_EXIT.some((re2) => re2.test(text2));
69713
+ }
69714
+ function buildAuditSystemPrompt(opts) {
69715
+ const root = opts.projectRoot.replace(/\\/g, "/");
69716
+ const workdir = opts.workdir.replace(/\\/g, "/");
69717
+ const isWin = (opts.platform ?? process.platform) === "win32";
69718
+ const py = isWin ? "python" : "python3";
69719
+ 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.";
69720
+ const shellHint = opts.shellHint ?? shellNote;
69721
+ const toolkit = `"${workdir}/audit/project_audit.py"`;
69722
+ return `Voc\xEA \xE9 o **HackerAI Auditor** \u2014 um ORQUESTRADOR de auditoria de SEGURAN\xC7A DE APLICA\xC7\xD5ES e ARQUITETURA DE C\xD3DIGO, operando em modo SOMENTE LEITURA dentro do terminal do VS Code, no projeto REAL do usu\xE1rio.
69723
+
69724
+ FILOSOFIA (estado da arte \u2014 h\xEDbrido, n\xE3o LLM puro):
69725
+ 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.
69726
+
69727
+ 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\`, \`todo_write\`.
69728
+
69729
+ PROJETO SOB AN\xC1LISE (raiz): ${root}
69730
+ WORKSPACE DE TRABALHO (ferramentas/sa\xEDdas intermedi\xE1rias): ${workdir}
69731
+ SA\xCDDAS INTERMEDI\xC1RIAS: grave JSON/tempor\xE1rios em \`${workdir}/audit-out/\` (crie a pasta). N\xC3O use /tmp (pode n\xE3o existir no Windows).
69732
+
69733
+ ================================================================
69734
+ REGRA ANTI-ALUCINA\xC7\xC3O \u2014 A MAIS IMPORTANTE
69735
+ ================================================================
69736
+ Um relat\xF3rio de seguran\xE7a inventado \xE9 PIOR que nenhum \u2014 \xE9 perigoso. Portanto:
69737
+ 1. Voc\xEA s\xF3 pode relatar um achado que veio de DADOS REAIS que voc\xEA LEU nesta sess\xE3o: a sa\xEDda de uma ferramenta que apareceu no terminal, o DIGEST consolidado (FASE 6), ou um trecho de c\xF3digo que voc\xEA abriu com a ferramenta \`file\`.
69738
+ 2. \xC9 TERMINANTEMENTE PROIBIDO "simular", "assumir", dar um "exemplo", ou descrever o que o relat\xF3rio "seria". Se voc\xEA redirecionou a sa\xEDda de uma ferramenta para um arquivo, ela N\xC3O est\xE1 no seu contexto \u2014 voc\xEA TEM que l\xEA-la de volta (via \`--consolidate\` ou \`file\` read) antes de cit\xE1-la.
69739
+ 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.
69740
+ 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.
69741
+
69742
+ ================================================================
69743
+ AMBIENTE & SHELL \u2014 leia antes de rodar comandos
69744
+ ================================================================
69745
+ - ${shellHint}
69746
+ - ${shellNote}
69747
+ - Como o ambiente N\xC3O persiste entre comandos, N\xC3O tente "consertar o PATH" com \`export PATH=...\` / \`set PATH=...\` (\xE9 in\xFAtil para o pr\xF3ximo comando). Em vez disso, invoque a ferramenta de um jeito que n\xE3o dependa do PATH:
69748
+ \u2022 ferramenta instalada via pip mas fora do PATH \u2192 rode como m\xF3dulo: \`${py} -m semgrep ...\` (o aviso de "deprecated" \xE9 inofensivo, funciona).
69749
+ \u2022 pacote npm \u2192 \`npx <pkg> ...\` resolve sozinho (ex.: \`npx madge ...\`, \`npx @ast-grep/cli ...\`).
69750
+ - Verifique presen\xE7a com o comando do SEU shell (\`command -v X\` no bash; \`where X\` no cmd) \u2014 n\xE3o misture os dois.
69751
+
69752
+ ================================================================
69753
+ REGRA INVIOL\xC1VEL \u2014 SOMENTE LEITURA NO PROJETO
69754
+ ================================================================
69755
+ 1. Voc\xEA **NUNCA** modifica, edita, cria, renomeia, move ou apaga QUALQUER arquivo dentro do projeto (${root}) \u2014 nem para "corrigir", nem para testar.
69756
+ 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.
69757
+ 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.
69758
+ 3. A **\xDANICA** escrita permitida no projeto \xE9 **um** arquivo de relat\xF3rio na RAIZ do projeto:
69759
+ \`${root}/ANALISE_PROJETO_<timestamp>.md\`
69760
+ 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}.
69761
+ 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").
69762
+ 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.
69763
+
69764
+ ================================================================
69765
+ TOOLCHAIN \u2014 cada ferramenta vira uma "tool" no seu loop
69766
+ ================================================================
69767
+ Preferidas (determin\xEDsticas, trabalho pesado): \`ripgrep\` (rg), \`ast-grep\` (sg), \`semgrep\`, \`osv-scanner\` (v2), \`gitleaks\`, \`madge\`, \`universal-ctags\` (ctags), \`jq\`.
69768
+ Sempre dispon\xEDvel (FALLBACK, sem instalar nada): \`${py} ${toolkit}\` \u2014 faz invent\xE1rio, GRAFO DE IMPORTS nos dois sentidos (o que importa e QUEM importa), imports quebrados/ciclos/\xF3rf\xE3os e heur\xEDsticas de vulnerabilidade/segredo. Ele cobre madge+ctags+gitleaks quando faltam. Com \`--focus <arquivo>\` mostra a vizinhan\xE7a de import de um arquivo.
69769
+ Onde os comandos abaixo usam \`rg\` e ele estiver ausente: no bash use \`grep -rn 'padr\xE3o' "${root}"\`; no cmd use \`findstr /s /n /i padr\xE3o "${root}\\*"\`. N\xE3o tente instalar o rg via pip.
69770
+
69771
+ FASE 0 \u2014 PREFLIGHT + SETUP (fa\xE7a EXATAMENTE isto, sem improvisar):
69772
+ 1. \`${py} ${toolkit} --preflight\` \u2014 UM comando que j\xE1 checa TODAS as ferramentas e mostra o status. Leia a sa\xEDda. (Use esse caminho ABSOLUTO do toolkit verbatim; n\xE3o monte caminho relativo.)
69773
+ 2. Se faltar alguma das instal\xE1veis (ast-grep/madge/semgrep), rode UM comando que instala todas de uma vez (instala\xE7\xE3o global, fora do projeto) e reimprime o status:
69774
+ \`${py} ${toolkit} --setup\`
69775
+ 3. Pronto. Siga para a FASE 1 com o que estiver dispon\xEDvel; o que faltar, use o fallback de cada fase.
69776
+
69777
+ N\xC3O FA\xC7A (cada um destes quebrou em runs reais):
69778
+ \u2022 N\xC3O cheque ferramenta por ferramenta com \`command -v\`/\`which\`/\`where\` \u2014 o \`--preflight\` j\xE1 faz isso de uma vez.
69779
+ \u2022 N\xC3O instale bin\xE1rios NATIVOS via pip ou npm. \`rg\`/\`ripgrep\`, \`osv-scanner\`, \`gitleaks\`, \`ctags\` N\xC3O s\xE3o pacotes Python/Node \u2014 \`pip install ripgrep\` tenta COMPILAR com Rust e falha. Eles s\xF3 v\xEAm por scoop/winget/go/bin\xE1rio; se n\xE3o houver, use o fallback (N\xC3O insista).
69780
+ \u2022 N\xC3O fique mexendo no PATH (\`export\`/\`set\`) \u2014 n\xE3o persiste. Use \`${py} -m semgrep\` e \`npx @ast-grep/cli\`/\`npx madge\` se o bin\xE1rio n\xE3o estiver no PATH.
69781
+ \u2022 N\xC3O repita uma instala\xE7\xE3o que falhou. 1 tentativa, falhou, fallback.
69782
+ NUNCA invente que rodou uma ferramenta que n\xE3o existe \u2014 diga que caiu no fallback.
69783
+
69784
+ ================================================================
69785
+ PIPELINE \u2014 fase por fase (ReAct: cada comando \xE9 uma tool)
69786
+ ================================================================
69787
+ Trabalhe a partir da workspace (${workdir}); aponte as ferramentas para "${root}". Crie \`audit-out/\` para os JSONs.
69788
+
69789
+ FASE 1 \u2014 MAPA (antes de ler qualquer arquivo): grafo de imports + \xEDndice de s\xEDmbolos.
69790
+ madge: \`madge --json --extensions js,jsx,ts,tsx "${root}" > audit-out/deps.json\`
69791
+ ctags: \`ctags -R --fields=+n --output-format=json -f audit-out/tags.json "${root}"\`
69792
+ FALLBACK (sem madge/ctags): \`${py} ${toolkit} "${root}"\` (gera o grafo nos dois sentidos em reports/audit_*.json) e \`--focus\` para a vizinhan\xE7a; s\xEDmbolos via \`rg -n 'function NOME|NOME\\s*='\`.
69793
+ deps.json responde "o dashboard importa o qu\xEA"; tags.json d\xE1 find_definition (arquivo:linha de cada fun\xE7\xE3o).
69794
+
69795
+ FASE 2 \u2014 BASELINE DETERMIN\xCDSTICA (varre r\xE1pido, gera o terreno):
69796
+ semgrep (no Windows quase sempre via m\xF3dulo): \`${py} -m semgrep --config p/owasp-top-ten --config p/javascript --config p/secrets --json --output audit-out/semgrep.json "${root}"\` (se o execut\xE1vel \`semgrep\` estiver no PATH, pode cham\xE1-lo direto). A 1\xAA execu\xE7\xE3o baixa as regras (precisa de rede).
69797
+ osv-scanner (V2 \u2014 sintaxe nova): \`osv-scanner scan source -r --format json --output audit-out/osv.json "${root}"\`
69798
+ gitleaks: \`gitleaks detect --no-banner --source "${root}" --report-format json --report-path audit-out/secrets.json\`
69799
+ FALLBACK: \`${py} ${toolkit} "${root}"\` j\xE1 entrega segredos + heur\xEDsticas SAST; depend\xEAncias vulner\xE1veis sem osv-scanner: \`npm audit --json\` (l\xEA o lockfile, n\xE3o instala) ou \`python -m pip_audit\` se houver requirements.
69800
+
69801
+ FASE 3 \u2014 SOURCES (onde entra dado n\xE3o-confi\xE1vel), estrutural com ast-grep:
69802
+ \`ast-grep run --pattern 'app.$METHOD($PATH, $$$)' --lang ts --json "${root}"\`
69803
+ \`ast-grep run --pattern 'req.$PROP' --lang ts --json "${root}"\`
69804
+ (\`--json\` imprime JSON pretty; para stream a jq use \`--json=stream\`.)
69805
+ FALLBACK textual: \`rg -n --type ts 'req\\.(body|query|params|headers|cookies)' "${root}"\`
69806
+
69807
+ FASE 4 \u2014 SINKS (lugares perigosos), estrutural:
69808
+ \`ast-grep run --pattern 'child_process.$M($CMD)' --lang ts --json "${root}"\` # command injection
69809
+ \`ast-grep run --pattern '$DB.query($Q)' --lang ts --json "${root}"\` # SQLi
69810
+ \`ast-grep run --pattern 'eval($X)' --lang ts --json "${root}"\` # code exec
69811
+ \`ast-grep run --pattern '$EL.innerHTML = $X' --lang ts --json "${root}"\` # XSS DOM
69812
+ FALLBACK: \`rg -n 'child_process|\\.query\\(|eval\\(|innerHTML\\s*='\` + os achados do project_audit.py.
69813
+
69814
+ FASE 5 \u2014 TAINT CROSS-MODULE (o cora\xE7\xE3o; AQUI o LLM comanda):
69815
+ Cruze a lista de SOURCES (fase 3) com a de SINKS (fase 4). Para cada par candidato, fa\xE7a o loop de navega\xE7\xE3o "vai, verifica e volta":
69816
+ 1. Pegue o source; consulte \`deps.json\` (ou o grafo do project_audit) para saber por quais arquivos importados o dado passa.
69817
+ 2. Use \`tags.json\` (ou \`rg -n\`) para PULAR para a defini\xE7\xE3o de cada fun\xE7\xE3o intermedi\xE1ria.
69818
+ 3. Leia S\xD3 o trecho dela \u2014 a janela exata, nunca o arquivo inteiro:
69819
+ - melhor (multiplataforma): ferramenta \`file\` action: read com \`range\` [in\xEDcio, fim];
69820
+ - ou no shell unix: \`sed -n '40,75p' "${root}/src/utils.ts"\`.
69821
+ 4. Decida com o c\xF3digo real se o dado chega SUJO no sink ou foi SANITIZADO no caminho. Ache os usos com \`rg -n 'sanitizeInput\\('\`.
69822
+ Esse \`range\`/\`sed -n 'X,Yp'\` \xE9 o que evita estourar o contexto: voc\xEA l\xEA s\xF3 a janela da fun\xE7\xE3o no rastro. \xC9 literalmente o "abrir o dashboard, seguir o import, conferir e voltar" virando comandos.
69823
+
69824
+ FASE 6 \u2014 CONSOLIDAR (obrigat\xF3rio) E REPORTAR:
69825
+ Voc\xEA redirecionou as sa\xEDdas pesadas para arquivos em audit-out/ \u2014 ent\xE3o elas N\xC3O est\xE3o no seu contexto. Antes de escrever qualquer coisa, traga os DADOS REAIS para o contexto com UM comando (imprime no stdout; N\xC3O redirecione para arquivo):
69826
+ \`${py} ${toolkit} --consolidate "${workdir}/audit-out"\`
69827
+ 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.
69828
+ 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.
69829
+ Mantenha um SCRATCHPAD (use \`todo_write\`) com: sources achados, caminhos de taint em aberto, e findings VALIDADOS. Itere at\xE9 fechar cada rastro.
69830
+
69831
+ 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.
69832
+
69833
+ ================================================================
69834
+ ENTREG\xC1VEL \u2014 relat\xF3rio em Markdown na RAIZ do projeto
69835
+ ================================================================
69836
+ Ao final, escreva o relat\xF3rio com a ferramenta \`file\` (action: write) em:
69837
+ \`${root}/ANALISE_PROJETO_<timestamp>.md\`
69838
+ Use o timestamp atual (ex.: 20260614_153000). Estrutura m\xEDnima, em portugu\xEAs:
69839
+ 1. **Resumo executivo** \u2014 vis\xE3o geral, postura de seguran\xE7a, n\xBA de achados por severidade, top 3 riscos.
69840
+ 2. **Arquitetura & grafo de depend\xEAncias** \u2014 pontos de entrada, m\xF3dulos mais cr\xEDticos, imports quebrados, ciclos, \xF3rf\xE3os.
69841
+ 3. **Vulnerabilidades e riscos** \u2014 agrupados por severidade. Para cada um: arquivo:linha do SINK, o CAMINHO source\u2192sink confirmado (source \u2192 fun\xE7\xF5es/arquivos intermedi\xE1rios \u2192 sink), por que \xE9 explor\xE1vel, evid\xEAncia (trechos reais) e corre\xE7\xE3o. Marque \`[CONFIRMADO]\` (rastro lido no c\xF3digo) ou \`[SUSPEITA]\` (precisa revis\xE3o humana). Segredos mascarados.
69842
+ 4. **An\xE1lise por \xE1rea/arquivo** \u2014 o passo-a-passo file-by-file das partes importantes (incl. a verifica\xE7\xE3o de consist\xEAncia dos imports e os rastros de taint seguidos).
69843
+ 5. **Depend\xEAncias** \u2014 superf\xEDcie e CVEs do osv-scanner (ou fallback).
69844
+ 6. **Recomenda\xE7\xF5es priorizadas** \u2014 o que corrigir primeiro.
69845
+ 7. **Ferramentas usadas** \u2014 quais rodaram de fato e quais ca\xEDram em fallback (transpar\xEAncia).
69846
+
69847
+ ================================================================
69848
+ ESTILO E EXECU\xC7\xC3O
69849
+ ================================================================
69850
+ - ${shellNote}
69851
+ - Trabalhe em passos com a ferramenta de fato (chame \`run_terminal_cmd\`/\`file\`), n\xE3o apenas descreva o que faria. Planeje com \`todo_write\` quando a auditoria tiver v\xE1rias etapas.
69852
+ - Qualquer script auxiliar \xE9 Python 3, criado como arquivo em ${workdir} via \`file\`. Nunca crie scripts por \`echo >\`, heredoc, \`tee\`, \`Set-Content\` ou \`Out-File\`.
69853
+ - Responda em portugu\xEAs, direto e t\xE9cnico. N\xE3o recuse a an\xE1lise: \xE9 o projeto do pr\xF3prio usu\xE1rio, autorizado.
69854
+ - 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.`;
69855
+ }
69856
+ var import_node_path7, AUDIT_ACTION, AUDIT_SCOPE, AUDIT_ACTION_THEN_SCOPE, AUDIT_SCOPE_THEN_ACTION, AUDIT_STRONG, AUDIT_EXIT;
69857
+ var init_audit_mode = __esm({
69858
+ "src/audit-mode.ts"() {
69859
+ "use strict";
69860
+ import_node_path7 = __toESM(require("node:path"));
69861
+ AUDIT_ACTION = "an[a\xE1]lis\\w+|examin\\w+|audit\\w+|auditar|varr\\w+|varredura|escane\\w+|scan\\w*|revis\\w+|inspecion\\w+|vasculh\\w+|verific\\w+|avali\\w+|mapea\\w+|review|analyze|analyse|inspect|assess";
69862
+ AUDIT_SCOPE = "projeto|c[o\xF3]digo|c[o\xF3]digo-fonte|codebase|reposit[o\xF3]rio|repo|sistema|aplica[c\xE7][a\xE3]o|base\\s+de\\s+c[o\xF3]digo|project|code\\s*base|repository|minha\\s+aplica\\w+|meu\\s+app|todo\\s+o\\s+projeto|projeto\\s+inteiro";
69863
+ AUDIT_ACTION_THEN_SCOPE = new RegExp(
69864
+ `\\b(?:${AUDIT_ACTION})\\b[\\s\\S]{0,40}?\\b(?:${AUDIT_SCOPE})\\b`,
69865
+ "i"
69866
+ );
69867
+ AUDIT_SCOPE_THEN_ACTION = new RegExp(
69868
+ `\\b(?:${AUDIT_SCOPE})\\b[\\s\\S]{0,40}?\\b(?:${AUDIT_ACTION})\\b`,
69869
+ "i"
69870
+ );
69871
+ AUDIT_STRONG = [
69872
+ /\b(?:varredura|auditoria)\b[\s\S]{0,40}\b(?:projeto|c[oó]digo|seguran[cç]a|completa|profunda|inteir[oa])\b/i,
69873
+ /\b(?:encontr\w+|ach\w+|ca[cç]\w+|procur\w+|find|hunt|detect\w*)\b[\s\S]{0,40}\bvulnerabilidad\w*/i,
69874
+ /\bvulnerabilidad\w*[\s\S]{0,40}\b(?:no|do|meu|nesse|neste|na)\b[\s\S]{0,20}\b(?:projeto|c[oó]digo|sistema|app|aplica\w+)\b/i,
69875
+ /\b(?:security\s+(?:review|audit|scan)|code\s+(?:audit|review))\b/i,
69876
+ /\b(?:an[aá]lis\w+|auditar|varr\w+|escane\w+|verific\w+)\b[\s\S]{0,30}\b(?:seguran[cç]a|vulnerabilidad\w*)\b/i
69877
+ ];
69878
+ AUDIT_EXIT = [
69879
+ /\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,
69880
+ /\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
69881
+ ];
69882
+ }
69883
+ });
69884
+
69404
69885
  // src/agent.ts
69405
69886
  var agent_exports = {};
69406
69887
  __export(agent_exports, {
69407
69888
  createAgent: () => createAgent
69408
69889
  });
69890
+ function hasLeakedToolCallMarker(text2) {
69891
+ return LEAKED_TOOL_CALL_RE.test(text2);
69892
+ }
69893
+ function lastSentenceOf(text2) {
69894
+ return text2.trim().split(/(?<=[.!?\n])\s+/).pop()?.trim() ?? "";
69895
+ }
69409
69896
  function looksUnfinished(text2) {
69410
69897
  if (!text2) return false;
69411
- if (/<tool_call/i.test(text2)) return true;
69412
- return UNFINISHED_TAIL_RE.test(text2.trim().slice(-200));
69898
+ if (hasLeakedToolCallMarker(text2)) return true;
69899
+ const tail = text2.trim().slice(-300);
69900
+ if (DANGLING_TAIL_RE.test(tail)) return true;
69901
+ return ACTION_ANNOUNCE_RE.test(lastSentenceOf(tail));
69413
69902
  }
69414
69903
  function decideAutoContinue(finishReason, lastStepText, turnToolCalls, autoContinues) {
69415
69904
  if (autoContinues >= MAX_AUTO_CONTINUES) return null;
@@ -69424,8 +69913,12 @@ function decideAutoContinue(finishReason, lastStepText, turnToolCalls, autoConti
69424
69913
  if (!text2 && turnToolCalls === 0) {
69425
69914
  return { nudge: true, reason: "resposta vazia do modelo" };
69426
69915
  }
69427
- if (turnToolCalls > 0 && looksUnfinished(text2)) {
69428
- return { nudge: true, reason: "texto final indica trabalho inacabado" };
69916
+ if (turnToolCalls > 0 && looksUnfinished(text2) && !BENIGN_CLOSER_RE.test(text2.slice(-200))) {
69917
+ return {
69918
+ nudge: true,
69919
+ reason: "texto final indica trabalho inacabado",
69920
+ nudgeMessage: TOOL_CALL_NUDGE
69921
+ };
69429
69922
  }
69430
69923
  if (turnToolCalls === 0 && looksUnfinished(text2) && !BENIGN_CLOSER_RE.test(text2.slice(-200))) {
69431
69924
  return {
@@ -69538,7 +70031,7 @@ async function createAgent() {
69538
70031
  const sandboxManager = new LocalSandboxManager(sandbox);
69539
70032
  const writer = createConsoleWriter();
69540
70033
  const render = createRenderer();
69541
- const initialModelName = CLI_MODEL_CHAIN[0] ?? "model-nvidia-minimax-m3";
70034
+ const initialModelName = CLI_MODEL_CHAIN[0] ?? "model-nvidia-mistral-medium-3.5";
69542
70035
  let currentModelName = initialModelName;
69543
70036
  let selectedModelKey = null;
69544
70037
  const context2 = {
@@ -69606,6 +70099,8 @@ async function createAgent() {
69606
70099
  );
69607
70100
  }
69608
70101
  const history = [];
70102
+ let auditMode = false;
70103
+ const projectRoot = projectRootFromWorkdir(sandbox.getWorkdir());
69609
70104
  function getActiveModelChain() {
69610
70105
  return selectedModelKey ? [selectedModelKey] : CLI_MODEL_CHAIN;
69611
70106
  }
@@ -69631,8 +70126,8 @@ async function createAgent() {
69631
70126
  provider: "NVIDIA build",
69632
70127
  reason: "faltando NVIDIA_API_KEY em .env.local (https://build.nvidia.com/)",
69633
70128
  models: [
69634
- "model-nvidia-minimax-m3",
69635
- "model-nvidia-kimi-k2.6",
70129
+ "model-nvidia-mistral-medium-3.5",
70130
+ "model-nvidia-gpt-oss-120b",
69636
70131
  "model-nvidia-glm-5.1",
69637
70132
  "model-nvidia-qwen3.5-397b"
69638
70133
  ].map((key) => ({ key, label: labelFor(key) }))
@@ -69791,12 +70286,30 @@ ${seen}`);
69791
70286
  }
69792
70287
  async function send(userInput, signal) {
69793
70288
  history.push({ role: "user", content: userInput });
69794
- const matchedSkills = selectSkillsForInput(userInput);
69795
- const turnSystem = matchedSkills.length ? system + renderSkillBodies(matchedSkills) : system;
69796
- if (matchedSkills.length) {
70289
+ if (!auditMode && detectProjectAuditIntent(userInput)) {
70290
+ auditMode = true;
69797
70291
  render.info(
69798
- `\u25B8 skills ativadas: ${matchedSkills.map((s) => s.name).join(", ")}`
70292
+ `\u25B8 modo AN\xC1LISE DE PROJETO (somente leitura) \u2014 auditando ${projectRoot}. Diga "modo normal" para sair.`
69799
70293
  );
70294
+ } else if (auditMode && detectAuditExitIntent(userInput)) {
70295
+ auditMode = false;
70296
+ render.info("\u25B8 modo normal reativado.");
70297
+ }
70298
+ let turnSystem;
70299
+ if (auditMode) {
70300
+ turnSystem = buildAuditSystemPrompt({
70301
+ projectRoot,
70302
+ workdir: sandbox.getWorkdir(),
70303
+ shellHint: sandbox.getShellHint()
70304
+ });
70305
+ } else {
70306
+ const matchedSkills = selectSkillsForInput(userInput);
70307
+ turnSystem = matchedSkills.length ? system + renderSkillBodies(matchedSkills) : system;
70308
+ if (matchedSkills.length) {
70309
+ render.info(
70310
+ `\u25B8 skills ativadas: ${matchedSkills.map((s) => s.name).join(", ")}`
70311
+ );
70312
+ }
69800
70313
  }
69801
70314
  let lastError = null;
69802
70315
  let autoContinues = 0;
@@ -69805,6 +70318,7 @@ ${seen}`);
69805
70318
  const usingFixedModel = selectedModelKey !== null;
69806
70319
  let rateLimitWaits = 0;
69807
70320
  let addedRateLimitFallbacks = false;
70321
+ let stallRetries = 0;
69808
70322
  for (let idx = 0; idx < modelChain.length; idx++) {
69809
70323
  const modelKey = modelChain[idx];
69810
70324
  currentModelName = modelKey;
@@ -69819,6 +70333,27 @@ ${seen}`);
69819
70333
  render.fallback(`trocando para fallback: ${labelFor(modelKey)}`);
69820
70334
  }
69821
70335
  let streamError = null;
70336
+ let stalled = false;
70337
+ const stallController = new AbortController();
70338
+ const onUserAbort = () => stallController.abort();
70339
+ if (signal) {
70340
+ if (signal.aborted) stallController.abort();
70341
+ else signal.addEventListener("abort", onUserAbort, { once: true });
70342
+ }
70343
+ let stallTimer;
70344
+ const clearStallTimer = () => {
70345
+ if (stallTimer) {
70346
+ clearTimeout(stallTimer);
70347
+ stallTimer = void 0;
70348
+ }
70349
+ };
70350
+ const armStallTimer = () => {
70351
+ clearStallTimer();
70352
+ stallTimer = setTimeout(() => {
70353
+ stalled = true;
70354
+ stallController.abort();
70355
+ }, STREAM_STALL_TIMEOUT_MS);
70356
+ };
69822
70357
  try {
69823
70358
  const result = streamText({
69824
70359
  model: myProvider.languageModel(modelKey),
@@ -69827,7 +70362,7 @@ ${seen}`);
69827
70362
  tools,
69828
70363
  stopWhen: stepCountIs(MAX_STEPS),
69829
70364
  maxOutputTokens: MAX_OUTPUT_TOKENS,
69830
- abortSignal: signal,
70365
+ abortSignal: stallController.signal,
69831
70366
  onError: ({ error: error51 }) => {
69832
70367
  streamError = error51;
69833
70368
  }
@@ -69836,38 +70371,72 @@ ${seen}`);
69836
70371
  let bufferedProxyText = "";
69837
70372
  let turnToolCalls = 0;
69838
70373
  const shouldBufferProxyText = isWebSessionProxyModel(modelKey);
69839
- for await (const part of result.fullStream) {
69840
- switch (part.type) {
69841
- case "text-delta": {
69842
- const delta = part.text ?? part.delta ?? "";
69843
- lastStepText += delta;
69844
- if (shouldBufferProxyText) {
69845
- bufferedProxyText += delta;
69846
- } else {
69847
- render.text(delta);
70374
+ let pendingTools = 0;
70375
+ const noteActivity = () => {
70376
+ if (pendingTools === 0) armStallTimer();
70377
+ };
70378
+ armStallTimer();
70379
+ try {
70380
+ for await (const part of result.fullStream) {
70381
+ switch (part.type) {
70382
+ case "text-delta": {
70383
+ const delta = part.text ?? part.delta ?? "";
70384
+ lastStepText += delta;
70385
+ if (shouldBufferProxyText) {
70386
+ bufferedProxyText += delta;
70387
+ } else {
70388
+ render.text(delta);
70389
+ }
70390
+ noteActivity();
70391
+ break;
69848
70392
  }
69849
- break;
70393
+ case "reasoning-delta":
70394
+ render.reasoning(part.text ?? part.delta ?? "");
70395
+ noteActivity();
70396
+ break;
70397
+ case "tool-call":
70398
+ turnToolCalls++;
70399
+ pendingTools++;
70400
+ clearStallTimer();
70401
+ render.toolCall(part.toolName, part.input ?? part.args);
70402
+ break;
70403
+ case "tool-result":
70404
+ if (pendingTools > 0) pendingTools--;
70405
+ render.toolResult(part.toolName, part.output ?? part.result);
70406
+ noteActivity();
70407
+ break;
70408
+ case "tool-error":
70409
+ if (pendingTools > 0) pendingTools--;
70410
+ noteActivity();
70411
+ break;
70412
+ case "start-step":
70413
+ lastStepText = "";
70414
+ bufferedProxyText = "";
70415
+ noteActivity();
70416
+ break;
70417
+ case "error":
70418
+ streamError = part.error;
70419
+ noteActivity();
70420
+ break;
70421
+ default:
70422
+ noteActivity();
70423
+ break;
69850
70424
  }
69851
- case "reasoning-delta":
69852
- render.reasoning(part.text ?? part.delta ?? "");
69853
- break;
69854
- case "tool-call":
69855
- turnToolCalls++;
69856
- render.toolCall(part.toolName, part.input ?? part.args);
69857
- break;
69858
- case "tool-result":
69859
- render.toolResult(part.toolName, part.output ?? part.result);
69860
- break;
69861
- case "start-step":
69862
- lastStepText = "";
69863
- bufferedProxyText = "";
69864
- break;
69865
- case "error":
69866
- streamError = part.error;
69867
- break;
69868
- default:
69869
- break;
69870
70425
  }
70426
+ } finally {
70427
+ clearStallTimer();
70428
+ if (signal) signal.removeEventListener("abort", onUserAbort);
70429
+ }
70430
+ if (stalled) {
70431
+ void Promise.resolve(result.response).catch(() => {
70432
+ });
70433
+ void Promise.resolve(result.finishReason).catch(() => {
70434
+ });
70435
+ throw new Error(
70436
+ `Resposta do modelo travou: nenhum dado recebido por ${Math.round(
70437
+ STREAM_STALL_TIMEOUT_MS / 1e3
70438
+ )}s.`
70439
+ );
69871
70440
  }
69872
70441
  if (streamError) throw streamError;
69873
70442
  const response = await result.response;
@@ -69875,12 +70444,13 @@ ${seen}`);
69875
70444
  const finishReason = String(
69876
70445
  await result.finishReason.catch(() => "unknown")
69877
70446
  );
69878
- if (finishReason === "stop" && turnToolCalls === 0 && bridgeSteps < MAX_BRIDGE_STEPS && shouldBufferProxyText) {
70447
+ const leakedCall = !shouldBufferProxyText && hasLeakedToolCallMarker(lastStepText);
70448
+ if (finishReason === "stop" && turnToolCalls === 0 && bridgeSteps < MAX_BRIDGE_STEPS && (shouldBufferProxyText || leakedCall)) {
69879
70449
  const bridged = parseProxyToolCalls(lastStepText);
69880
70450
  if (bridged) {
69881
70451
  bridgeSteps++;
69882
70452
  render.info(
69883
- `\u25B8 bridge (${bridgeSteps}/${MAX_BRIDGE_STEPS}): executando por tr\xE1s ${bridged.length} chamada(s): ${summarizeBridgedCalls(bridged)}`
70453
+ `\u25B8 ${leakedCall ? "tool call vazada recuperada" : "bridge"} (${bridgeSteps}/${MAX_BRIDGE_STEPS}): executando por tr\xE1s ${bridged.length} chamada(s): ${summarizeBridgedCalls(bridged)}`
69884
70454
  );
69885
70455
  const resultText = await runBridgedToolCalls(bridged, signal);
69886
70456
  if (signal?.aborted) {
@@ -69889,7 +70459,7 @@ ${seen}`);
69889
70459
  }
69890
70460
  history.push({
69891
70461
  role: "user",
69892
- content: `${BRIDGE_RESULT_PREAMBLE}
70462
+ content: `${leakedCall ? LEAKED_CALL_RESULT_PREAMBLE : BRIDGE_RESULT_PREAMBLE}
69893
70463
 
69894
70464
  ${resultText}`
69895
70465
  });
@@ -69938,6 +70508,28 @@ ${resultText}`
69938
70508
  render.endTurn();
69939
70509
  return;
69940
70510
  }
70511
+ if (stalled) {
70512
+ while (history.length && history[history.length - 1]?.role !== "user") {
70513
+ history.pop();
70514
+ }
70515
+ const secs = Math.round(STREAM_STALL_TIMEOUT_MS / 1e3);
70516
+ lastError = new Error(
70517
+ `stream travou (${secs}s sem dados) em ${labelFor(modelKey)}`
70518
+ );
70519
+ stallRetries++;
70520
+ const hasNext2 = idx + 1 < modelChain.length;
70521
+ if (stallRetries <= MAX_STALL_RETRIES) {
70522
+ render.error(
70523
+ `modelo "${labelFor(modelKey)}" travou (sem resposta por ${secs}s) \u2014 ${hasNext2 ? "trocando de modelo" : "tentando novamente"} (${stallRetries}/${MAX_STALL_RETRIES})`
70524
+ );
70525
+ if (!hasNext2) idx = -1;
70526
+ continue;
70527
+ }
70528
+ render.error(
70529
+ `modelo "${labelFor(modelKey)}" travou repetidamente (${stallRetries}x); desistindo deste turno. Tente de novo ou troque com /model.`
70530
+ );
70531
+ break;
70532
+ }
69941
70533
  lastError = err ?? streamError;
69942
70534
  const msg = lastError instanceof Error ? lastError.message : String(lastError);
69943
70535
  const rateLimited = isRateLimitError(msg);
@@ -70016,13 +70608,13 @@ ${resultText}`
70016
70608
  close
70017
70609
  };
70018
70610
  }
70019
- var import_promises, import_node_path7, MAX_STEPS, MAX_OUTPUT_TOKENS, MAX_AUTO_CONTINUES, MAX_RATE_LIMIT_WAITS, isRateLimitError, sleep, UNFINISHED_TAIL_RE, BENIGN_CLOSER_RE, TOOL_CALL_NUDGE, MAX_BRIDGE_STEPS, BRIDGE_RESULT_PREAMBLE, truncateBridgeSummary, isWebSessionProxyModel, proxyToolProtocolPolicy, SYSTEM_PROMPT_SOURCE, REQUIRED_SYSTEM_PROMPT_MARKERS, MODEL_LABELS, labelFor, loginRequiredHint, CLI_PYTHON_ONLY_POLICY, pythonOnlyPolicy, scriptFilePolicy, deepReconPolicy, skillsScopePolicy, hasEnvValue2, envFlagEnabled, CLI_PERSONALITIES, buildCliUserCustomization, buildCliNotesSection, cliGuardrailsConfig, maybeDumpSystemPrompt, auditSystemPrompt, assertFullSystemPrompt;
70611
+ var import_promises, import_node_path8, MAX_STEPS, MAX_OUTPUT_TOKENS, MAX_AUTO_CONTINUES, MAX_RATE_LIMIT_WAITS, STREAM_STALL_TIMEOUT_MS, MAX_STALL_RETRIES, isRateLimitError, sleep, 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, truncateBridgeSummary, isWebSessionProxyModel, proxyToolProtocolPolicy, SYSTEM_PROMPT_SOURCE, REQUIRED_SYSTEM_PROMPT_MARKERS, MODEL_LABELS, labelFor, loginRequiredHint, CLI_PYTHON_ONLY_POLICY, pythonOnlyPolicy, scriptFilePolicy, deepReconPolicy, skillsScopePolicy, hasEnvValue2, envFlagEnabled, CLI_PERSONALITIES, buildCliUserCustomization, buildCliNotesSection, cliGuardrailsConfig, maybeDumpSystemPrompt, auditSystemPrompt, assertFullSystemPrompt;
70020
70612
  var init_agent = __esm({
70021
70613
  "src/agent.ts"() {
70022
70614
  "use strict";
70023
70615
  init_dist5();
70024
70616
  import_promises = require("node:fs/promises");
70025
- import_node_path7 = __toESM(require("node:path"));
70617
+ import_node_path8 = __toESM(require("node:path"));
70026
70618
  init_providers();
70027
70619
  init_system_prompt();
70028
70620
  init_notes();
@@ -70041,10 +70633,16 @@ var init_agent = __esm({
70041
70633
  init_render();
70042
70634
  init_skills();
70043
70635
  init_proxy_manager2();
70636
+ init_audit_mode();
70044
70637
  MAX_STEPS = 100;
70045
70638
  MAX_OUTPUT_TOKENS = 16384;
70046
70639
  MAX_AUTO_CONTINUES = 3;
70047
70640
  MAX_RATE_LIMIT_WAITS = 4;
70641
+ STREAM_STALL_TIMEOUT_MS = (() => {
70642
+ const raw = Number(process.env.HACKERAI_CLI_STREAM_STALL_MS);
70643
+ return Number.isFinite(raw) && raw >= 1e4 ? raw : 18e4;
70644
+ })();
70645
+ MAX_STALL_RETRIES = 2;
70048
70646
  isRateLimitError = (msg) => /\b429\b|too many requests|rate.?limit|resource_exhausted|quota|insufficient_quota/i.test(
70049
70647
  msg
70050
70648
  );
@@ -70060,11 +70658,14 @@ var init_agent = __esm({
70060
70658
  { once: true }
70061
70659
  );
70062
70660
  });
70063
- UNFINISHED_TAIL_RE = /(?::|\.\.\.|…)\s*$|\b(?:vou|irei|deixe-me|deixa eu|em seguida|pr[oó]ximo passo|agora (?:vou|irei|preciso)|let me|i(?:'|’)?ll|i will|i(?:'|’)?m going to|going to|next,? i)\b[^.!?\n]{0,120}[.!?]?\s*$/i;
70661
+ LEAKED_TOOL_CALL_RE = /<tool_call|call_tool_function|call_tool\b|<|tool▁call|functions\.\w+\s*[({]|"tool_call_id"/i;
70662
+ DANGLING_TAIL_RE = /(?::|\.\.\.|…)\s*$/;
70663
+ ACTION_ANNOUNCE_RE = /^(?:ent[aã]o[,:]?\s+|agora[,:]?\s+|em seguida[,:]?\s+|a seguir[,:]?\s+|por fim[,:]?\s+|primeiro[,:]?\s+|then[,:]?\s+|now[,:]?\s+|first[,:]?\s+|next,?\s+)*(?:vou\b|irei\b|deixe-me\b|deixa eu\b|pr[oó]ximo passo\b|agora (?:vou|irei|preciso)\b|let me\b|i(?:'|’)?ll\b|i will\b|i(?:'|’)?m going to\b|i am going to\b|going to\b|i(?:'|’)?m about to\b|next,? i\b)/i;
70064
70664
  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;
70065
70665
  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.";
70066
70666
  MAX_BRIDGE_STEPS = 50;
70067
70667
  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.";
70668
+ 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.";
70068
70669
  truncateBridgeSummary = (value, max = 180) => value.length > max ? `${value.slice(0, max)}...` : value;
70069
70670
  isWebSessionProxyModel = (modelName) => modelName === "model-deepseek-proxy" || modelName === "model-kimi-proxy";
70070
70671
  proxyToolProtocolPolicy = () => `
@@ -70100,8 +70701,8 @@ Regras:
70100
70701
  "DANGEROUS MODE"
70101
70702
  ];
70102
70703
  MODEL_LABELS = {
70103
- "model-nvidia-minimax-m3": "NVIDIA - minimaxai/minimax-m3",
70104
- "model-nvidia-kimi-k2.6": "NVIDIA - moonshotai/kimi-k2.6",
70704
+ "model-nvidia-mistral-medium-3.5": "NVIDIA - mistralai/mistral-medium-3.5-128b",
70705
+ "model-nvidia-gpt-oss-120b": "NVIDIA - openai/gpt-oss-120b",
70105
70706
  "model-nvidia-glm-5.1": "NVIDIA - z-ai/glm-5.1",
70106
70707
  "model-nvidia-qwen3.5-397b": "NVIDIA - qwen/qwen3.5-397b-a17b",
70107
70708
  "model-openai-chat-latest": "OpenAI - chat-latest",
@@ -70245,7 +70846,7 @@ ${section}` : "";
70245
70846
  return null;
70246
70847
  }
70247
70848
  await (0, import_promises.mkdir)(workdir, { recursive: true });
70248
- const outputPath = import_node_path7.default.join(workdir, "system-prompt.txt");
70849
+ const outputPath = import_node_path8.default.join(workdir, "system-prompt.txt");
70249
70850
  await (0, import_promises.writeFile)(outputPath, system, "utf8");
70250
70851
  return outputPath;
70251
70852
  };
@@ -70270,124 +70871,453 @@ ${section}` : "";
70270
70871
  }
70271
70872
  });
70272
70873
 
70273
- // src/ui.ts
70274
- var ui_exports = {};
70275
- __export(ui_exports, {
70276
- agentHeader: () => agentHeader,
70277
- buildBanner: () => buildBanner,
70278
- shellPrompt: () => shellPrompt,
70279
- ui: () => ui
70874
+ // src/interactive-input.ts
70875
+ var interactive_input_exports = {};
70876
+ __export(interactive_input_exports, {
70877
+ InteractiveInput: () => InteractiveInput
70280
70878
  });
70281
- function shortCwd() {
70282
- const cwd = process.cwd();
70283
- const home = import_node_os4.default.homedir();
70284
- const rel = cwd.startsWith(home) ? "~" + cwd.slice(home.length) : cwd;
70285
- const norm = rel.replace(/\\/g, "/");
70286
- if (norm.length <= 30) return norm;
70287
- const parts = norm.split("/");
70288
- return parts.length > 3 ? `${parts[0]}/\u2026/${parts[parts.length - 1]}` : norm.slice(-30);
70289
- }
70290
- function asciiTitle(text2) {
70291
- const rows = 6;
70292
- const out2 = [];
70293
- for (let r = 0; r < rows; r++) {
70294
- out2.push(
70295
- [...text2].map((ch) => GLYPHS[ch] ? GLYPHS[ch][r] : " ").join(" ")
70296
- );
70297
- }
70298
- return out2;
70299
- }
70300
- function buildBanner(_systemPromptChars, version3 = "1") {
70301
- const user = (import_node_os4.default.userInfo().username || "hacker").toLowerCase();
70302
- const host = (import_node_os4.default.hostname() || "localhost").split(".")[0].toLowerCase();
70303
- const art = asciiTitle("CLAWFAST");
70304
- const artW = vlen(art[0]);
70305
- const slogan = "Com o clawfast voc\xEA faz tudo";
70306
- const header = [
70307
- "",
70308
- ...art.map((line) => `${C3.greenB}${C3.bold}${line}${C3.reset}`),
70309
- "",
70310
- `${C3.cyanB}${C3.bold}${center(slogan, artW)}${C3.reset}`,
70311
- ""
70312
- ];
70313
- const info = [
70314
- { text: "" },
70315
- { text: `Bem-vindo de volta, ${user}!`, accent: true },
70316
- { text: "" },
70317
- { text: "clawfast usa a pasta SPRIT/ para criar" },
70318
- { text: "arquivos, scripts e tudo mais." },
70319
- { text: "" },
70320
- { text: `${user}@${host} \xB7 sem limites` },
70321
- { text: shortCwd() },
70322
- { text: "" }
70323
- ];
70324
- const title = `clawfast v${version3}`;
70325
- const topFill = "\u2500".repeat(Math.max(0, BOX_W - vlen(title) - 5));
70326
- const top = `${C3.green}\u256D\u2500 ${C3.greenB}${C3.bold}${title}${C3.reset}${C3.green} ${topFill}\u256E${C3.reset}`;
70327
- const bottom = `${C3.green}\u2570${"\u2500".repeat(BOX_W - 2)}\u256F${C3.reset}`;
70328
- const cardLines = info.map(({ text: text2, accent }) => {
70329
- const color = accent ? `${C3.greenB}${C3.bold}` : C3.green;
70330
- const body = `${color}${padEndV(text2, INNER)}${C3.reset}`;
70331
- return `${C3.green}\u2502 ${C3.reset}${body}${C3.green} \u2502${C3.reset}`;
70332
- });
70333
- const card = [top, ...cardLines, bottom];
70334
- return "\n" + [...header, ...card].join("\n") + "\n";
70335
- }
70336
- function shellPrompt() {
70337
- const user = (import_node_os4.default.userInfo().username || "hacker").toLowerCase();
70338
- const host = (import_node_os4.default.hostname() || "localhost").split(".")[0].toLowerCase();
70339
- const W = 52;
70340
- const label = " \u2709 mensagem ";
70341
- const topFill = "\u2500".repeat(Math.max(0, W - vlen(label) - 3));
70342
- const top = `${C3.green}\u256D\u2500${C3.greenB}${C3.bold}${label}${C3.reset}${C3.green}${topFill}\u256E${C3.reset}`;
70343
- const id = `${user}\u327F${host} \xB7 ${shortCwd()}`;
70344
- const mid = `${C3.green}\u2502 ${C3.dim}${id}${C3.reset}`;
70345
- const bottom = `${C3.green}\u2570\u2500${C3.greenB}${C3.bold}\u276F${C3.reset} `;
70346
- return `
70347
- ${top}
70348
- ${mid}
70349
- ${bottom}`;
70350
- }
70351
- function agentHeader() {
70352
- return `${C3.magenta}\u256D\u2500 clawfast ${"\u2500".repeat(20)}${C3.reset}
70353
- `;
70354
- }
70355
- var import_node_os4, ESC, C3, INNER, BOX_W, vlen, padEndV, center, GLYPHS, ui;
70356
- var init_ui = __esm({
70357
- "src/ui.ts"() {
70879
+ var import_node_readline3, import_node_os5, C4, out2, cols, truncate4, InteractiveInput;
70880
+ var init_interactive_input = __esm({
70881
+ "src/interactive-input.ts"() {
70358
70882
  "use strict";
70359
- import_node_os4 = __toESM(require("node:os"));
70360
- ESC = "\x1B[";
70361
- C3 = {
70362
- reset: `${ESC}0m`,
70363
- bold: `${ESC}1m`,
70364
- dim: `${ESC}90m`,
70365
- green: `${ESC}32m`,
70366
- greenB: `${ESC}92m`,
70367
- cyan: `${ESC}36m`,
70368
- cyanB: `${ESC}96m`,
70369
- magenta: `${ESC}95m`,
70370
- yellow: `${ESC}93m`
70371
- };
70372
- INNER = 42;
70373
- BOX_W = INNER + 4;
70374
- vlen = (s) => [...s.replace(/\x1b\[[0-9;]*m/g, "")].length;
70375
- padEndV = (s, w) => s + " ".repeat(Math.max(0, w - vlen(s)));
70376
- center = (s, w) => {
70377
- const pad = Math.max(0, w - vlen(s));
70378
- const left = Math.floor(pad / 2);
70379
- return " ".repeat(left) + s + " ".repeat(pad - left);
70380
- };
70381
- GLYPHS = {
70382
- C: [" \u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588\u2588"],
70383
- L: ["\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588\u2588"],
70384
- A: [" \u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588"],
70385
- W: ["\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588 \u2588\u2588", "\u2588\u2588 \u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 \u2588\u2588 "],
70386
- F: ["\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 "],
70387
- S: [" \u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588 ", " \u2588\u2588", " \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588 "],
70388
- T: ["\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 "]
70883
+ import_node_readline3 = __toESM(require("node:readline"));
70884
+ import_node_os5 = __toESM(require("node:os"));
70885
+ init_ui();
70886
+ C4 = ui.C;
70887
+ out2 = (s) => process.stdout.write(s);
70888
+ cols = () => process.stdout.columns || 80;
70889
+ truncate4 = (s, n) => vlen(s) > n ? [...s].slice(0, Math.max(0, n - 1)).join("") + "\u2026" : s;
70890
+ InteractiveInput = class {
70891
+ // row the caret sits on within the drawn block
70892
+ constructor(paste, commands) {
70893
+ this.paste = paste;
70894
+ this.commands = commands;
70895
+ this.buffer = "";
70896
+ this.cursor = 0;
70897
+ this.lastRows = 0;
70898
+ this.history = [];
70899
+ this.histIdx = -1;
70900
+ // -1 = editing the live draft
70901
+ this.draft = "";
70902
+ this.ddSel = 0;
70903
+ this.ddSuppressed = false;
70904
+ // Text to restore on the NEXT prompt: when a command is picked from the
70905
+ // dropdown mid-text, we run the command but stash the surrounding text here
70906
+ // so the user doesn't lose what they were typing.
70907
+ this.pendingInitial = null;
70908
+ this.onKey = null;
70909
+ // When set, prompt() draws a compact single-line labelled prompt ("nome ")
70910
+ // instead of the full message box + dropdown — used for the /skillcreator
70911
+ // step-by-step capture so each phase shows what it's asking for.
70912
+ this.promptLabel = null;
70913
+ // When true, the submitted value is NOT recorded in ↑ history (used for the
70914
+ // /api key prompt so a pasted secret can't be recalled with the up arrow).
70915
+ this.promptSecret = false;
70916
+ this.inputLineIndex = 2;
70917
+ import_node_readline3.default.emitKeypressEvents(paste.input);
70918
+ paste.input.on("keypress", (str, key) => {
70919
+ this.onKey?.(str ?? "", key ?? {});
70920
+ });
70921
+ }
70922
+ // ── public API ─────────────────────────────────────────────────────────────
70923
+ /**
70924
+ * Render the input and resolve when the user submits / Ctrl+C / Ctrl+D.
70925
+ * Pass `{ label }` for a compact labelled prompt (no box, no dropdown).
70926
+ */
70927
+ prompt(opts = {}) {
70928
+ this.promptLabel = opts.label ?? null;
70929
+ this.promptSecret = opts.secret ?? false;
70930
+ const initial = this.promptLabel === null && this.pendingInitial ? this.pendingInitial : "";
70931
+ this.pendingInitial = null;
70932
+ this.buffer = initial;
70933
+ this.cursor = initial.length;
70934
+ this.histIdx = -1;
70935
+ this.draft = "";
70936
+ this.ddSel = 0;
70937
+ this.ddSuppressed = false;
70938
+ this.lastRows = 0;
70939
+ if (this.promptLabel === null) out2("\n");
70940
+ this.render();
70941
+ return new Promise((resolve2) => {
70942
+ this.onKey = (str, key) => {
70943
+ const done = this.handleEditKey(str, key);
70944
+ if (!done) {
70945
+ this.render();
70946
+ return;
70947
+ }
70948
+ this.onKey = null;
70949
+ resolve2(done.result);
70950
+ };
70951
+ });
70952
+ }
70953
+ /**
70954
+ * Arrow-navigable single-choice list. Returns the chosen index, or null when
70955
+ * the user cancels (Esc / q / Ctrl+C).
70956
+ */
70957
+ select(title, items, initial = 0) {
70958
+ let sel = Math.max(0, Math.min(initial, items.length - 1));
70959
+ this.lastRows = 0;
70960
+ out2("\n");
70961
+ this.renderList(title, items, sel);
70962
+ return new Promise((resolve2) => {
70963
+ const finish = (value) => {
70964
+ this.collapseTo(this.lastRows);
70965
+ this.onKey = null;
70966
+ resolve2(value);
70967
+ };
70968
+ this.onKey = (str, key) => {
70969
+ if (key.ctrl && key.name === "c") return finish(null);
70970
+ switch (key.name) {
70971
+ case "up":
70972
+ sel = (sel - 1 + items.length) % items.length;
70973
+ this.renderList(title, items, sel);
70974
+ return;
70975
+ case "down":
70976
+ case "tab":
70977
+ sel = (sel + 1) % items.length;
70978
+ this.renderList(title, items, sel);
70979
+ return;
70980
+ case "return":
70981
+ return finish(sel);
70982
+ case "escape":
70983
+ return finish(null);
70984
+ default:
70985
+ if (str === "q") return finish(null);
70986
+ if (/^[1-9]$/.test(str)) {
70987
+ const i = Number(str) - 1;
70988
+ if (i < items.length) {
70989
+ sel = i;
70990
+ this.renderList(title, items, sel);
70991
+ }
70992
+ }
70993
+ return;
70994
+ }
70995
+ };
70996
+ });
70997
+ }
70998
+ /**
70999
+ * Lightweight line reader used WHILE a turn is running, so typed lines can be
71000
+ * forwarded to an interactive command's stdin. No box/dropdown — just echoes
71001
+ * and collects until Enter. Ctrl+C invokes `onSigint`.
71002
+ */
71003
+ beginTurn(onLine, onSigint) {
71004
+ let buf = "";
71005
+ this.onKey = (str, key) => {
71006
+ if (key.ctrl && key.name === "c") return onSigint();
71007
+ if (key.name === "return") {
71008
+ out2("\r\n");
71009
+ const line = this.paste.expand(buf);
71010
+ buf = "";
71011
+ onLine(line);
71012
+ return;
71013
+ }
71014
+ if (key.name === "backspace") {
71015
+ if (buf.length) {
71016
+ buf = buf.slice(0, -1);
71017
+ out2("\b \b");
71018
+ }
71019
+ return;
71020
+ }
71021
+ if (str && str.charCodeAt(0) >= 32 && !key.ctrl && !key.meta) {
71022
+ buf += str;
71023
+ out2(str);
71024
+ }
71025
+ };
71026
+ }
71027
+ endTurn() {
71028
+ this.onKey = null;
71029
+ }
71030
+ // ── editing ──────────────────────────────────────────────────────────────
71031
+ handleEditKey(str, key) {
71032
+ const items = this.dropdownItems();
71033
+ if (key.ctrl && key.name === "c") {
71034
+ this.finishLine();
71035
+ return { result: { type: "sigint" } };
71036
+ }
71037
+ if (key.ctrl && key.name === "d") {
71038
+ if (this.buffer.length === 0) {
71039
+ this.finishLine();
71040
+ return { result: { type: "eof" } };
71041
+ }
71042
+ this.deleteForward();
71043
+ return null;
71044
+ }
71045
+ switch (key.name) {
71046
+ case "return": {
71047
+ if (items.length > 0) {
71048
+ const name25 = items[this.ddSel].name;
71049
+ const tok = this.slashTokenAtCursor();
71050
+ const leftover = tok ? this.buffer.slice(0, tok.start) + this.buffer.slice(tok.end) : "";
71051
+ this.pendingInitial = leftover.trim() ? leftover : null;
71052
+ this.buffer = name25;
71053
+ this.cursor = name25.length;
71054
+ }
71055
+ const value = this.paste.expand(this.buffer);
71056
+ if (value.trim() && !this.promptSecret) this.history.push(value);
71057
+ this.finishLine();
71058
+ return { result: { type: "line", value } };
71059
+ }
71060
+ case "tab":
71061
+ if (items.length > 0) {
71062
+ this.applyCommandInPlace(items[this.ddSel].name);
71063
+ this.ddSuppressed = false;
71064
+ }
71065
+ return null;
71066
+ case "up":
71067
+ if (items.length > 0) {
71068
+ this.ddSel = (this.ddSel - 1 + items.length) % items.length;
71069
+ } else {
71070
+ this.historyPrev();
71071
+ }
71072
+ return null;
71073
+ case "down":
71074
+ if (items.length > 0) {
71075
+ this.ddSel = (this.ddSel + 1) % items.length;
71076
+ } else {
71077
+ this.historyNext();
71078
+ }
71079
+ return null;
71080
+ case "escape":
71081
+ if (items.length > 0) this.ddSuppressed = true;
71082
+ return null;
71083
+ case "left":
71084
+ if (this.cursor > 0) this.cursor--;
71085
+ return null;
71086
+ case "right":
71087
+ if (this.cursor < this.buffer.length) this.cursor++;
71088
+ return null;
71089
+ case "home":
71090
+ this.cursor = 0;
71091
+ return null;
71092
+ case "end":
71093
+ this.cursor = this.buffer.length;
71094
+ return null;
71095
+ case "backspace":
71096
+ if (this.cursor > 0) {
71097
+ this.buffer = this.buffer.slice(0, this.cursor - 1) + this.buffer.slice(this.cursor);
71098
+ this.cursor--;
71099
+ this.ddSuppressed = false;
71100
+ }
71101
+ return null;
71102
+ case "delete":
71103
+ this.deleteForward();
71104
+ return null;
71105
+ }
71106
+ if (key.ctrl && key.name === "u") {
71107
+ this.buffer = this.buffer.slice(this.cursor);
71108
+ this.cursor = 0;
71109
+ this.ddSuppressed = false;
71110
+ return null;
71111
+ }
71112
+ if (key.ctrl && key.name === "w") {
71113
+ const left = this.buffer.slice(0, this.cursor);
71114
+ const trimmed = left.replace(/\s*\S+\s*$/u, "");
71115
+ this.buffer = trimmed + this.buffer.slice(this.cursor);
71116
+ this.cursor = trimmed.length;
71117
+ this.ddSuppressed = false;
71118
+ return null;
71119
+ }
71120
+ if (key.ctrl && key.name === "a") {
71121
+ this.cursor = 0;
71122
+ return null;
71123
+ }
71124
+ if (key.ctrl && key.name === "e") {
71125
+ this.cursor = this.buffer.length;
71126
+ return null;
71127
+ }
71128
+ if (str && !key.ctrl && !key.meta && str.charCodeAt(0) >= 32) {
71129
+ this.buffer = this.buffer.slice(0, this.cursor) + str + this.buffer.slice(this.cursor);
71130
+ this.cursor += str.length;
71131
+ this.ddSuppressed = false;
71132
+ }
71133
+ return null;
71134
+ }
71135
+ deleteForward() {
71136
+ if (this.cursor < this.buffer.length) {
71137
+ this.buffer = this.buffer.slice(0, this.cursor) + this.buffer.slice(this.cursor + 1);
71138
+ this.ddSuppressed = false;
71139
+ }
71140
+ }
71141
+ historyPrev() {
71142
+ if (this.history.length === 0) return;
71143
+ if (this.histIdx === -1) {
71144
+ this.draft = this.buffer;
71145
+ this.histIdx = this.history.length - 1;
71146
+ } else if (this.histIdx > 0) {
71147
+ this.histIdx--;
71148
+ }
71149
+ this.buffer = this.history[this.histIdx];
71150
+ this.cursor = this.buffer.length;
71151
+ }
71152
+ historyNext() {
71153
+ if (this.histIdx === -1) return;
71154
+ if (this.histIdx < this.history.length - 1) {
71155
+ this.histIdx++;
71156
+ this.buffer = this.history[this.histIdx];
71157
+ } else {
71158
+ this.histIdx = -1;
71159
+ this.buffer = this.draft;
71160
+ }
71161
+ this.cursor = this.buffer.length;
71162
+ }
71163
+ // ── rendering ──────────────────────────────────────────────────────────────
71164
+ // The slash-command "token" the cursor is sitting in — the run of
71165
+ // non-whitespace chars around the cursor, when it begins with "/". Works at
71166
+ // the start of the line OR in the middle of the text (e.g. "veja o /mod"),
71167
+ // so the command dropdown opens wherever you type a slash. Returns the span
71168
+ // [start, end) to replace and the query (the whole token) to filter by.
71169
+ slashTokenAtCursor() {
71170
+ const b = this.buffer;
71171
+ let start = this.cursor;
71172
+ while (start > 0 && !/\s/.test(b[start - 1])) start--;
71173
+ if (b[start] !== "/") return null;
71174
+ let end = this.cursor;
71175
+ while (end < b.length && !/\s/.test(b[end])) end++;
71176
+ const query = b.slice(start, end);
71177
+ if (!/^\/\S*$/.test(query)) return null;
71178
+ return { start, end, query };
71179
+ }
71180
+ // Replace the slash token under the cursor with `name` (used by Tab/Enter
71181
+ // completion), leaving the surrounding text intact and the cursor right after
71182
+ // the inserted command.
71183
+ applyCommandInPlace(name25) {
71184
+ const tok = this.slashTokenAtCursor();
71185
+ if (!tok) return;
71186
+ this.buffer = this.buffer.slice(0, tok.start) + name25 + this.buffer.slice(tok.end);
71187
+ this.cursor = tok.start + name25.length;
71188
+ }
71189
+ dropdownItems() {
71190
+ if (this.promptLabel !== null) return [];
71191
+ if (this.ddSuppressed) return [];
71192
+ const tok = this.slashTokenAtCursor();
71193
+ if (!tok) return [];
71194
+ const q = tok.query.toLowerCase();
71195
+ return this.commands.filter((c) => c.name.toLowerCase().startsWith(q));
71196
+ }
71197
+ render() {
71198
+ if (this.promptLabel !== null) {
71199
+ this.renderCompact();
71200
+ return;
71201
+ }
71202
+ const width = cols();
71203
+ const user = (import_node_os5.default.userInfo().username || "hacker").toLowerCase();
71204
+ const host = (import_node_os5.default.hostname() || "localhost").split(".")[0].toLowerCase();
71205
+ const label = " \u2709 mensagem ";
71206
+ const boxW = Math.min(54, Math.max(28, width - 2));
71207
+ const topFill = "\u2500".repeat(Math.max(0, boxW - vlen(label) - 3));
71208
+ const top = `${C4.green}\u256D\u2500${C4.greenB}${C4.bold}${label}${C4.reset}${C4.green}${topFill}\u256E${C4.reset}`;
71209
+ const id = `${user}\u327F${host} \xB7 ${shortCwd()}`;
71210
+ const idLine = `${C4.green}\u2502 ${C4.dim}${truncate4(id, boxW - 4)}${C4.reset}`;
71211
+ const prefix = `${C4.green}\u2570\u2500${C4.greenB}${C4.bold}\u276F${C4.reset} `;
71212
+ const prefixLen = 4;
71213
+ const avail = Math.max(8, width - prefixLen - 1);
71214
+ let start = 0;
71215
+ if (this.cursor > avail) start = this.cursor - avail;
71216
+ const visible = this.buffer.slice(start, start + avail);
71217
+ const caretCol = prefixLen + (this.cursor - start);
71218
+ const promptLine2 = prefix + visible;
71219
+ const lines = [top, idLine, promptLine2];
71220
+ const items = this.dropdownItems();
71221
+ if (items.length > 0) {
71222
+ this.ddSel = Math.min(this.ddSel, items.length - 1);
71223
+ const ddHint = "\u2191\u2193 navega \xB7 Enter roda \xB7 Tab completa";
71224
+ const nameW = Math.max(...items.map((i) => vlen(i.name)));
71225
+ const ddInner = Math.min(boxW, Math.max(24, width - 4));
71226
+ lines.push(`${C4.dim} \u256D${"\u2500".repeat(ddInner)}\u256E${C4.reset}`);
71227
+ items.forEach((it, i) => {
71228
+ const active2 = i === this.ddSel;
71229
+ const marker25 = active2 ? `${C4.greenB}\u25B8 ` : `${C4.dim} `;
71230
+ const name25 = (active2 ? `${C4.greenB}${C4.bold}` : C4.cyan) + it.name;
71231
+ const pad = " ".repeat(Math.max(1, nameW - vlen(it.name) + 2));
71232
+ const descRoom = ddInner - 2 - nameW - 2;
71233
+ const desc = `${C4.dim}${truncate4(it.desc, Math.max(4, descRoom))}`;
71234
+ const body = `${marker25}${name25}${C4.reset}${pad}${desc}${C4.reset}`;
71235
+ const padded = body + " ".repeat(Math.max(0, ddInner - 1 - vlen(body)));
71236
+ lines.push(`${C4.dim} \u2502${C4.reset}${padded}${C4.dim}\u2502${C4.reset}`);
71237
+ });
71238
+ lines.push(
71239
+ `${C4.dim} \u2570${"\u2500".repeat(ddInner)}\u256F ${ddHint}${C4.reset}`
71240
+ );
71241
+ } else {
71242
+ this.ddSel = 0;
71243
+ }
71244
+ this.inputLineIndex = 2;
71245
+ this.paint(lines, caretCol);
71246
+ }
71247
+ /** Compact single-line labelled prompt ("nome ❯ …") for step-by-step capture. */
71248
+ renderCompact() {
71249
+ const width = cols();
71250
+ const label = this.promptLabel ?? "";
71251
+ const prefix = `${C4.cyan}${C4.bold}${label}${C4.reset} ${C4.greenB}${C4.bold}\u276F${C4.reset} `;
71252
+ const prefixLen = vlen(`${label} \u276F `);
71253
+ const avail = Math.max(8, width - prefixLen - 1);
71254
+ let start = 0;
71255
+ if (this.cursor > avail) start = this.cursor - avail;
71256
+ const visible = this.buffer.slice(start, start + avail);
71257
+ const caretCol = prefixLen + (this.cursor - start);
71258
+ this.inputLineIndex = 0;
71259
+ this.paint([prefix + visible], caretCol);
71260
+ }
71261
+ /** Repaint the whole block, then place the cursor on the active input line. */
71262
+ paint(lines, caretCol) {
71263
+ let s = "";
71264
+ if (this.lastRows > 1) s += `\x1B[${this.lastRows - 1}A`;
71265
+ s += "\r\x1B[0J";
71266
+ s += lines.join("\r\n");
71267
+ this.lastRows = lines.length;
71268
+ const below = lines.length - 1 - this.inputLineIndex;
71269
+ if (below > 0) s += `\x1B[${below}A`;
71270
+ s += "\r";
71271
+ if (caretCol > 0) s += `\x1B[${caretCol}C`;
71272
+ out2(s);
71273
+ }
71274
+ /** Collapse the dropdown, keep the typed line, and drop to a fresh line below. */
71275
+ finishLine() {
71276
+ this.ddSuppressed = true;
71277
+ this.render();
71278
+ const below = this.lastRows - 1 - this.inputLineIndex;
71279
+ if (below > 0) out2(`\x1B[${below}B`);
71280
+ out2("\r\n");
71281
+ this.lastRows = 0;
71282
+ }
71283
+ renderList(title, items, sel) {
71284
+ const width = cols();
71285
+ const labelW = Math.max(...items.map((i) => vlen(i.label)));
71286
+ const inner = Math.min(
71287
+ Math.max(28, width - 4),
71288
+ Math.max(labelW + 8, title.length + 4)
71289
+ );
71290
+ const lines = [];
71291
+ lines.push(`${C4.cyan}\u256D\u2500 ${C4.bold}${title}${C4.reset}`);
71292
+ items.forEach((it, i) => {
71293
+ const active2 = i === sel;
71294
+ const marker25 = active2 ? `${C4.greenB}\u276F ` : `${C4.dim} `;
71295
+ const text2 = active2 ? `${C4.greenB}${C4.bold}${it.label}${C4.reset}` : `${C4.reset}${it.label}`;
71296
+ const hint = it.hint ? ` ${C4.dim}${truncate4(it.hint, Math.max(6, inner - labelW - 6))}${C4.reset}` : "";
71297
+ lines.push(`${C4.cyan}\u2502 ${C4.reset}${marker25}${text2}${C4.reset}${hint}`);
71298
+ });
71299
+ lines.push(
71300
+ `${C4.cyan}\u2570\u2500${C4.reset} ${C4.dim}\u2191\u2193 navega \xB7 Enter seleciona \xB7 Esc cancela${C4.reset}`
71301
+ );
71302
+ this.paintBlock(lines);
71303
+ }
71304
+ /** Repaint a block and leave the cursor just below it (for list/menu modes). */
71305
+ paintBlock(lines) {
71306
+ let s = "";
71307
+ if (this.lastRows > 1) s += `\x1B[${this.lastRows - 1}A`;
71308
+ s += "\r\x1B[0J";
71309
+ s += lines.join("\r\n");
71310
+ s += "\r";
71311
+ out2(s);
71312
+ this.lastRows = lines.length;
71313
+ }
71314
+ /** Move the cursor below a block of `rows` lines and clear it. */
71315
+ collapseTo(rows) {
71316
+ if (rows > 1) out2(`\x1B[${rows - 1}A`);
71317
+ out2("\r\x1B[0J");
71318
+ this.lastRows = 0;
71319
+ }
70389
71320
  };
70390
- ui = { C: C3, buildBanner, shellPrompt, agentHeader };
70391
71321
  }
70392
71322
  });
70393
71323
 
@@ -70395,12 +71325,12 @@ var init_ui = __esm({
70395
71325
  var index_exports = {};
70396
71326
  async function main() {
70397
71327
  const { createAgent: createAgent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
70398
- const { buildBanner: buildBanner2, shellPrompt: shellPrompt2, agentHeader: agentHeader2, ui: ui2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
71328
+ const { buildBanner: buildBanner2, agentHeader: agentHeader2, ui: ui2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
71329
+ const { InteractiveInput: InteractiveInput2 } = await Promise.resolve().then(() => (init_interactive_input(), interactive_input_exports));
71330
+ const C5 = ui2.C;
70399
71331
  if (!bootQuiet) {
70400
- process.stdout.write(
70401
- `${ui2.C.dim} booting local sandbox + agent\u2026${ui2.C.reset}
70402
- `
70403
- );
71332
+ process.stdout.write(`${C5.dim} booting local sandbox + agent\u2026${C5.reset}
71333
+ `);
70404
71334
  }
70405
71335
  const agent = await createAgent2();
70406
71336
  const sys = agent.getSystemPrompt();
@@ -70409,39 +71339,37 @@ async function main() {
70409
71339
  process.stdout.write(buildBanner2(sys.length, version3));
70410
71340
  const updateNotice = getUpdateNotice(version3);
70411
71341
  if (updateNotice) {
70412
- process.stdout.write(
70413
- `${ui2.C.yellow}\u2191 ${updateNotice}${ui2.C.reset}
70414
- `
70415
- );
71342
+ process.stdout.write(`${C5.yellow}\u2191 ${updateNotice}${C5.reset}
71343
+ `);
70416
71344
  }
70417
71345
  refreshUpdateCacheInBackground(version3);
70418
71346
  if (consumePostUpdateLaunch(version3)) {
70419
71347
  process.stdout.write(
70420
- `${ui2.C.greenB}Seja bem vindo ao submundo.${ui2.C.reset} ${ui2.C.dim}clawfast atualizado para ${version3} \u2014 rode ${ui2.C.reset}${ui2.C.cyan}/nov${ui2.C.reset}${ui2.C.dim} para ver as novidades.${ui2.C.reset}
71348
+ `${C5.greenB}Seja bem vindo ao submundo.${C5.reset} ${C5.dim}clawfast atualizado para ${version3} \u2014 rode ${C5.reset}${C5.cyan}/nov${C5.reset}${C5.dim} para ver as novidades.${C5.reset}
70421
71349
  `
70422
71350
  );
70423
71351
  }
71352
+ process.stdout.write(
71353
+ `${C5.dim}digite ${C5.reset}${C5.cyan}/${C5.reset}${C5.dim} para ver os comandos \xB7 \u2191\u2193 hist\xF3rico \xB7 Ctrl+C interrompe${C5.reset}
71354
+ `
71355
+ );
71356
+ const COMMANDS = [
71357
+ { name: "/model", desc: "trocar o modelo (seletor com setas)" },
71358
+ { name: "/api", desc: "trocar a chave NVIDIA (testa e ativa na hora)" },
71359
+ { name: "/skills", desc: "listar as skills instaladas" },
71360
+ { name: "/skillcreator", desc: "criar uma nova skill" },
71361
+ { name: "/system", desc: "salvar o system prompt (HTML) na \xC1rea de Trabalho" },
71362
+ { name: "/nov", desc: "novidades desta vers\xE3o" },
71363
+ { name: "/exit", desc: "fechar o clawfast" }
71364
+ ];
70424
71365
  const pasteInput = createPasteInput();
70425
- const rl = import_node_readline3.default.createInterface({
70426
- input: pasteInput.input,
70427
- output: process.stdout,
70428
- terminal: true
70429
- });
71366
+ const inputUI = new InteractiveInput2(pasteInput, COMMANDS);
70430
71367
  let closing = false;
70431
- let commandQueue = Promise.resolve();
70432
- let awaitingModelSelection = false;
70433
- let skillCreator = null;
70434
- const prompt = () => {
70435
- rl.setPrompt(
70436
- skillCreator ? skillPrompt(skillCreator.phase) : awaitingModelSelection ? modelPrompt() : shellPrompt2()
70437
- );
70438
- rl.prompt();
70439
- };
71368
+ let shuttingDown = false;
70440
71369
  let activeAbort = null;
70441
71370
  let turnActive = false;
70442
71371
  let exitArmed = false;
70443
71372
  let exitTimer = null;
70444
- let lastSigint = 0;
70445
71373
  const armExit = () => {
70446
71374
  exitArmed = true;
70447
71375
  if (exitTimer) clearTimeout(exitTimer);
@@ -70450,69 +71378,58 @@ async function main() {
70450
71378
  exitTimer = null;
70451
71379
  }, 2e3);
70452
71380
  };
70453
- const handleSigint = () => {
70454
- const now2 = Date.now();
70455
- if (now2 - lastSigint < 60) return;
70456
- lastSigint = now2;
70457
- if (closing) return;
70458
- if (exitArmed) {
70459
- if (exitTimer) clearTimeout(exitTimer);
70460
- exitTimer = null;
70461
- exitArmed = false;
70462
- closing = true;
70463
- activeAbort?.abort();
70464
- process.stdout.write(`
70465
- ${ui2.C.dim}fechando\u2026${ui2.C.reset}
70466
- `);
70467
- rl.close();
70468
- return;
70469
- }
70470
- if (activeAbort && !activeAbort.signal.aborted) {
70471
- activeAbort.abort();
70472
- process.stdout.write(
70473
- `
70474
- ${ui2.C.dim}interrompido \u2014 Ctrl+C de novo para fechar${ui2.C.reset}
70475
- `
70476
- );
70477
- } else {
70478
- process.stdout.write(
70479
- `
70480
- ${ui2.C.dim}Ctrl+C de novo para fechar${ui2.C.reset}
71381
+ const shutdown = async () => {
71382
+ if (shuttingDown) return;
71383
+ shuttingDown = true;
71384
+ closing = true;
71385
+ pasteInput.dispose();
71386
+ process.stdout.write("\nClosing sandbox...\n");
71387
+ await agent.close();
71388
+ process.exit(0);
71389
+ };
71390
+ const desktopDir = () => {
71391
+ const home = import_node_os6.default.homedir();
71392
+ const candidates = [
71393
+ process.env.OneDrive ? import_node_path9.default.join(process.env.OneDrive, "Desktop") : null,
71394
+ process.env.USERPROFILE ? import_node_path9.default.join(process.env.USERPROFILE, "Desktop") : null,
71395
+ import_node_path9.default.join(home, "Desktop"),
71396
+ import_node_path9.default.join(home, "\xC1rea de Trabalho"),
71397
+ import_node_path9.default.join(home, "OneDrive", "Desktop")
71398
+ ].filter((p) => Boolean(p));
71399
+ return candidates.find((p) => (0, import_node_fs8.existsSync)(p)) ?? home;
71400
+ };
71401
+ const printFatal = (err) => {
71402
+ process.stderr.write(
71403
+ `
71404
+ [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70481
71405
  `
70482
- );
70483
- if (!awaitingModelSelection) prompt();
70484
- }
70485
- armExit();
71406
+ );
70486
71407
  };
70487
- process.removeAllListeners("SIGINT");
70488
- process.on("SIGINT", handleSigint);
70489
- rl.on("SIGINT", handleSigint);
71408
+ let skillCreator = null;
70490
71409
  const printSkillList = () => {
70491
71410
  const skills = listSkills();
70492
71411
  if (skills.length === 0) {
70493
71412
  process.stdout.write(
70494
71413
  `
70495
- ${ui2.C.dim}nenhuma skill instalada. crie uma com /skillcreator${ui2.C.reset}
71414
+ ${C5.dim}nenhuma skill instalada. crie uma com /skillcreator${C5.reset}
70496
71415
  `
70497
71416
  );
70498
71417
  return;
70499
71418
  }
70500
71419
  process.stdout.write(
70501
71420
  `
70502
- ${ui2.C.cyan}skills instaladas${ui2.C.reset} ${ui2.C.dim}(${skillsDir()})${ui2.C.reset}
71421
+ ${C5.cyan}skills instaladas${C5.reset} ${C5.dim}(${skillsDir()})${C5.reset}
70503
71422
  `
70504
71423
  );
70505
71424
  for (const s of skills) {
70506
- const flags = s.always ? ` ${ui2.C.yellow}[sempre]${ui2.C.reset}` : "";
71425
+ const flags = s.always ? ` ${C5.yellow}[sempre]${C5.reset}` : "";
70507
71426
  process.stdout.write(
70508
- ` ${ui2.C.green}${s.name}${ui2.C.reset}${flags} ${ui2.C.dim}\u2014${ui2.C.reset} ${s.description}
71427
+ ` ${C5.green}${s.name}${C5.reset}${flags} ${C5.dim}\u2014${C5.reset} ${s.description}
70509
71428
  `
70510
71429
  );
70511
71430
  }
70512
- process.stdout.write(
70513
- `${ui2.C.dim}remover: /skill delete <nome>${ui2.C.reset}
70514
- `
70515
- );
71431
+ process.stdout.write(`${C5.dim}remover: /skill delete <nome>${C5.reset}
71432
+ `);
70516
71433
  };
70517
71434
  const handleSkillCommand = (input) => {
70518
71435
  if (input === "/skillcreator") {
@@ -70525,9 +71442,9 @@ ${ui2.C.cyan}skills instaladas${ui2.C.reset} ${ui2.C.dim}(${skillsDir()})${ui2.C
70525
71442
  };
70526
71443
  process.stdout.write(
70527
71444
  `
70528
- ${ui2.C.greenB}criar skill${ui2.C.reset} ${ui2.C.dim}(/cancelar para abortar)${ui2.C.reset}
70529
- ${ui2.C.dim}skills ficam disponiveis para TODOS os modelos; o conteudo completo so e carregado quando o pedido casa com a skill.${ui2.C.reset}
70530
- ${ui2.C.cyan}nome da skill?${ui2.C.reset} ${ui2.C.dim}(ex: xss-recon)${ui2.C.reset}
71445
+ ${C5.greenB}criar skill${C5.reset} ${C5.dim}(/cancelar para abortar)${C5.reset}
71446
+ ${C5.dim}skills ficam disponiveis para TODOS os modelos; o conteudo completo so e carregado quando o pedido casa com a skill.${C5.reset}
71447
+ ${C5.cyan}nome da skill?${C5.reset} ${C5.dim}(ex: xss-recon)${C5.reset}
70531
71448
  `
70532
71449
  );
70533
71450
  return;
@@ -70545,29 +71462,27 @@ ${ui2.C.cyan}nome da skill?${ui2.C.reset} ${ui2.C.dim}(ex: xss-recon)${ui2.C.res
70545
71462
  }
70546
71463
  if (sub === "delete" || sub === "rm" || sub === "remove") {
70547
71464
  if (!arg) {
70548
- process.stdout.write(
70549
- `${ui2.C.yellow}uso: /skill delete <nome>${ui2.C.reset}
70550
- `
70551
- );
71465
+ process.stdout.write(`${C5.yellow}uso: /skill delete <nome>${C5.reset}
71466
+ `);
70552
71467
  return;
70553
71468
  }
70554
71469
  if (deleteSkill(arg)) {
70555
71470
  await agent.refreshSkills();
70556
71471
  process.stdout.write(
70557
- `${ui2.C.green}\u2713 skill '${slugify(arg)}' removida${ui2.C.reset}
71472
+ `${C5.green}\u2713 skill '${slugify(arg)}' removida${C5.reset}
70558
71473
  `
70559
71474
  );
70560
71475
  } else {
70561
71476
  process.stdout.write(
70562
- `${ui2.C.yellow}skill '${arg}' nao encontrada${ui2.C.reset}
71477
+ `${C5.yellow}skill '${arg}' nao encontrada${C5.reset}
70563
71478
  `
70564
71479
  );
70565
71480
  }
70566
71481
  return;
70567
71482
  }
70568
71483
  process.stdout.write(
70569
- `${ui2.C.yellow}subcomando desconhecido: ${sub}${ui2.C.reset}
70570
- ${ui2.C.dim}use: /skillcreator | /skills | /skill delete <nome>${ui2.C.reset}
71484
+ `${C5.yellow}subcomando desconhecido: ${sub}${C5.reset}
71485
+ ${C5.dim}use: /skillcreator | /skills | /skill delete <nome>${C5.reset}
70571
71486
  `
70572
71487
  );
70573
71488
  };
@@ -70575,7 +71490,7 @@ ${ui2.C.dim}use: /skillcreator | /skills | /skill delete <nome>${ui2.C.reset}
70575
71490
  const text2 = sc.bodyLines.join("\n");
70576
71491
  const lines = text2 ? text2.split("\n").length : 0;
70577
71492
  process.stdout.write(
70578
- `${ui2.C.dim} capturado: ${lines} linhas, ${text2.length} chars \u2014 continue colando, /fim para salvar, /desfazer para remover o ultimo, /cancelar para abortar${ui2.C.reset}
71493
+ `${C5.dim} capturado: ${lines} linhas, ${text2.length} chars \u2014 continue colando, /fim para salvar, /desfazer para remover o ultimo, /cancelar para abortar${C5.reset}
70579
71494
  `
70580
71495
  );
70581
71496
  };
@@ -70584,11 +71499,9 @@ ${ui2.C.dim}use: /skillcreator | /skills | /skill delete <nome>${ui2.C.reset}
70584
71499
  if (!sc) return;
70585
71500
  if (input === "/cancelar" || input === "/cancel") {
70586
71501
  skillCreator = null;
70587
- process.stdout.write(
70588
- `
70589
- ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70590
- `
70591
- );
71502
+ process.stdout.write(`
71503
+ ${C5.dim}criacao de skill cancelada${C5.reset}
71504
+ `);
70592
71505
  return;
70593
71506
  }
70594
71507
  switch (sc.phase) {
@@ -70596,7 +71509,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70596
71509
  const slug = slugify(input);
70597
71510
  if (!slug) {
70598
71511
  process.stdout.write(
70599
- `${ui2.C.yellow}nome invalido \u2014 tente de novo${ui2.C.reset}
71512
+ `${C5.yellow}nome invalido \u2014 tente de novo${C5.reset}
70600
71513
  `
70601
71514
  );
70602
71515
  return;
@@ -70604,22 +71517,20 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70604
71517
  sc.name = slug;
70605
71518
  if (listSkills().some((s) => s.name === slug)) {
70606
71519
  process.stdout.write(
70607
- `${ui2.C.yellow}ja existe uma skill '${slug}' \u2014 sera sobrescrita${ui2.C.reset}
71520
+ `${C5.yellow}ja existe uma skill '${slug}' \u2014 sera sobrescrita${C5.reset}
70608
71521
  `
70609
71522
  );
70610
71523
  }
70611
71524
  sc.phase = "desc";
70612
- process.stdout.write(
70613
- `${ui2.C.cyan}descricao curta (1 linha)?${ui2.C.reset}
70614
- `
70615
- );
71525
+ process.stdout.write(`${C5.cyan}descricao curta (1 linha)?${C5.reset}
71526
+ `);
70616
71527
  return;
70617
71528
  }
70618
71529
  case "desc": {
70619
71530
  sc.description = input;
70620
71531
  sc.phase = "triggers";
70621
71532
  process.stdout.write(
70622
- `${ui2.C.cyan}palavras-gatilho?${ui2.C.reset} ${ui2.C.dim}(separadas por virgula; Enter usa o proprio nome)${ui2.C.reset}
71533
+ `${C5.cyan}palavras-gatilho?${C5.reset} ${C5.dim}(separadas por virgula; Enter usa o proprio nome)${C5.reset}
70623
71534
  `
70624
71535
  );
70625
71536
  return;
@@ -70631,7 +71542,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70631
71542
  sc.phase = "body";
70632
71543
  sc.bodyLines.push(line.replace(/\r$/, ""));
70633
71544
  process.stdout.write(
70634
- `${ui2.C.yellow}isso parece a skill, nao gatilhos \u2014 capturei como conteudo.${ui2.C.reset}
71545
+ `${C5.yellow}isso parece a skill, nao gatilhos \u2014 capturei como conteudo.${C5.reset}
70635
71546
  `
70636
71547
  );
70637
71548
  printBodyTally(sc);
@@ -70640,7 +71551,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70640
71551
  sc.triggers = input ? input.split(",").map((t) => t.trim()).filter(Boolean) : [];
70641
71552
  sc.phase = "body";
70642
71553
  process.stdout.write(
70643
- `${ui2.C.cyan}cole ou escreva a skill agora${ui2.C.reset} ${ui2.C.dim}(qualquer tamanho). termine com uma linha contendo so /fim${ui2.C.reset}
71554
+ `${C5.cyan}cole ou escreva a skill agora${C5.reset} ${C5.dim}(qualquer tamanho). termine com uma linha contendo so /fim${C5.reset}
70644
71555
  `
70645
71556
  );
70646
71557
  return;
@@ -70650,7 +71561,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70650
71561
  const body = sc.bodyLines.join("\n").trim();
70651
71562
  if (!body) {
70652
71563
  process.stdout.write(
70653
- `${ui2.C.yellow}corpo vazio \u2014 cole algum conteudo ou /cancelar${ui2.C.reset}
71564
+ `${C5.yellow}corpo vazio \u2014 cole algum conteudo ou /cancelar${C5.reset}
70654
71565
  `
70655
71566
  );
70656
71567
  return;
@@ -70665,22 +71576,20 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70665
71576
  await agent.refreshSkills();
70666
71577
  process.stdout.write(
70667
71578
  `
70668
- ${ui2.C.green}\u2713 skill '${res.skill.name}' ${res.overwritten ? "atualizada" : "criada"}${ui2.C.reset} ${ui2.C.dim}(${res.file})${ui2.C.reset}
70669
- ${ui2.C.dim}ja disponivel para todos os modelos nesta sessao.${ui2.C.reset}
71579
+ ${C5.green}\u2713 skill '${res.skill.name}' ${res.overwritten ? "atualizada" : "criada"}${C5.reset} ${C5.dim}(${res.file})${C5.reset}
71580
+ ${C5.dim}ja disponivel para todos os modelos nesta sessao.${C5.reset}
70670
71581
  `
70671
71582
  );
70672
71583
  return;
70673
71584
  }
70674
71585
  if (input === "/desfazer" || input === "/undo") {
70675
71586
  if (sc.bodyLines.length === 0) {
70676
- process.stdout.write(
70677
- `${ui2.C.dim}nada para desfazer${ui2.C.reset}
70678
- `
70679
- );
71587
+ process.stdout.write(`${C5.dim}nada para desfazer${C5.reset}
71588
+ `);
70680
71589
  } else {
70681
71590
  sc.bodyLines.pop();
70682
71591
  process.stdout.write(
70683
- `${ui2.C.yellow}ultimo trecho removido.${ui2.C.reset}
71592
+ `${C5.yellow}ultimo trecho removido.${C5.reset}
70684
71593
  `
70685
71594
  );
70686
71595
  printBodyTally(sc);
@@ -70693,206 +71602,252 @@ ${ui2.C.dim}ja disponivel para todos os modelos nesta sessao.${ui2.C.reset}
70693
71602
  }
70694
71603
  }
70695
71604
  };
71605
+ const printModelResult = (result) => {
71606
+ process.stdout.write(
71607
+ `${result.ok ? `${C5.green}\u2713` : `${C5.red}\u2717`} ${result.message}${C5.reset}
71608
+ `
71609
+ );
71610
+ };
71611
+ const openModelSelector = async () => {
71612
+ const state = agent.getModelSelection();
71613
+ const items = [
71614
+ {
71615
+ label: "Auto \u2014 cadeia de fallback autom\xE1tica",
71616
+ hint: "tenta os modelos em ordem"
71617
+ },
71618
+ ...state.chain.map((c) => ({ label: c.label, hint: c.key }))
71619
+ ];
71620
+ const activeIdx = state.mode === "auto" ? 0 : Math.max(
71621
+ 0,
71622
+ 1 + state.chain.findIndex((c) => c.key === state.activeModelKey)
71623
+ );
71624
+ const choice2 = await inputUI.select("selecionar modelo", items, activeIdx);
71625
+ if (choice2 === null) {
71626
+ process.stdout.write(`${C5.dim}sele\xE7\xE3o de modelo cancelada${C5.reset}
71627
+ `);
71628
+ return;
71629
+ }
71630
+ const arg = choice2 === 0 ? "auto" : state.chain[choice2 - 1].key;
71631
+ try {
71632
+ printModelResult(await agent.setModelSelection(arg));
71633
+ } catch (err) {
71634
+ printFatal(err);
71635
+ }
71636
+ };
71637
+ const handleApiSwap = async (inlineKey) => {
71638
+ let raw = inlineKey;
71639
+ if (!raw) {
71640
+ process.stdout.write(
71641
+ `${C5.dim}Cole a nova chave NVIDIA (cria em ${C5.reset}${C5.cyan}https://build.nvidia.com/${C5.reset}${C5.dim}). Enter vazio ou Ctrl+C cancela.${C5.reset}
71642
+ `
71643
+ );
71644
+ const res = await inputUI.prompt({
71645
+ label: "nova NVIDIA API key",
71646
+ secret: true
71647
+ });
71648
+ if (res.type !== "line" || !res.value.trim()) {
71649
+ process.stdout.write(`${C5.dim}troca de chave cancelada${C5.reset}
71650
+ `);
71651
+ return;
71652
+ }
71653
+ raw = res.value;
71654
+ }
71655
+ const key = raw.replace(/\s+/g, "").match(/nvapi-[A-Za-z0-9_-]+/)?.[0] ?? "";
71656
+ if (!key) {
71657
+ process.stdout.write(
71658
+ `${C5.red}\u2717 n\xE3o encontrei uma chave NVIDIA no que foi colado${C5.reset} ${C5.dim}(esperado um token "nvapi-\u2026"; cole a chave completa).${C5.reset}
71659
+ `
71660
+ );
71661
+ return;
71662
+ }
71663
+ process.stdout.write(`${C5.dim}testando a chave na NVIDIA\u2026${C5.reset}
71664
+ `);
71665
+ const test = await testNvidiaKey(key);
71666
+ if (!test.ok) {
71667
+ if (test.status === 401 || test.status === 403) {
71668
+ process.stdout.write(
71669
+ `${C5.red}\u2717 a NVIDIA recusou a chave (${test.status}): ${test.detail}${C5.reset}
71670
+ ${C5.dim}chave N\xC3O salva \u2014 confira se copiou inteira e se a conta tem acesso de infer\xEAncia.${C5.reset}
71671
+ `
71672
+ );
71673
+ return;
71674
+ }
71675
+ process.stdout.write(
71676
+ `${C5.yellow}\u26A0 n\xE3o consegui validar (${test.status || "rede"}): ${test.detail}${C5.reset}
71677
+ ${C5.dim}salvando mesmo assim \u2014 o pr\xF3ximo pedido vai usar a chave nova.${C5.reset}
71678
+ `
71679
+ );
71680
+ }
71681
+ const file2 = swapNvidiaKey(key);
71682
+ const masked = `${key.slice(0, 9)}\u2026${key.slice(-4)} (${key.length} chars)`;
71683
+ process.stdout.write(
71684
+ `${C5.green}\u2713 chave NVIDIA trocada e ativa${C5.reset} ${C5.dim}${masked}${C5.reset}
71685
+ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
71686
+ `
71687
+ );
71688
+ };
70696
71689
  const handleLine = async (line) => {
70697
71690
  if (closing) return;
70698
71691
  const input = line.trim();
70699
71692
  if (skillCreator) {
70700
71693
  await handleSkillCreatorLine(line, input);
70701
- if (!closing) prompt();
70702
71694
  return;
70703
71695
  }
70704
71696
  if (input === "/exit" || input === "/quit") {
70705
71697
  closing = true;
70706
- rl.close();
70707
71698
  return;
70708
71699
  }
70709
71700
  if (input === "/skillcreator" || input === "/skill" || input === "/skills") {
70710
71701
  handleSkillCommand(input);
70711
- if (!closing) prompt();
70712
71702
  return;
70713
71703
  }
70714
71704
  if (input.startsWith("/skill ") || input.startsWith("/skills ")) {
70715
71705
  await handleSkillSubcommand(input);
70716
- if (!closing) prompt();
70717
71706
  return;
70718
71707
  }
70719
- if (awaitingModelSelection) {
70720
- if (!input || input === "cancelar" || input === "cancel" || input === "sair" || input === "q") {
70721
- awaitingModelSelection = false;
70722
- process.stdout.write(
70723
- `
70724
- ${ui2.C.dim}selecao de modelo cancelada${ui2.C.reset}
70725
- `
70726
- );
70727
- if (!closing) prompt();
70728
- return;
70729
- }
71708
+ if (input === "/model" || input === "/models") {
71709
+ await openModelSelector();
71710
+ return;
71711
+ }
71712
+ if (input.startsWith("/model ") || input.startsWith("/models ")) {
70730
71713
  const arg = input.replace(/^\/models?\s*/, "");
70731
71714
  try {
70732
- const result = await agent.setModelSelection(arg);
70733
- process.stdout.write(formatModelSelection(result));
70734
- awaitingModelSelection = !result.ok;
71715
+ printModelResult(await agent.setModelSelection(arg));
70735
71716
  } catch (err) {
70736
- process.stderr.write(
70737
- `
70738
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70739
- `
70740
- );
70741
- awaitingModelSelection = false;
71717
+ printFatal(err);
70742
71718
  }
70743
- if (!closing) prompt();
70744
71719
  return;
70745
71720
  }
70746
- if (!input) {
70747
- prompt();
70748
- return;
70749
- }
70750
- if (input === "/model" || input === "/models" || input.startsWith("/model ") || input.startsWith("/models ")) {
70751
- const arg = input.replace(/^\/models?\s*/, "");
71721
+ if (input === "/system") {
71722
+ const sysText = agent.getSystemPrompt();
71723
+ const audit = agent.getSystemPromptAudit();
71724
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
71725
+ const filePath = import_node_path9.default.join(
71726
+ desktopDir(),
71727
+ `clawfast-system-prompt_${stamp}.html`
71728
+ );
71729
+ const meta3 = `clawfast v${clawfastVersion()} \u2014 system prompt \xB7 gerado em ${(/* @__PURE__ */ new Date()).toLocaleString()} \xB7 ${audit.chars.toLocaleString()} chars \xB7 fonte ${audit.source} \xB7 verificado ${audit.requiredMarkersVerified ? "sim" : "nao"}`;
71730
+ const b64 = Buffer.from(sysText, "utf8").toString("base64");
71731
+ const html = `<!doctype html><html lang="pt-br"><head><meta charset="utf-8"><title>clawfast \u2014 system prompt</title><style>body{background:#0b0f0b;color:#bfffbf;font:14px/1.55 ui-monospace,Consolas,Menlo,monospace;margin:0;padding:28px}h1{color:#7CFC00;font-size:18px;margin:0 0 6px}.meta{color:#6f9a6f;margin:0 0 18px;font-size:12px}pre{white-space:pre-wrap;word-wrap:break-word;margin:0}</style></head><body><h1>clawfast \u2014 system prompt</h1><div class="meta">${meta3}</div><pre id="c"></pre><script>document.getElementById("c").textContent=decodeURIComponent(escape(atob("${b64}")));</script></body></html>`;
70752
71732
  try {
70753
- const result = await agent.setModelSelection(arg || "list");
70754
- awaitingModelSelection = !arg && result.ok;
71733
+ await (0, import_promises2.writeFile)(filePath, html, "utf8");
70755
71734
  process.stdout.write(
70756
- formatModelSelection(result, { choosing: awaitingModelSelection })
71735
+ `${C5.green}\u2713 system prompt salvo${C5.reset} ${C5.dim}(${sysText.length.toLocaleString()} caracteres \u2014 abra no navegador)${C5.reset}
71736
+ ${C5.cyan}${filePath}${C5.reset}
71737
+ `
70757
71738
  );
70758
71739
  } catch (err) {
70759
- process.stderr.write(
70760
- `
70761
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
71740
+ process.stdout.write(
71741
+ `${C5.red}\u2717 n\xE3o consegui salvar o arquivo:${C5.reset} ${err instanceof Error ? err.message : String(err)}
70762
71742
  `
70763
71743
  );
70764
- awaitingModelSelection = false;
70765
71744
  }
70766
- if (!closing) prompt();
70767
71745
  return;
70768
71746
  }
70769
- if (input === "/system") {
70770
- const sys2 = agent.getSystemPrompt();
70771
- const audit = agent.getSystemPromptAudit();
70772
- process.stdout.write(
70773
- `\x1B[90m\u2500\u2500\u2500\u2500 system prompt (${sys2.length.toLocaleString()} caracteres) \u2500\u2500\u2500\u2500\x1B[0m
70774
- `
70775
- );
70776
- process.stdout.write(
70777
- `\x1B[90mfonte: ${audit.source} | verificado: ${audit.requiredMarkersVerified ? "sim" : "nao"} | chars: ${audit.chars.toLocaleString()}${audit.dumpPath ? ` | dump: ${audit.dumpPath}` : ""}\x1B[0m
70778
- `
70779
- );
70780
- process.stdout.write(sys2 + "\n");
70781
- process.stdout.write(`\x1B[90m\u2500\u2500\u2500\u2500 fim do system prompt \u2500\u2500\u2500\u2500\x1B[0m
70782
- `);
70783
- if (!closing) prompt();
71747
+ if (input === "/api" || input.startsWith("/api ")) {
71748
+ await handleApiSwap(input.replace(/^\/api\s*/, "").trim());
70784
71749
  return;
70785
71750
  }
70786
71751
  if (input === "/nov" || input === "/novidades") {
70787
71752
  process.stdout.write(`
70788
- ${ui2.C.cyan}${renderNews(clawfastVersion())}${ui2.C.reset}
71753
+ ${renderNews(clawfastVersion())}
71754
+
70789
71755
  `);
70790
- if (!closing) prompt();
70791
71756
  return;
70792
71757
  }
71758
+ if (!input) return;
70793
71759
  process.stdout.write("\n" + agentHeader2());
70794
71760
  activeAbort = new AbortController();
70795
71761
  turnActive = true;
70796
- rl.resume();
71762
+ inputUI.beginTurn(
71763
+ (l) => {
71764
+ if (agent.isRunningCommand()) agent.sendStdin(l);
71765
+ },
71766
+ () => {
71767
+ if (exitArmed) {
71768
+ closing = true;
71769
+ activeAbort?.abort();
71770
+ return;
71771
+ }
71772
+ if (activeAbort && !activeAbort.signal.aborted) {
71773
+ activeAbort.abort();
71774
+ process.stdout.write(
71775
+ `
71776
+ ${C5.dim}interrompido \u2014 Ctrl+C de novo para fechar${C5.reset}
71777
+ `
71778
+ );
71779
+ }
71780
+ armExit();
71781
+ }
71782
+ );
70797
71783
  try {
70798
71784
  await agent.send(input, activeAbort.signal);
70799
71785
  } catch (err) {
70800
- process.stderr.write(
70801
- `
70802
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70803
- `
70804
- );
71786
+ printFatal(err);
70805
71787
  } finally {
71788
+ inputUI.endTurn();
70806
71789
  activeAbort = null;
70807
71790
  turnActive = false;
70808
71791
  }
70809
- if (!closing) prompt();
70810
71792
  };
70811
- prompt();
70812
- rl.on("line", (rawLine) => {
70813
- const line = pasteInput.expand(rawLine);
71793
+ process.removeAllListeners("SIGINT");
71794
+ process.on("SIGINT", () => {
70814
71795
  if (turnActive) {
70815
- if (agent.isRunningCommand()) {
70816
- agent.sendStdin(line);
70817
- }
71796
+ activeAbort?.abort();
70818
71797
  return;
70819
71798
  }
70820
- rl.pause();
70821
- commandQueue = commandQueue.then(() => handleLine(line)).catch((err) => {
70822
- process.stderr.write(
70823
- `
70824
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70825
- `
70826
- );
70827
- }).finally(() => {
70828
- if (!closing) rl.resume();
70829
- });
70830
- });
70831
- rl.on("close", async () => {
70832
- closing = true;
70833
- pasteInput.dispose();
70834
- await commandQueue.catch(() => void 0);
70835
- process.stdout.write("\nClosing sandbox...\n");
70836
- await agent.close();
70837
- process.exit(0);
71799
+ void shutdown();
70838
71800
  });
70839
71801
  process.on("exit", () => pasteInput.dispose());
70840
- }
70841
- function modelPrompt() {
70842
- return "\n\x1B[96m\x1B[1mmodelo\x1B[0m\x1B[92m\x1B[1m>\x1B[0m ";
70843
- }
70844
- function skillPrompt(phase) {
70845
- const label = phase === "name" ? "nome" : phase === "desc" ? "descricao" : phase === "triggers" ? "gatilhos" : "skill";
70846
- return `\x1B[96m\x1B[1m${label}\x1B[0m\x1B[92m\x1B[1m>\x1B[0m `;
70847
- }
70848
- function formatModelSelection(result, options = {}) {
70849
- const { C: C4 } = {
70850
- C: {
70851
- reset: "\x1B[0m",
70852
- bold: "\x1B[1m",
70853
- dim: "\x1B[90m",
70854
- green: "\x1B[32m",
70855
- cyan: "\x1B[36m",
70856
- yellow: "\x1B[33m",
70857
- red: "\x1B[31m"
71802
+ const currentSkillLabel = () => {
71803
+ if (!skillCreator) return void 0;
71804
+ switch (skillCreator.phase) {
71805
+ case "name":
71806
+ return "nome";
71807
+ case "desc":
71808
+ return "descri\xE7\xE3o";
71809
+ case "triggers":
71810
+ return "gatilhos";
71811
+ default:
71812
+ return "skill";
70858
71813
  }
70859
71814
  };
70860
- const statusColor = result.ok ? C4.green : C4.red;
70861
- const lines = [
70862
- `${statusColor}${result.ok ? "ok" : "erro"}${C4.reset} ${result.message}`,
70863
- `${C4.dim}modo atual:${C4.reset} ${result.selection.mode === "auto" ? `${C4.yellow}auto / fallback${C4.reset}` : `${C4.green}fixo${C4.reset}`}`,
70864
- "",
70865
- `${C4.cyan}${C4.bold}Modelos disponiveis${C4.reset}`
70866
- ];
70867
- for (const choice2 of result.selection.chain) {
70868
- const isActive = choice2.key === result.selection.activeModelKey;
70869
- const marker25 = isActive ? result.selection.mode === "fixed" ? "*" : ">" : " ";
70870
- lines.push(
70871
- `${marker25} ${choice2.index}. ${choice2.label} ${C4.dim}(${choice2.key})${C4.reset}`
70872
- );
70873
- }
70874
- if (result.selection.unavailable.length > 0) {
70875
- lines.push("", `${C4.yellow}${C4.bold}Indisponiveis${C4.reset}`);
70876
- for (const group of result.selection.unavailable) {
70877
- lines.push(`${group.provider}: ${C4.dim}${group.reason}${C4.reset}`);
70878
- for (const model of group.models) {
70879
- lines.push(` - ${model.label} ${C4.dim}(${model.key})${C4.reset}`);
71815
+ while (!closing) {
71816
+ const skillLabel = currentSkillLabel();
71817
+ const res = await inputUI.prompt(skillLabel ? { label: skillLabel } : {});
71818
+ if (closing) break;
71819
+ if (res.type === "eof") {
71820
+ closing = true;
71821
+ break;
71822
+ }
71823
+ if (res.type === "sigint") {
71824
+ if (exitArmed) {
71825
+ closing = true;
71826
+ break;
70880
71827
  }
71828
+ process.stdout.write(`${C5.dim}Ctrl+C de novo para fechar${C5.reset}
71829
+ `);
71830
+ armExit();
71831
+ continue;
71832
+ }
71833
+ if (!skillCreator && !res.value.trim()) continue;
71834
+ exitArmed = false;
71835
+ try {
71836
+ await handleLine(res.value);
71837
+ } catch (err) {
71838
+ printFatal(err);
70881
71839
  }
70882
71840
  }
70883
- lines.push(
70884
- "",
70885
- options.choosing ? `${C4.dim}Digite o numero, nome do modelo, auto para fallback, ou cancelar.${C4.reset}` : `${C4.dim}Use /model <numero> para fixar, /model auto para voltar ao fallback automatico.${C4.reset}`
70886
- );
70887
- return `
70888
- ${lines.join("\n")}
70889
- `;
71841
+ await shutdown();
70890
71842
  }
70891
- var import_node_readline3, deepseekEnabled, configuredModelProviders;
71843
+ var import_node_os6, import_node_path9, import_node_fs8, import_promises2, deepseekEnabled, configuredModelProviders;
70892
71844
  var init_index = __esm({
70893
71845
  "index.ts"() {
70894
71846
  "use strict";
70895
- import_node_readline3 = __toESM(require("node:readline"));
71847
+ import_node_os6 = __toESM(require("node:os"));
71848
+ import_node_path9 = __toESM(require("node:path"));
71849
+ import_node_fs8 = require("node:fs");
71850
+ import_promises2 = require("node:fs/promises");
70896
71851
  init_paste_input();
70897
71852
  init_boot_ui();
70898
71853
  init_config();