clawfast 1.0.3 → 2.0.0

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 +2 -2
  2. package/dist/clawfast.cjs +1282 -475
  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) {
@@ -502,7 +502,7 @@ var clawfastVersion, isDevVersion, isNewerVersion;
502
502
  var init_version = __esm({
503
503
  "src/version.ts"() {
504
504
  "use strict";
505
- clawfastVersion = () => true ? "1.0.3" : "0.0.0-dev";
505
+ clawfastVersion = () => true ? "2.0.0" : "0.0.0-dev";
506
506
  isDevVersion = () => clawfastVersion().includes("-dev");
507
507
  isNewerVersion = (a, b) => {
508
508
  const parse3 = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
@@ -699,14 +699,14 @@ var init_paste_input = __esm({
699
699
  /** Replace any paste chips in a submitted line with their real content. */
700
700
  expand(line) {
701
701
  if (this.pastes.size === 0) return line;
702
- let out2 = line;
702
+ let out3 = line;
703
703
  for (const [chip, content] of this.pastes) {
704
- if (out2.includes(chip)) {
705
- out2 = out2.split(chip).join(content);
704
+ if (out3.includes(chip)) {
705
+ out3 = out3.split(chip).join(content);
706
706
  this.pastes.delete(chip);
707
707
  }
708
708
  }
709
- return out2;
709
+ return out3;
710
710
  }
711
711
  /** How many captured pastes are still waiting to be expanded. */
712
712
  pendingCount() {
@@ -878,10 +878,18 @@ var init_news = __esm({
878
878
  import_node_path4 = __toESM(require("node:path"));
879
879
  init_config();
880
880
  NEWS = {
881
+ "2.0.0": [
882
+ '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.',
883
+ "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.",
884
+ "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.",
885
+ "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.",
886
+ "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.",
887
+ "Motor Python somente-leitura semeado a cada sessao (audit/project_audit.py); modo --focus mostra a vizinhanca de import de um arquivo especifico."
888
+ ],
881
889
  "1.0.3": [
882
890
  "Atualizacao: `clawfast update` atualiza o CLI e mostra as boas-vindas; aparece um aviso quando ha versao nova; /nov lista as novidades.",
883
891
  "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).",
892
+ "Modelos na NVIDIA build: mistral-medium-3.5, kimi-k2.6, glm-5.1 e qwen3.5-397b \u2014 todos com function calling de verdade (as ferramentas disparam).",
885
893
  "Resiliencia a rate limit (429): cai para os outros modelos como contingencia e espera/retenta a cadeia automaticamente."
886
894
  ]
887
895
  };
@@ -1505,10 +1513,10 @@ function mergeDefs(...defs) {
1505
1513
  function cloneDef(schema) {
1506
1514
  return mergeDefs(schema._zod.def);
1507
1515
  }
1508
- function getElementAtPath(obj, path8) {
1509
- if (!path8)
1516
+ function getElementAtPath(obj, path10) {
1517
+ if (!path10)
1510
1518
  return obj;
1511
- return path8.reduce((acc, key) => acc?.[key], obj);
1519
+ return path10.reduce((acc, key) => acc?.[key], obj);
1512
1520
  }
1513
1521
  function promiseAllObject(promisesObj) {
1514
1522
  const keys = Object.keys(promisesObj);
@@ -1836,11 +1844,11 @@ function explicitlyAborted(x, startIndex = 0) {
1836
1844
  }
1837
1845
  return false;
1838
1846
  }
1839
- function prefixIssues(path8, issues) {
1847
+ function prefixIssues(path10, issues) {
1840
1848
  return issues.map((iss) => {
1841
1849
  var _a25;
1842
1850
  (_a25 = iss).path ?? (_a25.path = []);
1843
- iss.path.unshift(path8);
1851
+ iss.path.unshift(path10);
1844
1852
  return iss;
1845
1853
  });
1846
1854
  }
@@ -2058,16 +2066,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
2058
2066
  }
2059
2067
  function formatError(error51, mapper = (issue2) => issue2.message) {
2060
2068
  const fieldErrors = { _errors: [] };
2061
- const processError = (error52, path8 = []) => {
2069
+ const processError = (error52, path10 = []) => {
2062
2070
  for (const issue2 of error52.issues) {
2063
2071
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2064
- issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
2072
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
2065
2073
  } else if (issue2.code === "invalid_key") {
2066
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
2074
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
2067
2075
  } else if (issue2.code === "invalid_element") {
2068
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
2076
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
2069
2077
  } else {
2070
- const fullpath = [...path8, ...issue2.path];
2078
+ const fullpath = [...path10, ...issue2.path];
2071
2079
  if (fullpath.length === 0) {
2072
2080
  fieldErrors._errors.push(mapper(issue2));
2073
2081
  } else {
@@ -2094,17 +2102,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
2094
2102
  }
2095
2103
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
2096
2104
  const result = { errors: [] };
2097
- const processError = (error52, path8 = []) => {
2105
+ const processError = (error52, path10 = []) => {
2098
2106
  var _a25, _b18;
2099
2107
  for (const issue2 of error52.issues) {
2100
2108
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2101
- issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
2109
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
2102
2110
  } else if (issue2.code === "invalid_key") {
2103
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
2111
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
2104
2112
  } else if (issue2.code === "invalid_element") {
2105
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
2113
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
2106
2114
  } else {
2107
- const fullpath = [...path8, ...issue2.path];
2115
+ const fullpath = [...path10, ...issue2.path];
2108
2116
  if (fullpath.length === 0) {
2109
2117
  result.errors.push(mapper(issue2));
2110
2118
  continue;
@@ -2136,8 +2144,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
2136
2144
  }
2137
2145
  function toDotPath(_path) {
2138
2146
  const segs = [];
2139
- const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2140
- for (const seg of path8) {
2147
+ const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2148
+ for (const seg of path10) {
2141
2149
  if (typeof seg === "number")
2142
2150
  segs.push(`[${seg}]`);
2143
2151
  else if (typeof seg === "symbol")
@@ -12449,11 +12457,11 @@ function _catch(Class2, innerType, catchValue) {
12449
12457
  });
12450
12458
  }
12451
12459
  // @__NO_SIDE_EFFECTS__
12452
- function _pipe(Class2, in_, out2) {
12460
+ function _pipe(Class2, in_, out3) {
12453
12461
  return new Class2({
12454
12462
  type: "pipe",
12455
12463
  in: in_,
12456
- out: out2
12464
+ out: out3
12457
12465
  });
12458
12466
  }
12459
12467
  // @__NO_SIDE_EFFECTS__
@@ -14689,19 +14697,19 @@ function _catch2(innerType, catchValue) {
14689
14697
  function nan(params) {
14690
14698
  return _nan(ZodNaN, params);
14691
14699
  }
14692
- function pipe(in_, out2) {
14700
+ function pipe(in_, out3) {
14693
14701
  return new ZodPipe({
14694
14702
  type: "pipe",
14695
14703
  in: in_,
14696
- out: out2
14704
+ out: out3
14697
14705
  // ...util.normalizeParams(params),
14698
14706
  });
14699
14707
  }
14700
- function codec(in_, out2, params) {
14708
+ function codec(in_, out3, params) {
14701
14709
  return new ZodCodec({
14702
14710
  type: "pipe",
14703
14711
  in: in_,
14704
- out: out2,
14712
+ out: out3,
14705
14713
  transform: params.decode,
14706
14714
  reverseTransform: params.encode
14707
14715
  });
@@ -15640,13 +15648,13 @@ function resolveRef(ref, ctx) {
15640
15648
  if (!ref.startsWith("#")) {
15641
15649
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
15642
15650
  }
15643
- const path8 = ref.slice(1).split("/").filter(Boolean);
15644
- if (path8.length === 0) {
15651
+ const path10 = ref.slice(1).split("/").filter(Boolean);
15652
+ if (path10.length === 0) {
15645
15653
  return ctx.rootSchema;
15646
15654
  }
15647
15655
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
15648
- if (path8[0] === defsKey) {
15649
- const key = path8[1];
15656
+ if (path10[0] === defsKey) {
15657
+ const key = path10[1];
15650
15658
  if (!key || !ctx.defs[key]) {
15651
15659
  throw new Error(`Reference not found: ${ref}`);
15652
15660
  }
@@ -16835,8 +16843,8 @@ var init_parseUtil = __esm({
16835
16843
  init_errors3();
16836
16844
  init_en2();
16837
16845
  makeIssue = (params) => {
16838
- const { data, path: path8, errorMaps, issueData } = params;
16839
- const fullPath = [...path8, ...issueData.path || []];
16846
+ const { data, path: path10, errorMaps, issueData } = params;
16847
+ const fullPath = [...path10, ...issueData.path || []];
16840
16848
  const fullIssue = {
16841
16849
  ...issueData,
16842
16850
  path: fullPath
@@ -17119,11 +17127,11 @@ var init_types = __esm({
17119
17127
  init_parseUtil();
17120
17128
  init_util2();
17121
17129
  ParseInputLazyPath = class {
17122
- constructor(parent, value, path8, key) {
17130
+ constructor(parent, value, path10, key) {
17123
17131
  this._cachedPath = [];
17124
17132
  this.parent = parent;
17125
17133
  this.data = value;
17126
- this._path = path8;
17134
+ this._path = path10;
17127
17135
  this._key = key;
17128
17136
  }
17129
17137
  get path() {
@@ -23163,7 +23171,7 @@ var require_auth_config = __commonJS({
23163
23171
  });
23164
23172
  module2.exports = __toCommonJS(auth_config_exports);
23165
23173
  var fs6 = __toESM2(require("fs"));
23166
- var path8 = __toESM2(require("path"));
23174
+ var path10 = __toESM2(require("path"));
23167
23175
  var import_token_util = require_token_util();
23168
23176
  function getAuthConfigPath() {
23169
23177
  const dataDir = (0, import_token_util.getVercelDataDir)();
@@ -23172,7 +23180,7 @@ var require_auth_config = __commonJS({
23172
23180
  `Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`
23173
23181
  );
23174
23182
  }
23175
- return path8.join(dataDir, "auth.json");
23183
+ return path10.join(dataDir, "auth.json");
23176
23184
  }
23177
23185
  function readAuthConfig() {
23178
23186
  try {
@@ -23191,7 +23199,7 @@ var require_auth_config = __commonJS({
23191
23199
  }
23192
23200
  function writeAuthConfig(config3) {
23193
23201
  const authPath = getAuthConfigPath();
23194
- const authDir = path8.dirname(authPath);
23202
+ const authDir = path10.dirname(authPath);
23195
23203
  if (!fs6.existsSync(authDir)) {
23196
23204
  fs6.mkdirSync(authDir, { mode: 504, recursive: true });
23197
23205
  }
@@ -23386,7 +23394,7 @@ var require_token_util = __commonJS({
23386
23394
  saveToken: () => saveToken
23387
23395
  });
23388
23396
  module2.exports = __toCommonJS(token_util_exports);
23389
- var path8 = __toESM2(require("path"));
23397
+ var path10 = __toESM2(require("path"));
23390
23398
  var fs6 = __toESM2(require("fs"));
23391
23399
  var import_token_error = require_token_error();
23392
23400
  var import_token_io = require_token_io();
@@ -23399,7 +23407,7 @@ var require_token_util = __commonJS({
23399
23407
  if (!dataDir) {
23400
23408
  return null;
23401
23409
  }
23402
- return path8.join(dataDir, vercelFolder);
23410
+ return path10.join(dataDir, vercelFolder);
23403
23411
  }
23404
23412
  async function getVercelToken2(options) {
23405
23413
  const authConfig = (0, import_auth_config.readAuthConfig)();
@@ -23475,7 +23483,7 @@ var require_token_util = __commonJS({
23475
23483
  "Unable to find project root directory. Have you linked your project with `vc link?`"
23476
23484
  );
23477
23485
  }
23478
- const prjPath = path8.join(dir, ".vercel", "project.json");
23486
+ const prjPath = path10.join(dir, ".vercel", "project.json");
23479
23487
  if (!fs6.existsSync(prjPath)) {
23480
23488
  throw new import_token_error.VercelOidcTokenError(
23481
23489
  "project.json not found, have you linked your project with `vc link?`"
@@ -23496,9 +23504,9 @@ var require_token_util = __commonJS({
23496
23504
  "Unable to find user data directory. Please reach out to Vercel support."
23497
23505
  );
23498
23506
  }
23499
- const tokenPath = path8.join(dir, "com.vercel.token", `${projectId}.json`);
23507
+ const tokenPath = path10.join(dir, "com.vercel.token", `${projectId}.json`);
23500
23508
  const tokenJson = JSON.stringify(token);
23501
- fs6.mkdirSync(path8.dirname(tokenPath), { mode: 504, recursive: true });
23509
+ fs6.mkdirSync(path10.dirname(tokenPath), { mode: 504, recursive: true });
23502
23510
  fs6.writeFileSync(tokenPath, tokenJson);
23503
23511
  fs6.chmodSync(tokenPath, 432);
23504
23512
  return;
@@ -23510,7 +23518,7 @@ var require_token_util = __commonJS({
23510
23518
  "Unable to find user data directory. Please reach out to Vercel support."
23511
23519
  );
23512
23520
  }
23513
- const tokenPath = path8.join(dir, "com.vercel.token", `${projectId}.json`);
23521
+ const tokenPath = path10.join(dir, "com.vercel.token", `${projectId}.json`);
23514
23522
  if (!fs6.existsSync(tokenPath)) {
23515
23523
  return null;
23516
23524
  }
@@ -35540,7 +35548,7 @@ function createOpenRouter(options = {}) {
35540
35548
  );
35541
35549
  const createChatModel = (modelId, settings = {}) => new OpenRouterChatLanguageModel(modelId, settings, {
35542
35550
  provider: "openrouter.chat",
35543
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35551
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35544
35552
  headers: getHeaders,
35545
35553
  compatibility,
35546
35554
  fetch: options.fetch,
@@ -35548,7 +35556,7 @@ function createOpenRouter(options = {}) {
35548
35556
  });
35549
35557
  const createCompletionModel = (modelId, settings = {}) => new OpenRouterCompletionLanguageModel(modelId, settings, {
35550
35558
  provider: "openrouter.completion",
35551
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35559
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35552
35560
  headers: getHeaders,
35553
35561
  compatibility,
35554
35562
  fetch: options.fetch,
@@ -35556,21 +35564,21 @@ function createOpenRouter(options = {}) {
35556
35564
  });
35557
35565
  const createEmbeddingModel = (modelId, settings = {}) => new OpenRouterEmbeddingModel(modelId, settings, {
35558
35566
  provider: "openrouter.embedding",
35559
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35567
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35560
35568
  headers: getHeaders,
35561
35569
  fetch: options.fetch,
35562
35570
  extraBody: options.extraBody
35563
35571
  });
35564
35572
  const createImageModel = (modelId, settings = {}) => new OpenRouterImageModel(modelId, settings, {
35565
35573
  provider: "openrouter.image",
35566
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35574
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35567
35575
  headers: getHeaders,
35568
35576
  fetch: options.fetch,
35569
35577
  extraBody: options.extraBody
35570
35578
  });
35571
35579
  const createVideoModel = (modelId, settings = {}) => new OpenRouterVideoModel(modelId, settings, {
35572
35580
  provider: "openrouter.video",
35573
- url: ({ path: path8 }) => `${baseURL}${path8}`,
35581
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35574
35582
  headers: getHeaders,
35575
35583
  fetch: options.fetch,
35576
35584
  extraBody: options.extraBody
@@ -40106,37 +40114,37 @@ function createOpenAI(options = {}) {
40106
40114
  );
40107
40115
  const createChatModel = (modelId) => new OpenAIChatLanguageModel(modelId, {
40108
40116
  provider: `${providerName}.chat`,
40109
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40117
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40110
40118
  headers: getHeaders,
40111
40119
  fetch: options.fetch
40112
40120
  });
40113
40121
  const createCompletionModel = (modelId) => new OpenAICompletionLanguageModel(modelId, {
40114
40122
  provider: `${providerName}.completion`,
40115
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40123
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40116
40124
  headers: getHeaders,
40117
40125
  fetch: options.fetch
40118
40126
  });
40119
40127
  const createEmbeddingModel = (modelId) => new OpenAIEmbeddingModel(modelId, {
40120
40128
  provider: `${providerName}.embedding`,
40121
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40129
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40122
40130
  headers: getHeaders,
40123
40131
  fetch: options.fetch
40124
40132
  });
40125
40133
  const createImageModel = (modelId) => new OpenAIImageModel(modelId, {
40126
40134
  provider: `${providerName}.image`,
40127
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40135
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40128
40136
  headers: getHeaders,
40129
40137
  fetch: options.fetch
40130
40138
  });
40131
40139
  const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
40132
40140
  provider: `${providerName}.transcription`,
40133
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40141
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40134
40142
  headers: getHeaders,
40135
40143
  fetch: options.fetch
40136
40144
  });
40137
40145
  const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
40138
40146
  provider: `${providerName}.speech`,
40139
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40147
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40140
40148
  headers: getHeaders,
40141
40149
  fetch: options.fetch
40142
40150
  });
@@ -40151,7 +40159,7 @@ function createOpenAI(options = {}) {
40151
40159
  const createResponsesModel = (modelId) => {
40152
40160
  return new OpenAIResponsesLanguageModel(modelId, {
40153
40161
  provider: `${providerName}.responses`,
40154
- url: ({ path: path8 }) => `${baseURL}${path8}`,
40162
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
40155
40163
  headers: getHeaders,
40156
40164
  fetch: options.fetch,
40157
40165
  fileIdPrefixes: ["file-"]
@@ -45372,7 +45380,7 @@ function supportsMultimodalToolResults(modelName) {
45372
45380
  const normalized = modelName.toLowerCase();
45373
45381
  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
45382
  }
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;
45383
+ 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
45384
  var init_providers = __esm({
45377
45385
  "../lib/ai/providers.ts"() {
45378
45386
  "use strict";
@@ -45532,10 +45540,43 @@ var init_providers = __esm({
45532
45540
  name: "openai",
45533
45541
  apiKey: process.env.OPENAI_API_KEY
45534
45542
  });
45543
+ isNvidiaMistralModel = (value) => typeof value === "string" && value.toLowerCase().startsWith("mistralai/mistral");
45544
+ applyNvidiaMistralConfig = (body) => {
45545
+ if (!isRecord(body) || !isNvidiaMistralModel(body.model)) {
45546
+ return { body, changed: false };
45547
+ }
45548
+ return {
45549
+ body: {
45550
+ ...body,
45551
+ reasoning_effort: "none",
45552
+ temperature: 1,
45553
+ top_p: 1,
45554
+ max_tokens: 16384
45555
+ },
45556
+ changed: true
45557
+ };
45558
+ };
45559
+ nvidiaPatchFetch = async (url2, init) => {
45560
+ if (init?.body && typeof init.body === "string") {
45561
+ try {
45562
+ const parsed = JSON.parse(init.body);
45563
+ const patched = applyNvidiaMistralConfig(parsed);
45564
+ if (patched.changed) {
45565
+ return globalThis.fetch(url2, {
45566
+ ...init,
45567
+ body: JSON.stringify(patched.body)
45568
+ });
45569
+ }
45570
+ } catch {
45571
+ }
45572
+ }
45573
+ return globalThis.fetch(url2, init);
45574
+ };
45535
45575
  nvidia = createOpenAI({
45536
45576
  name: "nvidia",
45537
45577
  baseURL: process.env.NVIDIA_BASE_URL || "https://integrate.api.nvidia.com/v1",
45538
- apiKey: process.env.NVIDIA_API_KEY
45578
+ apiKey: process.env.NVIDIA_API_KEY,
45579
+ fetch: nvidiaPatchFetch
45539
45580
  });
45540
45581
  deepseek = createOpenAI({
45541
45582
  name: "deepseek",
@@ -45563,7 +45604,9 @@ var init_providers = __esm({
45563
45604
  "model-opus-4.6": nvidia("nvidia/nemotron-3-ultra-550b-a55b"),
45564
45605
  "model-kimi-k2.6": or("qwen/qwen3-coder:free"),
45565
45606
  // NVIDIA build models — primary provider for the local CLI (chat-completions).
45566
- "model-nvidia-minimax-m3": nvidia.chat("minimaxai/minimax-m3"),
45607
+ "model-nvidia-mistral-medium-3.5": nvidia.chat(
45608
+ "mistralai/mistral-medium-3.5-128b"
45609
+ ),
45567
45610
  "model-nvidia-kimi-k2.6": nvidia.chat("moonshotai/kimi-k2.6"),
45568
45611
  "model-nvidia-glm-5.1": nvidia.chat("z-ai/glm-5.1"),
45569
45612
  "model-nvidia-qwen3.5-397b": nvidia.chat("qwen/qwen3.5-397b-a17b"),
@@ -45600,8 +45643,8 @@ var init_providers = __esm({
45600
45643
  };
45601
45644
  CLI_MODEL_CHAIN = [
45602
45645
  ...hasEnvValue("NVIDIA_API_KEY") ? [
45603
- "model-nvidia-minimax-m3",
45604
- // NVIDIA minimaxai/minimax-m3
45646
+ "model-nvidia-mistral-medium-3.5",
45647
+ // NVIDIA mistralai/mistral-medium-3.5-128b
45605
45648
  "model-nvidia-kimi-k2.6",
45606
45649
  // NVIDIA moonshotai/kimi-k2.6
45607
45650
  "model-nvidia-glm-5.1",
@@ -45628,7 +45671,7 @@ var init_providers = __esm({
45628
45671
  "model-deepseek-v4-flash": "May 2025",
45629
45672
  "model-opus-4.6": "May 2025",
45630
45673
  "model-kimi-k2.6": "April 2024",
45631
- "model-nvidia-minimax-m3": "Unknown",
45674
+ "model-nvidia-mistral-medium-3.5": "Unknown",
45632
45675
  "model-nvidia-kimi-k2.6": "April 2024",
45633
45676
  "model-nvidia-glm-5.1": "Unknown",
45634
45677
  "model-nvidia-qwen3.5-397b": "Unknown",
@@ -45652,7 +45695,7 @@ var init_providers = __esm({
45652
45695
  "model-deepseek-v4-flash": "DeepSeek V4 Flash",
45653
45696
  "model-opus-4.6": "Anthropic Claude Opus 4.6",
45654
45697
  "model-kimi-k2.6": "Moonshot Kimi K2.6",
45655
- "model-nvidia-minimax-m3": "NVIDIA - MiniMax M3",
45698
+ "model-nvidia-mistral-medium-3.5": "NVIDIA - Mistral Medium 3.5",
45656
45699
  "model-nvidia-kimi-k2.6": "NVIDIA - Moonshot Kimi K2.6",
45657
45700
  "model-nvidia-glm-5.1": "NVIDIA - Z.ai GLM 5.1",
45658
45701
  "model-nvidia-qwen3.5-397b": "NVIDIA - Qwen3.5 397B A17B",
@@ -48687,8 +48730,8 @@ var init_background_process_tracker = __esm({
48687
48730
  /**
48688
48731
  * Normalize file path for comparison
48689
48732
  */
48690
- normalizePath(path8) {
48691
- let normalized = path8.trim().replace(/\/+/g, "/");
48733
+ normalizePath(path10) {
48734
+ let normalized = path10.trim().replace(/\/+/g, "/");
48692
48735
  if (normalized.startsWith("./")) {
48693
48736
  normalized = normalized.slice(2);
48694
48737
  }
@@ -48926,8 +48969,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
48926
48969
  return decodedFile;
48927
48970
  };
48928
48971
  }
48929
- function normalizeWindowsPath(path8) {
48930
- return path8.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
48972
+ function normalizeWindowsPath(path10) {
48973
+ return path10.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
48931
48974
  }
48932
48975
  var import_path;
48933
48976
  var init_module_node = __esm({
@@ -51816,9 +51859,9 @@ async function addSourceContext(frames) {
51816
51859
  LRU_FILE_CONTENTS_CACHE.reduce();
51817
51860
  return frames;
51818
51861
  }
51819
- function getContextLinesFromFile(path8, ranges, output) {
51862
+ function getContextLinesFromFile(path10, ranges, output) {
51820
51863
  return new Promise((resolve2) => {
51821
- const stream = (0, import_node_fs5.createReadStream)(path8);
51864
+ const stream = (0, import_node_fs5.createReadStream)(path10);
51822
51865
  const lineReaded = (0, import_node_readline2.createInterface)({
51823
51866
  input: stream
51824
51867
  });
@@ -51833,7 +51876,7 @@ function getContextLinesFromFile(path8, ranges, output) {
51833
51876
  let rangeStart = range[0];
51834
51877
  let rangeEnd = range[1];
51835
51878
  function onStreamError() {
51836
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path8, 1);
51879
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path10, 1);
51837
51880
  lineReaded.close();
51838
51881
  lineReaded.removeAllListeners();
51839
51882
  destroyStreamAndResolve();
@@ -51894,8 +51937,8 @@ function clearLineContext(frame2) {
51894
51937
  delete frame2.context_line;
51895
51938
  delete frame2.post_context;
51896
51939
  }
51897
- function shouldSkipContextLinesForFile(path8) {
51898
- return path8.startsWith("node:") || path8.endsWith(".min.js") || path8.endsWith(".min.cjs") || path8.endsWith(".min.mjs") || path8.startsWith("data:");
51940
+ function shouldSkipContextLinesForFile(path10) {
51941
+ return path10.startsWith("node:") || path10.endsWith(".min.js") || path10.endsWith(".min.cjs") || path10.endsWith(".min.mjs") || path10.startsWith("data:");
51899
51942
  }
51900
51943
  function shouldSkipContextLinesForFrame(frame2) {
51901
51944
  if (void 0 !== frame2.lineno && frame2.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -51914,22 +51957,22 @@ function makeLineReaderRanges(lines) {
51914
51957
  const line = lines[0];
51915
51958
  if ("number" != typeof line) return [];
51916
51959
  let current = makeContextRange(line);
51917
- const out2 = [];
51960
+ const out3 = [];
51918
51961
  while (true) {
51919
51962
  if (i === lines.length - 1) {
51920
- out2.push(current);
51963
+ out3.push(current);
51921
51964
  break;
51922
51965
  }
51923
51966
  const next = lines[i + 1];
51924
51967
  if ("number" != typeof next) break;
51925
51968
  if (next <= current[1]) current[1] = next + DEFAULT_LINES_OF_CONTEXT;
51926
51969
  else {
51927
- out2.push(current);
51970
+ out3.push(current);
51928
51971
  current = makeContextRange(next);
51929
51972
  }
51930
51973
  i++;
51931
51974
  }
51932
- return out2;
51975
+ return out3;
51933
51976
  }
51934
51977
  function makeContextRange(line) {
51935
51978
  return [
@@ -55447,8 +55490,8 @@ async function createE2BPtyHandle(sandbox, opts) {
55447
55490
  sendInput(bytes) {
55448
55491
  return pty.sendInput(pid, bytes);
55449
55492
  },
55450
- async resize(cols, rows) {
55451
- await pty.resize(pid, { cols, rows });
55493
+ async resize(cols2, rows) {
55494
+ await pty.resize(pid, { cols: cols2, rows });
55452
55495
  },
55453
55496
  async kill() {
55454
55497
  const killed = await pty.kill(pid);
@@ -55589,9 +55632,9 @@ var init_pty_session_manager = __esm({
55589
55632
  consumeDelta(session) {
55590
55633
  const total = this.totalBufferBytes(session);
55591
55634
  const start = Math.min(session.readCursor, total);
55592
- const out2 = this.sliceBuffer(session, start, total);
55635
+ const out3 = this.sliceBuffer(session, start, total);
55593
55636
  session.readCursor = total;
55594
- return out2;
55637
+ return out3;
55595
55638
  }
55596
55639
  /**
55597
55640
  * Returns the full accumulated buffer without advancing `readCursor`.
@@ -55649,7 +55692,7 @@ var init_pty_session_manager = __esm({
55649
55692
  }
55650
55693
  sliceBuffer(session, start, end) {
55651
55694
  if (end <= start) return new Uint8Array(0);
55652
- const out2 = new Uint8Array(end - start);
55695
+ const out3 = new Uint8Array(end - start);
55653
55696
  let outOffset = 0;
55654
55697
  let cursor = 0;
55655
55698
  for (const chunk of session.buffer) {
@@ -55662,11 +55705,11 @@ var init_pty_session_manager = __esm({
55662
55705
  if (chunkStart >= end) break;
55663
55706
  const sliceStart = Math.max(0, start - chunkStart);
55664
55707
  const sliceEnd = Math.min(chunk.byteLength, end - chunkStart);
55665
- out2.set(chunk.subarray(sliceStart, sliceEnd), outOffset);
55708
+ out3.set(chunk.subarray(sliceStart, sliceEnd), outOffset);
55666
55709
  outOffset += sliceEnd - sliceStart;
55667
55710
  cursor = chunkEnd;
55668
55711
  }
55669
- return out2;
55712
+ return out3;
55670
55713
  }
55671
55714
  async killAndRemove(session, _reason) {
55672
55715
  if (session.closing) {
@@ -55924,7 +55967,7 @@ var require_xterm_headless = __commonJS({
55924
55967
  };
55925
55968
  Object.defineProperty(t2, "__esModule", { value: true }), t2.InputHandler = t2.WindowsOptionsReportType = void 0, t2.isValidColorIndex = k;
55926
55969
  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) {
55970
+ function C5(e3, t3) {
55928
55971
  if (e3 > 24) return t3.setWinLines || false;
55929
55972
  switch (e3) {
55930
55973
  case 1:
@@ -56059,7 +56102,7 @@ var require_xterm_headless = __commonJS({
56059
56102
  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
56103
  }
56061
56104
  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)));
56105
+ 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
56106
  }
56064
56107
  registerDcsHandler(e3, t3) {
56065
56108
  return this._parser.registerDcsHandler(e3, new v.DcsHandler(t3));
@@ -56573,7 +56616,7 @@ var require_xterm_headless = __commonJS({
56573
56616
  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
56617
  }
56575
56618
  windowOptions(e3) {
56576
- if (!C4(e3.params[0], this._optionsService.rawOptions.windowOptions)) return true;
56619
+ if (!C5(e3.params[0], this._optionsService.rawOptions.windowOptions)) return true;
56577
56620
  const t3 = e3.length > 1 ? e3.params[1] : 0;
56578
56621
  switch (e3.params[0]) {
56579
56622
  case 14:
@@ -61700,12 +61743,12 @@ function applyDelta(source, delta) {
61700
61743
  zDelta.pos += cnt;
61701
61744
  break;
61702
61745
  case ";": {
61703
- const out2 = zOut.toByteArray(source);
61704
- if (cnt !== checksum(out2))
61746
+ const out3 = zOut.toByteArray(source);
61747
+ if (cnt !== checksum(out3))
61705
61748
  throw new Error("bad checksum");
61706
61749
  if (total !== limit)
61707
61750
  throw new Error("generated size does not match predicted size");
61708
- return out2;
61751
+ return out3;
61709
61752
  }
61710
61753
  default:
61711
61754
  throw new Error("unknown delta operator");
@@ -66279,11 +66322,11 @@ async function createCentrifugoPtyHandle(sandbox, opts) {
66279
66322
  };
66280
66323
  await publish(payload);
66281
66324
  },
66282
- async resize(cols, rows) {
66325
+ async resize(cols2, rows) {
66283
66326
  const payload = {
66284
66327
  type: "pty_resize",
66285
66328
  sessionId,
66286
- cols,
66329
+ cols: cols2,
66287
66330
  rows,
66288
66331
  targetConnectionId: connectionId
66289
66332
  };
@@ -66518,7 +66561,7 @@ In using these tools, adhere to the following guidelines:
66518
66561
  timeout,
66519
66562
  interactive
66520
66563
  }, { toolCallId, abortSignal }) => {
66521
- const cols = DEFAULT_PTY_COLS;
66564
+ const cols2 = DEFAULT_PTY_COLS;
66522
66565
  const rows = DEFAULT_PTY_ROWS;
66523
66566
  let activePtySessionId;
66524
66567
  let emitQueue = Promise.resolve();
@@ -66613,20 +66656,20 @@ In using these tools, adhere to the following guidelines:
66613
66656
  }
66614
66657
  }
66615
66658
  const session = await ptySessionManager2.create(chatId, {
66616
- cols,
66659
+ cols: cols2,
66617
66660
  rows,
66618
66661
  createHandle: async () => {
66619
66662
  if (isCentrifugo) {
66620
66663
  const { createCentrifugoPtyHandle: createCentrifugoPtyHandle2 } = await Promise.resolve().then(() => (init_centrifugo_pty_adapter(), centrifugo_pty_adapter_exports));
66621
66664
  return createCentrifugoPtyHandle2(sandbox, {
66622
66665
  command,
66623
- cols,
66666
+ cols: cols2,
66624
66667
  rows,
66625
66668
  envs: caidoEnvVars
66626
66669
  });
66627
66670
  }
66628
66671
  return createE2BPtyHandle(sandbox, {
66629
- cols,
66672
+ cols: cols2,
66630
66673
  rows,
66631
66674
  envs: caidoEnvVars
66632
66675
  });
@@ -67305,8 +67348,8 @@ var init_logger2 = __esm({
67305
67348
  });
67306
67349
 
67307
67350
  // ../lib/ai/tools/file.ts
67308
- function isSpritPath(path8) {
67309
- return path8.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
67351
+ function isSpritPath(path10) {
67352
+ return path10.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
67310
67353
  }
67311
67354
  function getViewSandboxType(sandbox) {
67312
67355
  return isCentrifugoSandbox(sandbox) ? "centrifugo" : "e2b";
@@ -67337,7 +67380,7 @@ function captureFileViewImageUsage(args) {
67337
67380
  const {
67338
67381
  context: context2,
67339
67382
  sandbox,
67340
- path: path8,
67383
+ path: path10,
67341
67384
  outcome,
67342
67385
  durationMs,
67343
67386
  mediaType,
@@ -67355,7 +67398,7 @@ function captureFileViewImageUsage(args) {
67355
67398
  model: getActiveModelName(context2),
67356
67399
  configured_model: context2.modelName,
67357
67400
  sandbox_type: getViewSandboxType(sandbox),
67358
- file_extension: getFileExtension(path8),
67401
+ file_extension: getFileExtension(path10),
67359
67402
  outcome,
67360
67403
  success: outcome === "success",
67361
67404
  duration_ms: durationMs,
@@ -67429,22 +67472,22 @@ async function runSandboxCommand(sandbox, command, envVars, timeoutMs = 6e4) {
67429
67472
  function isWindowsSandbox(sandbox) {
67430
67473
  return isCentrifugoSandbox(sandbox) && sandbox.isWindows();
67431
67474
  }
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, "\\")}`;
67475
+ function getWindowsNativePath(path10) {
67476
+ if (/^[A-Za-z]:[\\/]/.test(path10)) return path10;
67477
+ if (path10.startsWith("/tmp/")) {
67478
+ return `C:\\temp${path10.slice(4).replace(/\//g, "\\")}`;
67436
67479
  }
67437
- return path8.replace(/\//g, "\\");
67480
+ return path10.replace(/\//g, "\\");
67438
67481
  }
67439
- function getPythonPathForSandbox(sandbox, path8) {
67440
- return isWindowsSandbox(sandbox) ? getWindowsNativePath(path8) : path8;
67482
+ function getPythonPathForSandbox(sandbox, path10) {
67483
+ return isWindowsSandbox(sandbox) ? getWindowsNativePath(path10) : path10;
67441
67484
  }
67442
- function toWindowsBashPath(path8) {
67443
- const drive = path8.match(/^([A-Za-z]):[\\/](.*)$/);
67485
+ function toWindowsBashPath(path10) {
67486
+ const drive = path10.match(/^([A-Za-z]):[\\/](.*)$/);
67444
67487
  if (drive) {
67445
67488
  return `/${drive[1].toLowerCase()}/${drive[2].replace(/\\/g, "/")}`;
67446
67489
  }
67447
- return path8.replace(/\\/g, "/");
67490
+ return path10.replace(/\\/g, "/");
67448
67491
  }
67449
67492
  async function detectSandboxShell(sandbox) {
67450
67493
  if (!isWindowsSandbox(sandbox)) return "bash";
@@ -67483,8 +67526,8 @@ PY`;
67483
67526
  }
67484
67527
  }
67485
67528
  }
67486
- async function getSandboxFileState(sandbox, path8) {
67487
- const pythonPath = getPythonPathForSandbox(sandbox, path8);
67529
+ async function getSandboxFileState(sandbox, path10) {
67530
+ const pythonPath = getPythonPathForSandbox(sandbox, path10);
67488
67531
  const result = await runPythonScript(
67489
67532
  sandbox,
67490
67533
  FILE_STATE_SCRIPT,
@@ -67501,23 +67544,23 @@ async function getSandboxFileState(sandbox, path8) {
67501
67544
  if (result.exitCode !== 0) {
67502
67545
  return {
67503
67546
  kind: "unknown",
67504
- path: path8,
67547
+ path: path10,
67505
67548
  error: result.stderr || result.stdout || "file state command failed"
67506
67549
  };
67507
67550
  }
67508
67551
  try {
67509
67552
  const payload = JSON.parse(result.stdout.trim());
67510
67553
  if (payload.kind === "file" && typeof payload.sizeBytes === "number" && Number.isFinite(payload.sizeBytes)) {
67511
- return { ...payload, path: path8 };
67554
+ return { ...payload, path: path10 };
67512
67555
  }
67513
67556
  if (payload.kind === "missing" || payload.kind === "not_file") {
67514
- return { ...payload, path: path8 };
67557
+ return { ...payload, path: path10 };
67515
67558
  }
67516
67559
  } catch {
67517
67560
  }
67518
67561
  return {
67519
67562
  kind: "unknown",
67520
- path: path8,
67563
+ path: path10,
67521
67564
  error: result.stderr || result.stdout || "invalid file state response"
67522
67565
  };
67523
67566
  }
@@ -67549,8 +67592,8 @@ ${numberedContent}${truncatedNotice}${footerNotice}`;
67549
67592
  })
67550
67593
  };
67551
67594
  }
67552
- async function readSandboxTextFile(sandbox, path8, range) {
67553
- const pythonPath = getPythonPathForSandbox(sandbox, path8);
67595
+ async function readSandboxTextFile(sandbox, path10, range) {
67596
+ const pythonPath = getPythonPathForSandbox(sandbox, path10);
67554
67597
  const envVars = {
67555
67598
  HACKERAI_FILE_READ_PATH: pythonPath,
67556
67599
  HACKERAI_FILE_READ_RANGE_START: String(range?.[0] ?? 0),
@@ -67578,40 +67621,40 @@ async function readSandboxTextFile(sandbox, path8, range) {
67578
67621
  }
67579
67622
  return payload;
67580
67623
  }
67581
- async function readSandboxTextFileWithFallback(sandbox, path8, range) {
67624
+ async function readSandboxTextFileWithFallback(sandbox, path10, range) {
67582
67625
  try {
67583
- return await readSandboxTextFile(sandbox, path8, range);
67626
+ return await readSandboxTextFile(sandbox, path10, range);
67584
67627
  } catch (error51) {
67585
67628
  const errorMessage = error51 instanceof Error ? error51.message : String(error51);
67586
67629
  if (errorMessage.startsWith("Invalid ") || errorMessage.includes("File not found")) {
67587
67630
  throw error51;
67588
67631
  }
67589
- const state = await getSandboxFileState(sandbox, path8);
67632
+ const state = await getSandboxFileState(sandbox, path10);
67590
67633
  if (state.kind === "unknown") {
67591
67634
  throw new Error(
67592
- `Unable to determine file size for ${path8}; refusing to load the file into memory. ${state.error}`
67635
+ `Unable to determine file size for ${path10}; refusing to load the file into memory. ${state.error}`
67593
67636
  );
67594
67637
  }
67595
67638
  if (state.kind === "missing") {
67596
- throw new Error(`File not found or is not a regular file: ${path8}`);
67639
+ throw new Error(`File not found or is not a regular file: ${path10}`);
67597
67640
  }
67598
67641
  if (state.kind === "not_file") {
67599
- throw new Error(`File is not a regular file: ${path8}`);
67642
+ throw new Error(`File is not a regular file: ${path10}`);
67600
67643
  }
67601
67644
  if (state.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
67602
67645
  if (range) {
67603
67646
  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.`
67647
+ `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
67648
  );
67606
67649
  }
67607
67650
  return {
67608
- path: path8,
67651
+ path: path10,
67609
67652
  sizeBytes: state.sizeBytes,
67610
67653
  totalLines: 0,
67611
67654
  tooLarge: true
67612
67655
  };
67613
67656
  }
67614
- const fileContent = await sandbox.files.read(path8, {
67657
+ const fileContent = await sandbox.files.read(path10, {
67615
67658
  user: "user"
67616
67659
  });
67617
67660
  const lines = fileContent.split("\n");
@@ -67640,7 +67683,7 @@ async function readSandboxTextFileWithFallback(sandbox, path8, range) {
67640
67683
  const startIndex = start - 1;
67641
67684
  const endIndex = end === -1 ? lines.length : end;
67642
67685
  return {
67643
- path: path8,
67686
+ path: path10,
67644
67687
  sizeBytes: Buffer.byteLength(fileContent),
67645
67688
  totalLines: lines.length,
67646
67689
  content: lines.slice(startIndex, endIndex).join("\n"),
@@ -67648,7 +67691,7 @@ async function readSandboxTextFileWithFallback(sandbox, path8, range) {
67648
67691
  };
67649
67692
  }
67650
67693
  return {
67651
- path: path8,
67694
+ path: path10,
67652
67695
  sizeBytes: Buffer.byteLength(fileContent),
67653
67696
  totalLines: lines.length,
67654
67697
  content: fileContent,
@@ -67656,7 +67699,7 @@ async function readSandboxTextFileWithFallback(sandbox, path8, range) {
67656
67699
  };
67657
67700
  }
67658
67701
  }
67659
- async function appendSandboxTextFile(sandbox, path8, text2) {
67702
+ async function appendSandboxTextFile(sandbox, path10, text2) {
67660
67703
  const tempPath = `/tmp/hackerai_append_${Date.now()}_${Math.random().toString(36).slice(2)}.tmp`;
67661
67704
  await sandbox.files.write(tempPath, text2, {
67662
67705
  user: "user"
@@ -67665,7 +67708,7 @@ async function appendSandboxTextFile(sandbox, path8, text2) {
67665
67708
  sandbox,
67666
67709
  APPEND_TEXT_FILE_SCRIPT,
67667
67710
  {
67668
- HACKERAI_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path8),
67711
+ HACKERAI_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path10),
67669
67712
  HACKERAI_FILE_APPEND_SOURCE_PATH: getPythonPathForSandbox(
67670
67713
  sandbox,
67671
67714
  tempPath
@@ -67677,13 +67720,13 @@ async function appendSandboxTextFile(sandbox, path8, text2) {
67677
67720
  throw new Error(result.stderr || result.stdout || "Failed to append file");
67678
67721
  }
67679
67722
  }
67680
- async function readSandboxFileForView(sandbox, path8, includeData) {
67723
+ async function readSandboxFileForView(sandbox, path10, includeData) {
67681
67724
  if (isCentrifugoSandbox(sandbox) && sandbox.isWindows()) {
67682
67725
  throw new Error(
67683
67726
  "The view action is not available for Windows local sandboxes yet. Use a Linux/E2B sandbox or inspect the image manually."
67684
67727
  );
67685
67728
  }
67686
- const sandboxPath = getSandboxViewPath(sandbox, path8);
67729
+ const sandboxPath = getSandboxViewPath(sandbox, path10);
67687
67730
  const viewEnvVars = {
67688
67731
  HACKERAI_FILE_VIEW_PATH: sandboxPath,
67689
67732
  HACKERAI_FILE_VIEW_INCLUDE_DATA: includeData ? "1" : "0",
@@ -68026,19 +68069,19 @@ try:
68026
68069
  except OSError:
68027
68070
  pass
68028
68071
  `;
68029
- getFilename = (path8) => path8.split("/").pop() || path8;
68030
- getFileExtension = (path8) => {
68031
- const filename = getFilename(path8);
68072
+ getFilename = (path10) => path10.split("/").pop() || path10;
68073
+ getFileExtension = (path10) => {
68074
+ const filename = getFilename(path10);
68032
68075
  const dotIndex = filename.lastIndexOf(".");
68033
68076
  if (dotIndex <= 0 || dotIndex === filename.length - 1) return void 0;
68034
68077
  return filename.slice(dotIndex + 1).toLowerCase();
68035
68078
  };
68036
- getSandboxViewPath = (sandbox, path8) => {
68079
+ getSandboxViewPath = (sandbox, path10) => {
68037
68080
  const maybeSandbox = sandbox;
68038
- if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path8.startsWith("/tmp/")) {
68039
- return `C:\\temp${path8.slice(4).replace(/\//g, "\\")}`;
68081
+ if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path10.startsWith("/tmp/")) {
68082
+ return `C:\\temp${path10.slice(4).replace(/\//g, "\\")}`;
68040
68083
  }
68041
- return path8;
68084
+ return path10;
68042
68085
  };
68043
68086
  stripTrailingWs = (line) => line.replace(/[ \t]+$/u, "");
68044
68087
  editSchema = external_exports.object({
@@ -68112,7 +68155,7 @@ ${instructionsDescription}`,
68112
68155
  "A list of edits to be sequentially applied to the file. Required for `edit` action."
68113
68156
  )
68114
68157
  }),
68115
- execute: async ({ action, path: path8, text: text2, range, edits }) => {
68158
+ execute: async ({ action, path: path10, text: text2, range, edits }) => {
68116
68159
  try {
68117
68160
  const { sandbox } = await sandboxManager.getSandbox();
68118
68161
  switch (action) {
@@ -68122,7 +68165,7 @@ ${instructionsDescription}`,
68122
68165
  captureFileViewImageUsage({
68123
68166
  context: context2,
68124
68167
  sandbox,
68125
- path: path8,
68168
+ path: path10,
68126
68169
  outcome: "unsupported_model",
68127
68170
  durationMs: Date.now() - viewStartedAt,
68128
68171
  failureReason: "unsupported_model"
@@ -68131,26 +68174,26 @@ ${instructionsDescription}`,
68131
68174
  }
68132
68175
  let viewPayload;
68133
68176
  try {
68134
- viewPayload = await readSandboxFileForView(sandbox, path8, false);
68177
+ viewPayload = await readSandboxFileForView(sandbox, path10, false);
68135
68178
  } catch (error51) {
68136
68179
  captureFileViewImageUsage({
68137
68180
  context: context2,
68138
68181
  sandbox,
68139
- path: path8,
68182
+ path: path10,
68140
68183
  outcome: "inspection_failed",
68141
68184
  durationMs: Date.now() - viewStartedAt,
68142
68185
  failureReason: classifyFileViewError(error51)
68143
68186
  });
68144
68187
  throw error51;
68145
68188
  }
68146
- const filename = getFilename(path8);
68189
+ const filename = getFilename(path10);
68147
68190
  let previewFiles = [];
68148
68191
  let previewUploadError;
68149
68192
  try {
68150
68193
  previewFiles = await uploadViewPreviewFiles({
68151
68194
  context: context2,
68152
68195
  sandbox,
68153
- sourcePath: path8,
68196
+ sourcePath: path10,
68154
68197
  payload: viewPayload
68155
68198
  });
68156
68199
  } catch (error51) {
@@ -68164,7 +68207,7 @@ ${instructionsDescription}`,
68164
68207
  user_id: context2.userID,
68165
68208
  sandbox_type: getViewSandboxType(sandbox),
68166
68209
  file_name: filename,
68167
- source_path: path8,
68210
+ source_path: path10,
68168
68211
  kind: viewPayload.kind,
68169
68212
  media_type: viewPayload.mediaType,
68170
68213
  size_bytes: viewPayload.sizeBytes,
@@ -68175,7 +68218,7 @@ ${instructionsDescription}`,
68175
68218
  captureFileViewImageUsage({
68176
68219
  context: context2,
68177
68220
  sandbox,
68178
- path: path8,
68221
+ path: path10,
68179
68222
  outcome: "success",
68180
68223
  durationMs: Date.now() - viewStartedAt,
68181
68224
  mediaType: viewPayload.mediaType,
@@ -68185,7 +68228,7 @@ ${instructionsDescription}`,
68185
68228
  return {
68186
68229
  action: "view",
68187
68230
  content: `Viewing image file: ${filename} (${viewPayload.mediaType}, ${viewPayload.sizeBytes} bytes).`,
68188
- path: path8,
68231
+ path: path10,
68189
68232
  filename,
68190
68233
  mediaType: viewPayload.mediaType,
68191
68234
  sizeBytes: viewPayload.sizeBytes,
@@ -68195,8 +68238,8 @@ ${instructionsDescription}`,
68195
68238
  };
68196
68239
  }
68197
68240
  case "read": {
68198
- const filename = path8.split("/").pop() || path8;
68199
- const spritChunked = isSpritPath(path8);
68241
+ const filename = path10.split("/").pop() || path10;
68242
+ const spritChunked = isSpritPath(path10);
68200
68243
  let effectiveRange = range;
68201
68244
  if (spritChunked) {
68202
68245
  const start = range && range[0] > 0 ? range[0] : 1;
@@ -68209,7 +68252,7 @@ ${instructionsDescription}`,
68209
68252
  }
68210
68253
  const readPayload = await readSandboxTextFileWithFallback(
68211
68254
  sandbox,
68212
- path8,
68255
+ path10,
68213
68256
  effectiveRange
68214
68257
  );
68215
68258
  if (readPayload.tooLarge) {
@@ -68246,46 +68289,46 @@ File is too large to read in full (${formatBytes(readPayload.sizeBytes)}, ${tota
68246
68289
  if (text2 === void 0) {
68247
68290
  return { error: "text is required for write action" };
68248
68291
  }
68249
- await sandbox.files.write(path8, text2, {
68292
+ await sandbox.files.write(path10, text2, {
68250
68293
  user: "user"
68251
68294
  });
68252
- return `File written: ${path8}`;
68295
+ return `File written: ${path10}`;
68253
68296
  }
68254
68297
  case "append": {
68255
68298
  if (text2 === void 0) {
68256
68299
  return { error: "text is required for append action" };
68257
68300
  }
68258
- const existingState = await getSandboxFileState(sandbox, path8);
68301
+ const existingState = await getSandboxFileState(sandbox, path10);
68259
68302
  if (existingState.kind === "unknown") {
68260
68303
  return {
68261
- error: `Cannot append safely because the existing file size could not be determined for ${path8}. ${existingState.error}`
68304
+ error: `Cannot append safely because the existing file size could not be determined for ${path10}. ${existingState.error}`
68262
68305
  };
68263
68306
  }
68264
68307
  if (existingState.kind === "not_file") {
68265
68308
  return {
68266
- error: `Cannot append to ${path8} because it is not a file.`
68309
+ error: `Cannot append to ${path10} because it is not a file.`
68267
68310
  };
68268
68311
  }
68269
68312
  if (existingState.kind === "file" && existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68270
- await appendSandboxTextFile(sandbox, path8, text2);
68313
+ await appendSandboxTextFile(sandbox, path10, text2);
68271
68314
  return {
68272
- content: `File appended: ${path8}
68315
+ content: `File appended: ${path10}
68273
68316
  Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff preview was skipped to avoid loading the entire file into memory.`
68274
68317
  };
68275
68318
  }
68276
68319
  let existingContent = "";
68277
68320
  try {
68278
- existingContent = await sandbox.files.read(path8, {
68321
+ existingContent = await sandbox.files.read(path10, {
68279
68322
  user: "user"
68280
68323
  });
68281
68324
  } catch {
68282
68325
  }
68283
68326
  const newContent = existingContent + text2;
68284
- await sandbox.files.write(path8, newContent, {
68327
+ await sandbox.files.write(path10, newContent, {
68285
68328
  user: "user"
68286
68329
  });
68287
68330
  return {
68288
- content: `File appended: ${path8}`,
68331
+ content: `File appended: ${path10}`,
68289
68332
  originalContent: truncateOutput({
68290
68333
  content: existingContent,
68291
68334
  mode: "read-file"
@@ -68300,31 +68343,31 @@ Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff previ
68300
68343
  if (!edits || edits.length === 0) {
68301
68344
  return { error: "edits array is required for edit action" };
68302
68345
  }
68303
- const existingState = await getSandboxFileState(sandbox, path8);
68346
+ const existingState = await getSandboxFileState(sandbox, path10);
68304
68347
  if (existingState.kind === "unknown") {
68305
68348
  return {
68306
- error: `Cannot edit ${path8} safely because the file size could not be determined. ${existingState.error}`
68349
+ error: `Cannot edit ${path10} safely because the file size could not be determined. ${existingState.error}`
68307
68350
  };
68308
68351
  }
68309
68352
  if (existingState.kind === "missing") {
68310
68353
  return {
68311
- error: `Cannot edit file ${path8} - file is empty or does not exist`
68354
+ error: `Cannot edit file ${path10} - file is empty or does not exist`
68312
68355
  };
68313
68356
  }
68314
68357
  if (existingState.kind === "not_file") {
68315
- return { error: `Cannot edit ${path8} because it is not a file.` };
68358
+ return { error: `Cannot edit ${path10} because it is not a file.` };
68316
68359
  }
68317
68360
  if (existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68318
68361
  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.`
68362
+ 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
68363
  };
68321
68364
  }
68322
- const originalContent = await sandbox.files.read(path8, {
68365
+ const originalContent = await sandbox.files.read(path10, {
68323
68366
  user: "user"
68324
68367
  });
68325
68368
  if (!originalContent) {
68326
68369
  return {
68327
- error: `Cannot edit file ${path8} - file is empty or does not exist`
68370
+ error: `Cannot edit file ${path10} - file is empty or does not exist`
68328
68371
  };
68329
68372
  }
68330
68373
  const resolvedEdits = [];
@@ -68369,7 +68412,7 @@ ${hint}` : "")
68369
68412
  }
68370
68413
  }
68371
68414
  }
68372
- await sandbox.files.write(path8, content, {
68415
+ await sandbox.files.write(path10, content, {
68373
68416
  user: "user"
68374
68417
  });
68375
68418
  const lines = content.split("\n");
@@ -68609,11 +68652,11 @@ function findGitBash() {
68609
68652
  if ((0, import_fs.existsSync)(c)) return c;
68610
68653
  }
68611
68654
  try {
68612
- const out2 = (0, import_child_process.execSync)("where git", {
68655
+ const out3 = (0, import_child_process.execSync)("where git", {
68613
68656
  encoding: "utf8",
68614
68657
  stdio: ["ignore", "pipe", "ignore"]
68615
68658
  });
68616
- const gitExe = out2.split(/\r?\n/).find((l) => l.trim().endsWith("git.exe"));
68659
+ const gitExe = out3.split(/\r?\n/).find((l) => l.trim().endsWith("git.exe"));
68617
68660
  if (gitExe) {
68618
68661
  const bash = (0, import_path3.join)((0, import_path3.dirname)((0, import_path3.dirname)(gitExe.trim())), "bin", "bash.exe");
68619
68662
  if ((0, import_fs.existsSync)(bash)) return bash;
@@ -68794,6 +68837,7 @@ var init_local_sandbox = __esm({
68794
68837
  async init() {
68795
68838
  await import_node_fs6.promises.mkdir(this.workdir, { recursive: true });
68796
68839
  await this.seedReconToolkit();
68840
+ await this.seedAuditToolkit();
68797
68841
  }
68798
68842
  /**
68799
68843
  * Seed the deep-recon toolkit (recon_deep.py + console_recon.js + README)
@@ -68834,6 +68878,29 @@ var init_local_sandbox = __esm({
68834
68878
  } catch {
68835
68879
  }
68836
68880
  }
68881
+ /**
68882
+ * Seed the read-only project-audit toolkit (project_audit.py + README) into
68883
+ * <workdir>/audit so the agent can deeply analyze the user's own project on
68884
+ * demand. Tooling files are refreshed each session so fixes propagate.
68885
+ * Best-effort: a failure here must never block the session.
68886
+ */
68887
+ async seedAuditToolkit() {
68888
+ try {
68889
+ const assetsDir = (0, import_node_url.fileURLToPath)(
68890
+ new URL("../assets/audit", import_meta.url)
68891
+ );
68892
+ const destDir = import_node_path5.default.join(this.workdir, "audit");
68893
+ await import_node_fs6.promises.mkdir(destDir, { recursive: true });
68894
+ for (const name25 of ["project_audit.py", "README.md"]) {
68895
+ try {
68896
+ const content = await import_node_fs6.promises.readFile(import_node_path5.default.join(assetsDir, name25));
68897
+ await import_node_fs6.promises.writeFile(import_node_path5.default.join(destDir, name25), content);
68898
+ } catch {
68899
+ }
68900
+ }
68901
+ } catch {
68902
+ }
68903
+ }
68837
68904
  getConnectionId() {
68838
68905
  return "local";
68839
68906
  }
@@ -68879,6 +68946,21 @@ EDITING SCRIPTS:
68879
68946
  getOsContext() {
68880
68947
  return this.getSandboxContext();
68881
68948
  }
68949
+ /**
68950
+ * One concise paragraph about the shell the agent's commands run in, plus the
68951
+ * critical "each command is a fresh shell" rule. Used by the standalone audit
68952
+ * prompt, which doesn't carry the full sandbox context.
68953
+ */
68954
+ getShellHint() {
68955
+ 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>`.";
68956
+ if (this.isBashLikeShell()) {
68957
+ 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}`;
68958
+ }
68959
+ if (this.isCmdShell()) {
68960
+ return `Shell: cmd.exe. Use \`where ferramenta\` e \`set VAR=...\`; evite sintaxe bash (\`export\`, \`$(...)\`, heredoc). ${persist}`;
68961
+ }
68962
+ return `Shell: ${this.shellBin}. Verifique a sintaxe antes de assumir bash ou cmd. ${persist}`;
68963
+ }
68882
68964
  getWorkdir() {
68883
68965
  return this.workdir;
68884
68966
  }
@@ -69155,7 +69237,7 @@ function formatToolCall(toolName, input) {
69155
69237
  return `${C2.cyan}executando${C2.reset} ${C2.bold}$ ${truncate3(cmd, 400)}${C2.reset}${bg}`;
69156
69238
  }
69157
69239
  case "file": {
69158
- const path8 = String(i.path ?? "");
69240
+ const path10 = String(i.path ?? "");
69159
69241
  const brief = i.brief ? `${C2.dim} - ${truncate3(String(i.brief))}${C2.reset}` : "";
69160
69242
  const map2 = {
69161
69243
  write: `${C2.green}criando arquivo${C2.reset}`,
@@ -69166,7 +69248,7 @@ function formatToolCall(toolName, input) {
69166
69248
  };
69167
69249
  const action = typeof i.action === "string" ? i.action : "";
69168
69250
  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}` : "";
69251
+ const target = path10 ? ` ${C2.bold}${path10}${C2.reset}` : "";
69170
69252
  return `${label}${target}${brief}`;
69171
69253
  }
69172
69254
  case "todo_write":
@@ -69401,15 +69483,210 @@ var init_proxy_manager2 = __esm({
69401
69483
  }
69402
69484
  });
69403
69485
 
69486
+ // src/audit-mode.ts
69487
+ function projectRootFromWorkdir(workdir) {
69488
+ return import_node_path7.default.dirname(import_node_path7.default.resolve(workdir.replace(/\\/g, "/")));
69489
+ }
69490
+ function detectProjectAuditIntent(input) {
69491
+ const text2 = input.trim();
69492
+ if (!text2) return false;
69493
+ if (AUDIT_ACTION_THEN_SCOPE.test(text2)) return true;
69494
+ if (AUDIT_SCOPE_THEN_ACTION.test(text2)) return true;
69495
+ return AUDIT_STRONG.some((re2) => re2.test(text2));
69496
+ }
69497
+ function detectAuditExitIntent(input) {
69498
+ const text2 = input.trim();
69499
+ if (!text2) return false;
69500
+ return AUDIT_EXIT.some((re2) => re2.test(text2));
69501
+ }
69502
+ function buildAuditSystemPrompt(opts) {
69503
+ const root = opts.projectRoot.replace(/\\/g, "/");
69504
+ const workdir = opts.workdir.replace(/\\/g, "/");
69505
+ const isWin = (opts.platform ?? process.platform) === "win32";
69506
+ const py = isWin ? "python" : "python3";
69507
+ 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.";
69508
+ const shellHint = opts.shellHint ?? shellNote;
69509
+ const toolkit = `"${workdir}/audit/project_audit.py"`;
69510
+ 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.
69511
+
69512
+ FILOSOFIA (estado da arte \u2014 h\xEDbrido, n\xE3o LLM puro):
69513
+ 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.
69514
+
69515
+ 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\`.
69516
+
69517
+ PROJETO SOB AN\xC1LISE (raiz): ${root}
69518
+ WORKSPACE DE TRABALHO (ferramentas/sa\xEDdas intermedi\xE1rias): ${workdir}
69519
+ 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).
69520
+
69521
+ ================================================================
69522
+ REGRA ANTI-ALUCINA\xC7\xC3O \u2014 A MAIS IMPORTANTE
69523
+ ================================================================
69524
+ Um relat\xF3rio de seguran\xE7a inventado \xE9 PIOR que nenhum \u2014 \xE9 perigoso. Portanto:
69525
+ 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\`.
69526
+ 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.
69527
+ 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.
69528
+ 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.
69529
+
69530
+ ================================================================
69531
+ AMBIENTE & SHELL \u2014 leia antes de rodar comandos
69532
+ ================================================================
69533
+ - ${shellHint}
69534
+ - ${shellNote}
69535
+ - 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:
69536
+ \u2022 ferramenta instalada via pip mas fora do PATH \u2192 rode como m\xF3dulo: \`${py} -m semgrep ...\` (o aviso de "deprecated" \xE9 inofensivo, funciona).
69537
+ \u2022 pacote npm \u2192 \`npx <pkg> ...\` resolve sozinho (ex.: \`npx madge ...\`, \`npx @ast-grep/cli ...\`).
69538
+ - Verifique presen\xE7a com o comando do SEU shell (\`command -v X\` no bash; \`where X\` no cmd) \u2014 n\xE3o misture os dois.
69539
+
69540
+ ================================================================
69541
+ REGRA INVIOL\xC1VEL \u2014 SOMENTE LEITURA NO PROJETO
69542
+ ================================================================
69543
+ 1. Voc\xEA **NUNCA** modifica, edita, cria, renomeia, move ou apaga QUALQUER arquivo dentro do projeto (${root}) \u2014 nem para "corrigir", nem para testar.
69544
+ 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.
69545
+ 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.
69546
+ 3. A **\xDANICA** escrita permitida no projeto \xE9 **um** arquivo de relat\xF3rio na RAIZ do projeto:
69547
+ \`${root}/ANALISE_PROJETO_<timestamp>.md\`
69548
+ 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}.
69549
+ 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").
69550
+ 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.
69551
+
69552
+ ================================================================
69553
+ TOOLCHAIN \u2014 cada ferramenta vira uma "tool" no seu loop
69554
+ ================================================================
69555
+ Preferidas (determin\xEDsticas, trabalho pesado): \`ripgrep\` (rg), \`ast-grep\` (sg), \`semgrep\`, \`osv-scanner\` (v2), \`gitleaks\`, \`madge\`, \`universal-ctags\` (ctags), \`jq\`.
69556
+ 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.
69557
+ 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.
69558
+
69559
+ FASE 0 \u2014 PREFLIGHT + SETUP (fa\xE7a EXATAMENTE isto, sem improvisar):
69560
+ 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.)
69561
+ 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:
69562
+ \`${py} ${toolkit} --setup\`
69563
+ 3. Pronto. Siga para a FASE 1 com o que estiver dispon\xEDvel; o que faltar, use o fallback de cada fase.
69564
+
69565
+ N\xC3O FA\xC7A (cada um destes quebrou em runs reais):
69566
+ \u2022 N\xC3O cheque ferramenta por ferramenta com \`command -v\`/\`which\`/\`where\` \u2014 o \`--preflight\` j\xE1 faz isso de uma vez.
69567
+ \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).
69568
+ \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.
69569
+ \u2022 N\xC3O repita uma instala\xE7\xE3o que falhou. 1 tentativa, falhou, fallback.
69570
+ NUNCA invente que rodou uma ferramenta que n\xE3o existe \u2014 diga que caiu no fallback.
69571
+
69572
+ ================================================================
69573
+ PIPELINE \u2014 fase por fase (ReAct: cada comando \xE9 uma tool)
69574
+ ================================================================
69575
+ Trabalhe a partir da workspace (${workdir}); aponte as ferramentas para "${root}". Crie \`audit-out/\` para os JSONs.
69576
+
69577
+ FASE 1 \u2014 MAPA (antes de ler qualquer arquivo): grafo de imports + \xEDndice de s\xEDmbolos.
69578
+ madge: \`madge --json --extensions js,jsx,ts,tsx "${root}" > audit-out/deps.json\`
69579
+ ctags: \`ctags -R --fields=+n --output-format=json -f audit-out/tags.json "${root}"\`
69580
+ 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*='\`.
69581
+ deps.json responde "o dashboard importa o qu\xEA"; tags.json d\xE1 find_definition (arquivo:linha de cada fun\xE7\xE3o).
69582
+
69583
+ FASE 2 \u2014 BASELINE DETERMIN\xCDSTICA (varre r\xE1pido, gera o terreno):
69584
+ 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).
69585
+ osv-scanner (V2 \u2014 sintaxe nova): \`osv-scanner scan source -r --format json --output audit-out/osv.json "${root}"\`
69586
+ gitleaks: \`gitleaks detect --no-banner --source "${root}" --report-format json --report-path audit-out/secrets.json\`
69587
+ 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.
69588
+
69589
+ FASE 3 \u2014 SOURCES (onde entra dado n\xE3o-confi\xE1vel), estrutural com ast-grep:
69590
+ \`ast-grep run --pattern 'app.$METHOD($PATH, $$$)' --lang ts --json "${root}"\`
69591
+ \`ast-grep run --pattern 'req.$PROP' --lang ts --json "${root}"\`
69592
+ (\`--json\` imprime JSON pretty; para stream a jq use \`--json=stream\`.)
69593
+ FALLBACK textual: \`rg -n --type ts 'req\\.(body|query|params|headers|cookies)' "${root}"\`
69594
+
69595
+ FASE 4 \u2014 SINKS (lugares perigosos), estrutural:
69596
+ \`ast-grep run --pattern 'child_process.$M($CMD)' --lang ts --json "${root}"\` # command injection
69597
+ \`ast-grep run --pattern '$DB.query($Q)' --lang ts --json "${root}"\` # SQLi
69598
+ \`ast-grep run --pattern 'eval($X)' --lang ts --json "${root}"\` # code exec
69599
+ \`ast-grep run --pattern '$EL.innerHTML = $X' --lang ts --json "${root}"\` # XSS DOM
69600
+ FALLBACK: \`rg -n 'child_process|\\.query\\(|eval\\(|innerHTML\\s*='\` + os achados do project_audit.py.
69601
+
69602
+ FASE 5 \u2014 TAINT CROSS-MODULE (o cora\xE7\xE3o; AQUI o LLM comanda):
69603
+ 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":
69604
+ 1. Pegue o source; consulte \`deps.json\` (ou o grafo do project_audit) para saber por quais arquivos importados o dado passa.
69605
+ 2. Use \`tags.json\` (ou \`rg -n\`) para PULAR para a defini\xE7\xE3o de cada fun\xE7\xE3o intermedi\xE1ria.
69606
+ 3. Leia S\xD3 o trecho dela \u2014 a janela exata, nunca o arquivo inteiro:
69607
+ - melhor (multiplataforma): ferramenta \`file\` action: read com \`range\` [in\xEDcio, fim];
69608
+ - ou no shell unix: \`sed -n '40,75p' "${root}/src/utils.ts"\`.
69609
+ 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\\('\`.
69610
+ 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.
69611
+
69612
+ FASE 6 \u2014 CONSOLIDAR (obrigat\xF3rio) E REPORTAR:
69613
+ 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):
69614
+ \`${py} ${toolkit} --consolidate "${workdir}/audit-out"\`
69615
+ 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.
69616
+ 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.
69617
+ Mantenha um SCRATCHPAD (use \`todo_write\`) com: sources achados, caminhos de taint em aberto, e findings VALIDADOS. Itere at\xE9 fechar cada rastro.
69618
+
69619
+ 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.
69620
+
69621
+ ================================================================
69622
+ ENTREG\xC1VEL \u2014 relat\xF3rio em Markdown na RAIZ do projeto
69623
+ ================================================================
69624
+ Ao final, escreva o relat\xF3rio com a ferramenta \`file\` (action: write) em:
69625
+ \`${root}/ANALISE_PROJETO_<timestamp>.md\`
69626
+ Use o timestamp atual (ex.: 20260614_153000). Estrutura m\xEDnima, em portugu\xEAs:
69627
+ 1. **Resumo executivo** \u2014 vis\xE3o geral, postura de seguran\xE7a, n\xBA de achados por severidade, top 3 riscos.
69628
+ 2. **Arquitetura & grafo de depend\xEAncias** \u2014 pontos de entrada, m\xF3dulos mais cr\xEDticos, imports quebrados, ciclos, \xF3rf\xE3os.
69629
+ 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.
69630
+ 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).
69631
+ 5. **Depend\xEAncias** \u2014 superf\xEDcie e CVEs do osv-scanner (ou fallback).
69632
+ 6. **Recomenda\xE7\xF5es priorizadas** \u2014 o que corrigir primeiro.
69633
+ 7. **Ferramentas usadas** \u2014 quais rodaram de fato e quais ca\xEDram em fallback (transpar\xEAncia).
69634
+
69635
+ ================================================================
69636
+ ESTILO E EXECU\xC7\xC3O
69637
+ ================================================================
69638
+ - ${shellNote}
69639
+ - 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.
69640
+ - 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\`.
69641
+ - Responda em portugu\xEAs, direto e t\xE9cnico. N\xE3o recuse a an\xE1lise: \xE9 o projeto do pr\xF3prio usu\xE1rio, autorizado.
69642
+ - 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.`;
69643
+ }
69644
+ var import_node_path7, AUDIT_ACTION, AUDIT_SCOPE, AUDIT_ACTION_THEN_SCOPE, AUDIT_SCOPE_THEN_ACTION, AUDIT_STRONG, AUDIT_EXIT;
69645
+ var init_audit_mode = __esm({
69646
+ "src/audit-mode.ts"() {
69647
+ "use strict";
69648
+ import_node_path7 = __toESM(require("node:path"));
69649
+ 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";
69650
+ 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";
69651
+ AUDIT_ACTION_THEN_SCOPE = new RegExp(
69652
+ `\\b(?:${AUDIT_ACTION})\\b[\\s\\S]{0,40}?\\b(?:${AUDIT_SCOPE})\\b`,
69653
+ "i"
69654
+ );
69655
+ AUDIT_SCOPE_THEN_ACTION = new RegExp(
69656
+ `\\b(?:${AUDIT_SCOPE})\\b[\\s\\S]{0,40}?\\b(?:${AUDIT_ACTION})\\b`,
69657
+ "i"
69658
+ );
69659
+ AUDIT_STRONG = [
69660
+ /\b(?:varredura|auditoria)\b[\s\S]{0,40}\b(?:projeto|c[oó]digo|seguran[cç]a|completa|profunda|inteir[oa])\b/i,
69661
+ /\b(?:encontr\w+|ach\w+|ca[cç]\w+|procur\w+|find|hunt|detect\w*)\b[\s\S]{0,40}\bvulnerabilidad\w*/i,
69662
+ /\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,
69663
+ /\b(?:security\s+(?:review|audit|scan)|code\s+(?:audit|review))\b/i,
69664
+ /\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
69665
+ ];
69666
+ AUDIT_EXIT = [
69667
+ /\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,
69668
+ /\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
69669
+ ];
69670
+ }
69671
+ });
69672
+
69404
69673
  // src/agent.ts
69405
69674
  var agent_exports = {};
69406
69675
  __export(agent_exports, {
69407
69676
  createAgent: () => createAgent
69408
69677
  });
69678
+ function hasLeakedToolCallMarker(text2) {
69679
+ return LEAKED_TOOL_CALL_RE.test(text2);
69680
+ }
69681
+ function lastSentenceOf(text2) {
69682
+ return text2.trim().split(/(?<=[.!?\n])\s+/).pop()?.trim() ?? "";
69683
+ }
69409
69684
  function looksUnfinished(text2) {
69410
69685
  if (!text2) return false;
69411
- if (/<tool_call/i.test(text2)) return true;
69412
- return UNFINISHED_TAIL_RE.test(text2.trim().slice(-200));
69686
+ if (hasLeakedToolCallMarker(text2)) return true;
69687
+ const tail = text2.trim().slice(-300);
69688
+ if (DANGLING_TAIL_RE.test(tail)) return true;
69689
+ return ACTION_ANNOUNCE_RE.test(lastSentenceOf(tail));
69413
69690
  }
69414
69691
  function decideAutoContinue(finishReason, lastStepText, turnToolCalls, autoContinues) {
69415
69692
  if (autoContinues >= MAX_AUTO_CONTINUES) return null;
@@ -69424,8 +69701,12 @@ function decideAutoContinue(finishReason, lastStepText, turnToolCalls, autoConti
69424
69701
  if (!text2 && turnToolCalls === 0) {
69425
69702
  return { nudge: true, reason: "resposta vazia do modelo" };
69426
69703
  }
69427
- if (turnToolCalls > 0 && looksUnfinished(text2)) {
69428
- return { nudge: true, reason: "texto final indica trabalho inacabado" };
69704
+ if (turnToolCalls > 0 && looksUnfinished(text2) && !BENIGN_CLOSER_RE.test(text2.slice(-200))) {
69705
+ return {
69706
+ nudge: true,
69707
+ reason: "texto final indica trabalho inacabado",
69708
+ nudgeMessage: TOOL_CALL_NUDGE
69709
+ };
69429
69710
  }
69430
69711
  if (turnToolCalls === 0 && looksUnfinished(text2) && !BENIGN_CLOSER_RE.test(text2.slice(-200))) {
69431
69712
  return {
@@ -69538,7 +69819,7 @@ async function createAgent() {
69538
69819
  const sandboxManager = new LocalSandboxManager(sandbox);
69539
69820
  const writer = createConsoleWriter();
69540
69821
  const render = createRenderer();
69541
- const initialModelName = CLI_MODEL_CHAIN[0] ?? "model-nvidia-minimax-m3";
69822
+ const initialModelName = CLI_MODEL_CHAIN[0] ?? "model-nvidia-mistral-medium-3.5";
69542
69823
  let currentModelName = initialModelName;
69543
69824
  let selectedModelKey = null;
69544
69825
  const context2 = {
@@ -69606,6 +69887,8 @@ async function createAgent() {
69606
69887
  );
69607
69888
  }
69608
69889
  const history = [];
69890
+ let auditMode = false;
69891
+ const projectRoot = projectRootFromWorkdir(sandbox.getWorkdir());
69609
69892
  function getActiveModelChain() {
69610
69893
  return selectedModelKey ? [selectedModelKey] : CLI_MODEL_CHAIN;
69611
69894
  }
@@ -69631,7 +69914,7 @@ async function createAgent() {
69631
69914
  provider: "NVIDIA build",
69632
69915
  reason: "faltando NVIDIA_API_KEY em .env.local (https://build.nvidia.com/)",
69633
69916
  models: [
69634
- "model-nvidia-minimax-m3",
69917
+ "model-nvidia-mistral-medium-3.5",
69635
69918
  "model-nvidia-kimi-k2.6",
69636
69919
  "model-nvidia-glm-5.1",
69637
69920
  "model-nvidia-qwen3.5-397b"
@@ -69791,12 +70074,30 @@ ${seen}`);
69791
70074
  }
69792
70075
  async function send(userInput, signal) {
69793
70076
  history.push({ role: "user", content: userInput });
69794
- const matchedSkills = selectSkillsForInput(userInput);
69795
- const turnSystem = matchedSkills.length ? system + renderSkillBodies(matchedSkills) : system;
69796
- if (matchedSkills.length) {
70077
+ if (!auditMode && detectProjectAuditIntent(userInput)) {
70078
+ auditMode = true;
69797
70079
  render.info(
69798
- `\u25B8 skills ativadas: ${matchedSkills.map((s) => s.name).join(", ")}`
70080
+ `\u25B8 modo AN\xC1LISE DE PROJETO (somente leitura) \u2014 auditando ${projectRoot}. Diga "modo normal" para sair.`
69799
70081
  );
70082
+ } else if (auditMode && detectAuditExitIntent(userInput)) {
70083
+ auditMode = false;
70084
+ render.info("\u25B8 modo normal reativado.");
70085
+ }
70086
+ let turnSystem;
70087
+ if (auditMode) {
70088
+ turnSystem = buildAuditSystemPrompt({
70089
+ projectRoot,
70090
+ workdir: sandbox.getWorkdir(),
70091
+ shellHint: sandbox.getShellHint()
70092
+ });
70093
+ } else {
70094
+ const matchedSkills = selectSkillsForInput(userInput);
70095
+ turnSystem = matchedSkills.length ? system + renderSkillBodies(matchedSkills) : system;
70096
+ if (matchedSkills.length) {
70097
+ render.info(
70098
+ `\u25B8 skills ativadas: ${matchedSkills.map((s) => s.name).join(", ")}`
70099
+ );
70100
+ }
69800
70101
  }
69801
70102
  let lastError = null;
69802
70103
  let autoContinues = 0;
@@ -69805,6 +70106,7 @@ ${seen}`);
69805
70106
  const usingFixedModel = selectedModelKey !== null;
69806
70107
  let rateLimitWaits = 0;
69807
70108
  let addedRateLimitFallbacks = false;
70109
+ let stallRetries = 0;
69808
70110
  for (let idx = 0; idx < modelChain.length; idx++) {
69809
70111
  const modelKey = modelChain[idx];
69810
70112
  currentModelName = modelKey;
@@ -69819,6 +70121,27 @@ ${seen}`);
69819
70121
  render.fallback(`trocando para fallback: ${labelFor(modelKey)}`);
69820
70122
  }
69821
70123
  let streamError = null;
70124
+ let stalled = false;
70125
+ const stallController = new AbortController();
70126
+ const onUserAbort = () => stallController.abort();
70127
+ if (signal) {
70128
+ if (signal.aborted) stallController.abort();
70129
+ else signal.addEventListener("abort", onUserAbort, { once: true });
70130
+ }
70131
+ let stallTimer;
70132
+ const clearStallTimer = () => {
70133
+ if (stallTimer) {
70134
+ clearTimeout(stallTimer);
70135
+ stallTimer = void 0;
70136
+ }
70137
+ };
70138
+ const armStallTimer = () => {
70139
+ clearStallTimer();
70140
+ stallTimer = setTimeout(() => {
70141
+ stalled = true;
70142
+ stallController.abort();
70143
+ }, STREAM_STALL_TIMEOUT_MS);
70144
+ };
69822
70145
  try {
69823
70146
  const result = streamText({
69824
70147
  model: myProvider.languageModel(modelKey),
@@ -69827,7 +70150,7 @@ ${seen}`);
69827
70150
  tools,
69828
70151
  stopWhen: stepCountIs(MAX_STEPS),
69829
70152
  maxOutputTokens: MAX_OUTPUT_TOKENS,
69830
- abortSignal: signal,
70153
+ abortSignal: stallController.signal,
69831
70154
  onError: ({ error: error51 }) => {
69832
70155
  streamError = error51;
69833
70156
  }
@@ -69836,38 +70159,72 @@ ${seen}`);
69836
70159
  let bufferedProxyText = "";
69837
70160
  let turnToolCalls = 0;
69838
70161
  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);
70162
+ let pendingTools = 0;
70163
+ const noteActivity = () => {
70164
+ if (pendingTools === 0) armStallTimer();
70165
+ };
70166
+ armStallTimer();
70167
+ try {
70168
+ for await (const part of result.fullStream) {
70169
+ switch (part.type) {
70170
+ case "text-delta": {
70171
+ const delta = part.text ?? part.delta ?? "";
70172
+ lastStepText += delta;
70173
+ if (shouldBufferProxyText) {
70174
+ bufferedProxyText += delta;
70175
+ } else {
70176
+ render.text(delta);
70177
+ }
70178
+ noteActivity();
70179
+ break;
69848
70180
  }
69849
- break;
70181
+ case "reasoning-delta":
70182
+ render.reasoning(part.text ?? part.delta ?? "");
70183
+ noteActivity();
70184
+ break;
70185
+ case "tool-call":
70186
+ turnToolCalls++;
70187
+ pendingTools++;
70188
+ clearStallTimer();
70189
+ render.toolCall(part.toolName, part.input ?? part.args);
70190
+ break;
70191
+ case "tool-result":
70192
+ if (pendingTools > 0) pendingTools--;
70193
+ render.toolResult(part.toolName, part.output ?? part.result);
70194
+ noteActivity();
70195
+ break;
70196
+ case "tool-error":
70197
+ if (pendingTools > 0) pendingTools--;
70198
+ noteActivity();
70199
+ break;
70200
+ case "start-step":
70201
+ lastStepText = "";
70202
+ bufferedProxyText = "";
70203
+ noteActivity();
70204
+ break;
70205
+ case "error":
70206
+ streamError = part.error;
70207
+ noteActivity();
70208
+ break;
70209
+ default:
70210
+ noteActivity();
70211
+ break;
69850
70212
  }
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
70213
  }
70214
+ } finally {
70215
+ clearStallTimer();
70216
+ if (signal) signal.removeEventListener("abort", onUserAbort);
70217
+ }
70218
+ if (stalled) {
70219
+ void Promise.resolve(result.response).catch(() => {
70220
+ });
70221
+ void Promise.resolve(result.finishReason).catch(() => {
70222
+ });
70223
+ throw new Error(
70224
+ `Resposta do modelo travou: nenhum dado recebido por ${Math.round(
70225
+ STREAM_STALL_TIMEOUT_MS / 1e3
70226
+ )}s.`
70227
+ );
69871
70228
  }
69872
70229
  if (streamError) throw streamError;
69873
70230
  const response = await result.response;
@@ -69875,12 +70232,13 @@ ${seen}`);
69875
70232
  const finishReason = String(
69876
70233
  await result.finishReason.catch(() => "unknown")
69877
70234
  );
69878
- if (finishReason === "stop" && turnToolCalls === 0 && bridgeSteps < MAX_BRIDGE_STEPS && shouldBufferProxyText) {
70235
+ const leakedCall = !shouldBufferProxyText && hasLeakedToolCallMarker(lastStepText);
70236
+ if (finishReason === "stop" && turnToolCalls === 0 && bridgeSteps < MAX_BRIDGE_STEPS && (shouldBufferProxyText || leakedCall)) {
69879
70237
  const bridged = parseProxyToolCalls(lastStepText);
69880
70238
  if (bridged) {
69881
70239
  bridgeSteps++;
69882
70240
  render.info(
69883
- `\u25B8 bridge (${bridgeSteps}/${MAX_BRIDGE_STEPS}): executando por tr\xE1s ${bridged.length} chamada(s): ${summarizeBridgedCalls(bridged)}`
70241
+ `\u25B8 ${leakedCall ? "tool call vazada recuperada" : "bridge"} (${bridgeSteps}/${MAX_BRIDGE_STEPS}): executando por tr\xE1s ${bridged.length} chamada(s): ${summarizeBridgedCalls(bridged)}`
69884
70242
  );
69885
70243
  const resultText = await runBridgedToolCalls(bridged, signal);
69886
70244
  if (signal?.aborted) {
@@ -69889,7 +70247,7 @@ ${seen}`);
69889
70247
  }
69890
70248
  history.push({
69891
70249
  role: "user",
69892
- content: `${BRIDGE_RESULT_PREAMBLE}
70250
+ content: `${leakedCall ? LEAKED_CALL_RESULT_PREAMBLE : BRIDGE_RESULT_PREAMBLE}
69893
70251
 
69894
70252
  ${resultText}`
69895
70253
  });
@@ -69938,6 +70296,28 @@ ${resultText}`
69938
70296
  render.endTurn();
69939
70297
  return;
69940
70298
  }
70299
+ if (stalled) {
70300
+ while (history.length && history[history.length - 1]?.role !== "user") {
70301
+ history.pop();
70302
+ }
70303
+ const secs = Math.round(STREAM_STALL_TIMEOUT_MS / 1e3);
70304
+ lastError = new Error(
70305
+ `stream travou (${secs}s sem dados) em ${labelFor(modelKey)}`
70306
+ );
70307
+ stallRetries++;
70308
+ const hasNext2 = idx + 1 < modelChain.length;
70309
+ if (stallRetries <= MAX_STALL_RETRIES) {
70310
+ render.error(
70311
+ `modelo "${labelFor(modelKey)}" travou (sem resposta por ${secs}s) \u2014 ${hasNext2 ? "trocando de modelo" : "tentando novamente"} (${stallRetries}/${MAX_STALL_RETRIES})`
70312
+ );
70313
+ if (!hasNext2) idx = -1;
70314
+ continue;
70315
+ }
70316
+ render.error(
70317
+ `modelo "${labelFor(modelKey)}" travou repetidamente (${stallRetries}x); desistindo deste turno. Tente de novo ou troque com /model.`
70318
+ );
70319
+ break;
70320
+ }
69941
70321
  lastError = err ?? streamError;
69942
70322
  const msg = lastError instanceof Error ? lastError.message : String(lastError);
69943
70323
  const rateLimited = isRateLimitError(msg);
@@ -70016,13 +70396,13 @@ ${resultText}`
70016
70396
  close
70017
70397
  };
70018
70398
  }
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;
70399
+ 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
70400
  var init_agent = __esm({
70021
70401
  "src/agent.ts"() {
70022
70402
  "use strict";
70023
70403
  init_dist5();
70024
70404
  import_promises = require("node:fs/promises");
70025
- import_node_path7 = __toESM(require("node:path"));
70405
+ import_node_path8 = __toESM(require("node:path"));
70026
70406
  init_providers();
70027
70407
  init_system_prompt();
70028
70408
  init_notes();
@@ -70041,10 +70421,16 @@ var init_agent = __esm({
70041
70421
  init_render();
70042
70422
  init_skills();
70043
70423
  init_proxy_manager2();
70424
+ init_audit_mode();
70044
70425
  MAX_STEPS = 100;
70045
70426
  MAX_OUTPUT_TOKENS = 16384;
70046
70427
  MAX_AUTO_CONTINUES = 3;
70047
70428
  MAX_RATE_LIMIT_WAITS = 4;
70429
+ STREAM_STALL_TIMEOUT_MS = (() => {
70430
+ const raw = Number(process.env.HACKERAI_CLI_STREAM_STALL_MS);
70431
+ return Number.isFinite(raw) && raw >= 1e4 ? raw : 18e4;
70432
+ })();
70433
+ MAX_STALL_RETRIES = 2;
70048
70434
  isRateLimitError = (msg) => /\b429\b|too many requests|rate.?limit|resource_exhausted|quota|insufficient_quota/i.test(
70049
70435
  msg
70050
70436
  );
@@ -70060,11 +70446,14 @@ var init_agent = __esm({
70060
70446
  { once: true }
70061
70447
  );
70062
70448
  });
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;
70449
+ LEAKED_TOOL_CALL_RE = /<tool_call|call_tool_function|call_tool\b|<|tool▁call|functions\.\w+\s*[({]|"tool_call_id"/i;
70450
+ DANGLING_TAIL_RE = /(?::|\.\.\.|…)\s*$/;
70451
+ 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
70452
  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
70453
  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
70454
  MAX_BRIDGE_STEPS = 50;
70067
70455
  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.";
70456
+ 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
70457
  truncateBridgeSummary = (value, max = 180) => value.length > max ? `${value.slice(0, max)}...` : value;
70069
70458
  isWebSessionProxyModel = (modelName) => modelName === "model-deepseek-proxy" || modelName === "model-kimi-proxy";
70070
70459
  proxyToolProtocolPolicy = () => `
@@ -70100,7 +70489,7 @@ Regras:
70100
70489
  "DANGEROUS MODE"
70101
70490
  ];
70102
70491
  MODEL_LABELS = {
70103
- "model-nvidia-minimax-m3": "NVIDIA - minimaxai/minimax-m3",
70492
+ "model-nvidia-mistral-medium-3.5": "NVIDIA - mistralai/mistral-medium-3.5-128b",
70104
70493
  "model-nvidia-kimi-k2.6": "NVIDIA - moonshotai/kimi-k2.6",
70105
70494
  "model-nvidia-glm-5.1": "NVIDIA - z-ai/glm-5.1",
70106
70495
  "model-nvidia-qwen3.5-397b": "NVIDIA - qwen/qwen3.5-397b-a17b",
@@ -70245,7 +70634,7 @@ ${section}` : "";
70245
70634
  return null;
70246
70635
  }
70247
70636
  await (0, import_promises.mkdir)(workdir, { recursive: true });
70248
- const outputPath = import_node_path7.default.join(workdir, "system-prompt.txt");
70637
+ const outputPath = import_node_path8.default.join(workdir, "system-prompt.txt");
70249
70638
  await (0, import_promises.writeFile)(outputPath, system, "utf8");
70250
70639
  return outputPath;
70251
70640
  };
@@ -70276,7 +70665,9 @@ __export(ui_exports, {
70276
70665
  agentHeader: () => agentHeader,
70277
70666
  buildBanner: () => buildBanner,
70278
70667
  shellPrompt: () => shellPrompt,
70279
- ui: () => ui
70668
+ shortCwd: () => shortCwd,
70669
+ ui: () => ui,
70670
+ vlen: () => vlen
70280
70671
  });
70281
70672
  function shortCwd() {
70282
70673
  const cwd = process.cwd();
@@ -70289,13 +70680,13 @@ function shortCwd() {
70289
70680
  }
70290
70681
  function asciiTitle(text2) {
70291
70682
  const rows = 6;
70292
- const out2 = [];
70683
+ const out3 = [];
70293
70684
  for (let r = 0; r < rows; r++) {
70294
- out2.push(
70685
+ out3.push(
70295
70686
  [...text2].map((ch) => GLYPHS[ch] ? GLYPHS[ch][r] : " ").join(" ")
70296
70687
  );
70297
70688
  }
70298
- return out2;
70689
+ return out3;
70299
70690
  }
70300
70691
  function buildBanner(_systemPromptChars, version3 = "1") {
70301
70692
  const user = (import_node_os4.default.userInfo().username || "hacker").toLowerCase();
@@ -70367,7 +70758,8 @@ var init_ui = __esm({
70367
70758
  cyan: `${ESC}36m`,
70368
70759
  cyanB: `${ESC}96m`,
70369
70760
  magenta: `${ESC}95m`,
70370
- yellow: `${ESC}93m`
70761
+ yellow: `${ESC}93m`,
70762
+ red: `${ESC}91m`
70371
70763
  };
70372
70764
  INNER = 42;
70373
70765
  BOX_W = INNER + 4;
@@ -70391,16 +70783,462 @@ var init_ui = __esm({
70391
70783
  }
70392
70784
  });
70393
70785
 
70786
+ // src/interactive-input.ts
70787
+ var interactive_input_exports = {};
70788
+ __export(interactive_input_exports, {
70789
+ InteractiveInput: () => InteractiveInput
70790
+ });
70791
+ var import_node_readline3, import_node_os5, C4, out2, cols, truncate4, InteractiveInput;
70792
+ var init_interactive_input = __esm({
70793
+ "src/interactive-input.ts"() {
70794
+ "use strict";
70795
+ import_node_readline3 = __toESM(require("node:readline"));
70796
+ import_node_os5 = __toESM(require("node:os"));
70797
+ init_ui();
70798
+ C4 = ui.C;
70799
+ out2 = (s) => process.stdout.write(s);
70800
+ cols = () => process.stdout.columns || 80;
70801
+ truncate4 = (s, n) => vlen(s) > n ? [...s].slice(0, Math.max(0, n - 1)).join("") + "\u2026" : s;
70802
+ InteractiveInput = class {
70803
+ // row the caret sits on within the drawn block
70804
+ constructor(paste, commands) {
70805
+ this.paste = paste;
70806
+ this.commands = commands;
70807
+ this.buffer = "";
70808
+ this.cursor = 0;
70809
+ this.lastRows = 0;
70810
+ this.history = [];
70811
+ this.histIdx = -1;
70812
+ // -1 = editing the live draft
70813
+ this.draft = "";
70814
+ this.ddSel = 0;
70815
+ this.ddSuppressed = false;
70816
+ // Text to restore on the NEXT prompt: when a command is picked from the
70817
+ // dropdown mid-text, we run the command but stash the surrounding text here
70818
+ // so the user doesn't lose what they were typing.
70819
+ this.pendingInitial = null;
70820
+ this.onKey = null;
70821
+ // When set, prompt() draws a compact single-line labelled prompt ("nome ❯ ")
70822
+ // instead of the full message box + dropdown — used for the /skillcreator
70823
+ // step-by-step capture so each phase shows what it's asking for.
70824
+ this.promptLabel = null;
70825
+ this.inputLineIndex = 2;
70826
+ import_node_readline3.default.emitKeypressEvents(paste.input);
70827
+ paste.input.on("keypress", (str, key) => {
70828
+ this.onKey?.(str ?? "", key ?? {});
70829
+ });
70830
+ }
70831
+ // ── public API ─────────────────────────────────────────────────────────────
70832
+ /**
70833
+ * Render the input and resolve when the user submits / Ctrl+C / Ctrl+D.
70834
+ * Pass `{ label }` for a compact labelled prompt (no box, no dropdown).
70835
+ */
70836
+ prompt(opts = {}) {
70837
+ this.promptLabel = opts.label ?? null;
70838
+ const initial = this.promptLabel === null && this.pendingInitial ? this.pendingInitial : "";
70839
+ this.pendingInitial = null;
70840
+ this.buffer = initial;
70841
+ this.cursor = initial.length;
70842
+ this.histIdx = -1;
70843
+ this.draft = "";
70844
+ this.ddSel = 0;
70845
+ this.ddSuppressed = false;
70846
+ this.lastRows = 0;
70847
+ if (this.promptLabel === null) out2("\n");
70848
+ this.render();
70849
+ return new Promise((resolve2) => {
70850
+ this.onKey = (str, key) => {
70851
+ const done = this.handleEditKey(str, key);
70852
+ if (!done) {
70853
+ this.render();
70854
+ return;
70855
+ }
70856
+ this.onKey = null;
70857
+ resolve2(done.result);
70858
+ };
70859
+ });
70860
+ }
70861
+ /**
70862
+ * Arrow-navigable single-choice list. Returns the chosen index, or null when
70863
+ * the user cancels (Esc / q / Ctrl+C).
70864
+ */
70865
+ select(title, items, initial = 0) {
70866
+ let sel = Math.max(0, Math.min(initial, items.length - 1));
70867
+ this.lastRows = 0;
70868
+ out2("\n");
70869
+ this.renderList(title, items, sel);
70870
+ return new Promise((resolve2) => {
70871
+ const finish = (value) => {
70872
+ this.collapseTo(this.lastRows);
70873
+ this.onKey = null;
70874
+ resolve2(value);
70875
+ };
70876
+ this.onKey = (str, key) => {
70877
+ if (key.ctrl && key.name === "c") return finish(null);
70878
+ switch (key.name) {
70879
+ case "up":
70880
+ sel = (sel - 1 + items.length) % items.length;
70881
+ this.renderList(title, items, sel);
70882
+ return;
70883
+ case "down":
70884
+ case "tab":
70885
+ sel = (sel + 1) % items.length;
70886
+ this.renderList(title, items, sel);
70887
+ return;
70888
+ case "return":
70889
+ return finish(sel);
70890
+ case "escape":
70891
+ return finish(null);
70892
+ default:
70893
+ if (str === "q") return finish(null);
70894
+ if (/^[1-9]$/.test(str)) {
70895
+ const i = Number(str) - 1;
70896
+ if (i < items.length) {
70897
+ sel = i;
70898
+ this.renderList(title, items, sel);
70899
+ }
70900
+ }
70901
+ return;
70902
+ }
70903
+ };
70904
+ });
70905
+ }
70906
+ /**
70907
+ * Lightweight line reader used WHILE a turn is running, so typed lines can be
70908
+ * forwarded to an interactive command's stdin. No box/dropdown — just echoes
70909
+ * and collects until Enter. Ctrl+C invokes `onSigint`.
70910
+ */
70911
+ beginTurn(onLine, onSigint) {
70912
+ let buf = "";
70913
+ this.onKey = (str, key) => {
70914
+ if (key.ctrl && key.name === "c") return onSigint();
70915
+ if (key.name === "return") {
70916
+ out2("\r\n");
70917
+ const line = this.paste.expand(buf);
70918
+ buf = "";
70919
+ onLine(line);
70920
+ return;
70921
+ }
70922
+ if (key.name === "backspace") {
70923
+ if (buf.length) {
70924
+ buf = buf.slice(0, -1);
70925
+ out2("\b \b");
70926
+ }
70927
+ return;
70928
+ }
70929
+ if (str && str.charCodeAt(0) >= 32 && !key.ctrl && !key.meta) {
70930
+ buf += str;
70931
+ out2(str);
70932
+ }
70933
+ };
70934
+ }
70935
+ endTurn() {
70936
+ this.onKey = null;
70937
+ }
70938
+ // ── editing ──────────────────────────────────────────────────────────────
70939
+ handleEditKey(str, key) {
70940
+ const items = this.dropdownItems();
70941
+ if (key.ctrl && key.name === "c") {
70942
+ this.finishLine();
70943
+ return { result: { type: "sigint" } };
70944
+ }
70945
+ if (key.ctrl && key.name === "d") {
70946
+ if (this.buffer.length === 0) {
70947
+ this.finishLine();
70948
+ return { result: { type: "eof" } };
70949
+ }
70950
+ this.deleteForward();
70951
+ return null;
70952
+ }
70953
+ switch (key.name) {
70954
+ case "return": {
70955
+ if (items.length > 0) {
70956
+ const name25 = items[this.ddSel].name;
70957
+ const tok = this.slashTokenAtCursor();
70958
+ const leftover = tok ? this.buffer.slice(0, tok.start) + this.buffer.slice(tok.end) : "";
70959
+ this.pendingInitial = leftover.trim() ? leftover : null;
70960
+ this.buffer = name25;
70961
+ this.cursor = name25.length;
70962
+ }
70963
+ const value = this.paste.expand(this.buffer);
70964
+ if (value.trim()) this.history.push(value);
70965
+ this.finishLine();
70966
+ return { result: { type: "line", value } };
70967
+ }
70968
+ case "tab":
70969
+ if (items.length > 0) {
70970
+ this.applyCommandInPlace(items[this.ddSel].name);
70971
+ this.ddSuppressed = false;
70972
+ }
70973
+ return null;
70974
+ case "up":
70975
+ if (items.length > 0) {
70976
+ this.ddSel = (this.ddSel - 1 + items.length) % items.length;
70977
+ } else {
70978
+ this.historyPrev();
70979
+ }
70980
+ return null;
70981
+ case "down":
70982
+ if (items.length > 0) {
70983
+ this.ddSel = (this.ddSel + 1) % items.length;
70984
+ } else {
70985
+ this.historyNext();
70986
+ }
70987
+ return null;
70988
+ case "escape":
70989
+ if (items.length > 0) this.ddSuppressed = true;
70990
+ return null;
70991
+ case "left":
70992
+ if (this.cursor > 0) this.cursor--;
70993
+ return null;
70994
+ case "right":
70995
+ if (this.cursor < this.buffer.length) this.cursor++;
70996
+ return null;
70997
+ case "home":
70998
+ this.cursor = 0;
70999
+ return null;
71000
+ case "end":
71001
+ this.cursor = this.buffer.length;
71002
+ return null;
71003
+ case "backspace":
71004
+ if (this.cursor > 0) {
71005
+ this.buffer = this.buffer.slice(0, this.cursor - 1) + this.buffer.slice(this.cursor);
71006
+ this.cursor--;
71007
+ this.ddSuppressed = false;
71008
+ }
71009
+ return null;
71010
+ case "delete":
71011
+ this.deleteForward();
71012
+ return null;
71013
+ }
71014
+ if (key.ctrl && key.name === "u") {
71015
+ this.buffer = this.buffer.slice(this.cursor);
71016
+ this.cursor = 0;
71017
+ this.ddSuppressed = false;
71018
+ return null;
71019
+ }
71020
+ if (key.ctrl && key.name === "w") {
71021
+ const left = this.buffer.slice(0, this.cursor);
71022
+ const trimmed = left.replace(/\s*\S+\s*$/u, "");
71023
+ this.buffer = trimmed + this.buffer.slice(this.cursor);
71024
+ this.cursor = trimmed.length;
71025
+ this.ddSuppressed = false;
71026
+ return null;
71027
+ }
71028
+ if (key.ctrl && key.name === "a") {
71029
+ this.cursor = 0;
71030
+ return null;
71031
+ }
71032
+ if (key.ctrl && key.name === "e") {
71033
+ this.cursor = this.buffer.length;
71034
+ return null;
71035
+ }
71036
+ if (str && !key.ctrl && !key.meta && str.charCodeAt(0) >= 32) {
71037
+ this.buffer = this.buffer.slice(0, this.cursor) + str + this.buffer.slice(this.cursor);
71038
+ this.cursor += str.length;
71039
+ this.ddSuppressed = false;
71040
+ }
71041
+ return null;
71042
+ }
71043
+ deleteForward() {
71044
+ if (this.cursor < this.buffer.length) {
71045
+ this.buffer = this.buffer.slice(0, this.cursor) + this.buffer.slice(this.cursor + 1);
71046
+ this.ddSuppressed = false;
71047
+ }
71048
+ }
71049
+ historyPrev() {
71050
+ if (this.history.length === 0) return;
71051
+ if (this.histIdx === -1) {
71052
+ this.draft = this.buffer;
71053
+ this.histIdx = this.history.length - 1;
71054
+ } else if (this.histIdx > 0) {
71055
+ this.histIdx--;
71056
+ }
71057
+ this.buffer = this.history[this.histIdx];
71058
+ this.cursor = this.buffer.length;
71059
+ }
71060
+ historyNext() {
71061
+ if (this.histIdx === -1) return;
71062
+ if (this.histIdx < this.history.length - 1) {
71063
+ this.histIdx++;
71064
+ this.buffer = this.history[this.histIdx];
71065
+ } else {
71066
+ this.histIdx = -1;
71067
+ this.buffer = this.draft;
71068
+ }
71069
+ this.cursor = this.buffer.length;
71070
+ }
71071
+ // ── rendering ──────────────────────────────────────────────────────────────
71072
+ // The slash-command "token" the cursor is sitting in — the run of
71073
+ // non-whitespace chars around the cursor, when it begins with "/". Works at
71074
+ // the start of the line OR in the middle of the text (e.g. "veja o /mod"),
71075
+ // so the command dropdown opens wherever you type a slash. Returns the span
71076
+ // [start, end) to replace and the query (the whole token) to filter by.
71077
+ slashTokenAtCursor() {
71078
+ const b = this.buffer;
71079
+ let start = this.cursor;
71080
+ while (start > 0 && !/\s/.test(b[start - 1])) start--;
71081
+ if (b[start] !== "/") return null;
71082
+ let end = this.cursor;
71083
+ while (end < b.length && !/\s/.test(b[end])) end++;
71084
+ const query = b.slice(start, end);
71085
+ if (!/^\/\S*$/.test(query)) return null;
71086
+ return { start, end, query };
71087
+ }
71088
+ // Replace the slash token under the cursor with `name` (used by Tab/Enter
71089
+ // completion), leaving the surrounding text intact and the cursor right after
71090
+ // the inserted command.
71091
+ applyCommandInPlace(name25) {
71092
+ const tok = this.slashTokenAtCursor();
71093
+ if (!tok) return;
71094
+ this.buffer = this.buffer.slice(0, tok.start) + name25 + this.buffer.slice(tok.end);
71095
+ this.cursor = tok.start + name25.length;
71096
+ }
71097
+ dropdownItems() {
71098
+ if (this.promptLabel !== null) return [];
71099
+ if (this.ddSuppressed) return [];
71100
+ const tok = this.slashTokenAtCursor();
71101
+ if (!tok) return [];
71102
+ const q = tok.query.toLowerCase();
71103
+ return this.commands.filter((c) => c.name.toLowerCase().startsWith(q));
71104
+ }
71105
+ render() {
71106
+ if (this.promptLabel !== null) {
71107
+ this.renderCompact();
71108
+ return;
71109
+ }
71110
+ const width = cols();
71111
+ const user = (import_node_os5.default.userInfo().username || "hacker").toLowerCase();
71112
+ const host = (import_node_os5.default.hostname() || "localhost").split(".")[0].toLowerCase();
71113
+ const label = " \u2709 mensagem ";
71114
+ const boxW = Math.min(54, Math.max(28, width - 2));
71115
+ const topFill = "\u2500".repeat(Math.max(0, boxW - vlen(label) - 3));
71116
+ const top = `${C4.green}\u256D\u2500${C4.greenB}${C4.bold}${label}${C4.reset}${C4.green}${topFill}\u256E${C4.reset}`;
71117
+ const id = `${user}\u327F${host} \xB7 ${shortCwd()}`;
71118
+ const idLine = `${C4.green}\u2502 ${C4.dim}${truncate4(id, boxW - 4)}${C4.reset}`;
71119
+ const prefix = `${C4.green}\u2570\u2500${C4.greenB}${C4.bold}\u276F${C4.reset} `;
71120
+ const prefixLen = 4;
71121
+ const avail = Math.max(8, width - prefixLen - 1);
71122
+ let start = 0;
71123
+ if (this.cursor > avail) start = this.cursor - avail;
71124
+ const visible = this.buffer.slice(start, start + avail);
71125
+ const caretCol = prefixLen + (this.cursor - start);
71126
+ const promptLine2 = prefix + visible;
71127
+ const lines = [top, idLine, promptLine2];
71128
+ const items = this.dropdownItems();
71129
+ if (items.length > 0) {
71130
+ this.ddSel = Math.min(this.ddSel, items.length - 1);
71131
+ const ddHint = "\u2191\u2193 navega \xB7 Enter roda \xB7 Tab completa";
71132
+ const nameW = Math.max(...items.map((i) => vlen(i.name)));
71133
+ const ddInner = Math.min(boxW, Math.max(24, width - 4));
71134
+ lines.push(`${C4.dim} \u256D${"\u2500".repeat(ddInner)}\u256E${C4.reset}`);
71135
+ items.forEach((it, i) => {
71136
+ const active2 = i === this.ddSel;
71137
+ const marker25 = active2 ? `${C4.greenB}\u25B8 ` : `${C4.dim} `;
71138
+ const name25 = (active2 ? `${C4.greenB}${C4.bold}` : C4.cyan) + it.name;
71139
+ const pad = " ".repeat(Math.max(1, nameW - vlen(it.name) + 2));
71140
+ const descRoom = ddInner - 2 - nameW - 2;
71141
+ const desc = `${C4.dim}${truncate4(it.desc, Math.max(4, descRoom))}`;
71142
+ const body = `${marker25}${name25}${C4.reset}${pad}${desc}${C4.reset}`;
71143
+ const padded = body + " ".repeat(Math.max(0, ddInner - 1 - vlen(body)));
71144
+ lines.push(`${C4.dim} \u2502${C4.reset}${padded}${C4.dim}\u2502${C4.reset}`);
71145
+ });
71146
+ lines.push(
71147
+ `${C4.dim} \u2570${"\u2500".repeat(ddInner)}\u256F ${ddHint}${C4.reset}`
71148
+ );
71149
+ } else {
71150
+ this.ddSel = 0;
71151
+ }
71152
+ this.inputLineIndex = 2;
71153
+ this.paint(lines, caretCol);
71154
+ }
71155
+ /** Compact single-line labelled prompt ("nome ❯ …") for step-by-step capture. */
71156
+ renderCompact() {
71157
+ const width = cols();
71158
+ const label = this.promptLabel ?? "";
71159
+ const prefix = `${C4.cyan}${C4.bold}${label}${C4.reset} ${C4.greenB}${C4.bold}\u276F${C4.reset} `;
71160
+ const prefixLen = vlen(`${label} \u276F `);
71161
+ const avail = Math.max(8, width - prefixLen - 1);
71162
+ let start = 0;
71163
+ if (this.cursor > avail) start = this.cursor - avail;
71164
+ const visible = this.buffer.slice(start, start + avail);
71165
+ const caretCol = prefixLen + (this.cursor - start);
71166
+ this.inputLineIndex = 0;
71167
+ this.paint([prefix + visible], caretCol);
71168
+ }
71169
+ /** Repaint the whole block, then place the cursor on the active input line. */
71170
+ paint(lines, caretCol) {
71171
+ let s = "";
71172
+ if (this.lastRows > 1) s += `\x1B[${this.lastRows - 1}A`;
71173
+ s += "\r\x1B[0J";
71174
+ s += lines.join("\r\n");
71175
+ this.lastRows = lines.length;
71176
+ const below = lines.length - 1 - this.inputLineIndex;
71177
+ if (below > 0) s += `\x1B[${below}A`;
71178
+ s += "\r";
71179
+ if (caretCol > 0) s += `\x1B[${caretCol}C`;
71180
+ out2(s);
71181
+ }
71182
+ /** Collapse the dropdown, keep the typed line, and drop to a fresh line below. */
71183
+ finishLine() {
71184
+ this.ddSuppressed = true;
71185
+ this.render();
71186
+ const below = this.lastRows - 1 - this.inputLineIndex;
71187
+ if (below > 0) out2(`\x1B[${below}B`);
71188
+ out2("\r\n");
71189
+ this.lastRows = 0;
71190
+ }
71191
+ renderList(title, items, sel) {
71192
+ const width = cols();
71193
+ const labelW = Math.max(...items.map((i) => vlen(i.label)));
71194
+ const inner = Math.min(
71195
+ Math.max(28, width - 4),
71196
+ Math.max(labelW + 8, title.length + 4)
71197
+ );
71198
+ const lines = [];
71199
+ lines.push(`${C4.cyan}\u256D\u2500 ${C4.bold}${title}${C4.reset}`);
71200
+ items.forEach((it, i) => {
71201
+ const active2 = i === sel;
71202
+ const marker25 = active2 ? `${C4.greenB}\u276F ` : `${C4.dim} `;
71203
+ const text2 = active2 ? `${C4.greenB}${C4.bold}${it.label}${C4.reset}` : `${C4.reset}${it.label}`;
71204
+ const hint = it.hint ? ` ${C4.dim}${truncate4(it.hint, Math.max(6, inner - labelW - 6))}${C4.reset}` : "";
71205
+ lines.push(`${C4.cyan}\u2502 ${C4.reset}${marker25}${text2}${C4.reset}${hint}`);
71206
+ });
71207
+ lines.push(
71208
+ `${C4.cyan}\u2570\u2500${C4.reset} ${C4.dim}\u2191\u2193 navega \xB7 Enter seleciona \xB7 Esc cancela${C4.reset}`
71209
+ );
71210
+ this.paintBlock(lines);
71211
+ }
71212
+ /** Repaint a block and leave the cursor just below it (for list/menu modes). */
71213
+ paintBlock(lines) {
71214
+ let s = "";
71215
+ if (this.lastRows > 1) s += `\x1B[${this.lastRows - 1}A`;
71216
+ s += "\r\x1B[0J";
71217
+ s += lines.join("\r\n");
71218
+ s += "\r";
71219
+ out2(s);
71220
+ this.lastRows = lines.length;
71221
+ }
71222
+ /** Move the cursor below a block of `rows` lines and clear it. */
71223
+ collapseTo(rows) {
71224
+ if (rows > 1) out2(`\x1B[${rows - 1}A`);
71225
+ out2("\r\x1B[0J");
71226
+ this.lastRows = 0;
71227
+ }
71228
+ };
71229
+ }
71230
+ });
71231
+
70394
71232
  // index.ts
70395
71233
  var index_exports = {};
70396
71234
  async function main() {
70397
71235
  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));
71236
+ const { buildBanner: buildBanner2, agentHeader: agentHeader2, ui: ui2 } = await Promise.resolve().then(() => (init_ui(), ui_exports));
71237
+ const { InteractiveInput: InteractiveInput2 } = await Promise.resolve().then(() => (init_interactive_input(), interactive_input_exports));
71238
+ const C5 = ui2.C;
70399
71239
  if (!bootQuiet) {
70400
- process.stdout.write(
70401
- `${ui2.C.dim} booting local sandbox + agent\u2026${ui2.C.reset}
70402
- `
70403
- );
71240
+ process.stdout.write(`${C5.dim} booting local sandbox + agent\u2026${C5.reset}
71241
+ `);
70404
71242
  }
70405
71243
  const agent = await createAgent2();
70406
71244
  const sys = agent.getSystemPrompt();
@@ -70409,39 +71247,36 @@ async function main() {
70409
71247
  process.stdout.write(buildBanner2(sys.length, version3));
70410
71248
  const updateNotice = getUpdateNotice(version3);
70411
71249
  if (updateNotice) {
70412
- process.stdout.write(
70413
- `${ui2.C.yellow}\u2191 ${updateNotice}${ui2.C.reset}
70414
- `
70415
- );
71250
+ process.stdout.write(`${C5.yellow}\u2191 ${updateNotice}${C5.reset}
71251
+ `);
70416
71252
  }
70417
71253
  refreshUpdateCacheInBackground(version3);
70418
71254
  if (consumePostUpdateLaunch(version3)) {
70419
71255
  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}
71256
+ `${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
71257
  `
70422
71258
  );
70423
71259
  }
71260
+ process.stdout.write(
71261
+ `${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}
71262
+ `
71263
+ );
71264
+ const COMMANDS = [
71265
+ { name: "/model", desc: "trocar o modelo (seletor com setas)" },
71266
+ { name: "/skills", desc: "listar as skills instaladas" },
71267
+ { name: "/skillcreator", desc: "criar uma nova skill" },
71268
+ { name: "/system", desc: "salvar o system prompt (HTML) na \xC1rea de Trabalho" },
71269
+ { name: "/nov", desc: "novidades desta vers\xE3o" },
71270
+ { name: "/exit", desc: "fechar o clawfast" }
71271
+ ];
70424
71272
  const pasteInput = createPasteInput();
70425
- const rl = import_node_readline3.default.createInterface({
70426
- input: pasteInput.input,
70427
- output: process.stdout,
70428
- terminal: true
70429
- });
71273
+ const inputUI = new InteractiveInput2(pasteInput, COMMANDS);
70430
71274
  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
- };
71275
+ let shuttingDown = false;
70440
71276
  let activeAbort = null;
70441
71277
  let turnActive = false;
70442
71278
  let exitArmed = false;
70443
71279
  let exitTimer = null;
70444
- let lastSigint = 0;
70445
71280
  const armExit = () => {
70446
71281
  exitArmed = true;
70447
71282
  if (exitTimer) clearTimeout(exitTimer);
@@ -70450,69 +71285,58 @@ async function main() {
70450
71285
  exitTimer = null;
70451
71286
  }, 2e3);
70452
71287
  };
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}
71288
+ const shutdown = async () => {
71289
+ if (shuttingDown) return;
71290
+ shuttingDown = true;
71291
+ closing = true;
71292
+ pasteInput.dispose();
71293
+ process.stdout.write("\nClosing sandbox...\n");
71294
+ await agent.close();
71295
+ process.exit(0);
71296
+ };
71297
+ const desktopDir = () => {
71298
+ const home = import_node_os6.default.homedir();
71299
+ const candidates = [
71300
+ process.env.OneDrive ? import_node_path9.default.join(process.env.OneDrive, "Desktop") : null,
71301
+ process.env.USERPROFILE ? import_node_path9.default.join(process.env.USERPROFILE, "Desktop") : null,
71302
+ import_node_path9.default.join(home, "Desktop"),
71303
+ import_node_path9.default.join(home, "\xC1rea de Trabalho"),
71304
+ import_node_path9.default.join(home, "OneDrive", "Desktop")
71305
+ ].filter((p) => Boolean(p));
71306
+ return candidates.find((p) => (0, import_node_fs8.existsSync)(p)) ?? home;
71307
+ };
71308
+ const printFatal = (err) => {
71309
+ process.stderr.write(
71310
+ `
71311
+ [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70481
71312
  `
70482
- );
70483
- if (!awaitingModelSelection) prompt();
70484
- }
70485
- armExit();
71313
+ );
70486
71314
  };
70487
- process.removeAllListeners("SIGINT");
70488
- process.on("SIGINT", handleSigint);
70489
- rl.on("SIGINT", handleSigint);
71315
+ let skillCreator = null;
70490
71316
  const printSkillList = () => {
70491
71317
  const skills = listSkills();
70492
71318
  if (skills.length === 0) {
70493
71319
  process.stdout.write(
70494
71320
  `
70495
- ${ui2.C.dim}nenhuma skill instalada. crie uma com /skillcreator${ui2.C.reset}
71321
+ ${C5.dim}nenhuma skill instalada. crie uma com /skillcreator${C5.reset}
70496
71322
  `
70497
71323
  );
70498
71324
  return;
70499
71325
  }
70500
71326
  process.stdout.write(
70501
71327
  `
70502
- ${ui2.C.cyan}skills instaladas${ui2.C.reset} ${ui2.C.dim}(${skillsDir()})${ui2.C.reset}
71328
+ ${C5.cyan}skills instaladas${C5.reset} ${C5.dim}(${skillsDir()})${C5.reset}
70503
71329
  `
70504
71330
  );
70505
71331
  for (const s of skills) {
70506
- const flags = s.always ? ` ${ui2.C.yellow}[sempre]${ui2.C.reset}` : "";
71332
+ const flags = s.always ? ` ${C5.yellow}[sempre]${C5.reset}` : "";
70507
71333
  process.stdout.write(
70508
- ` ${ui2.C.green}${s.name}${ui2.C.reset}${flags} ${ui2.C.dim}\u2014${ui2.C.reset} ${s.description}
71334
+ ` ${C5.green}${s.name}${C5.reset}${flags} ${C5.dim}\u2014${C5.reset} ${s.description}
70509
71335
  `
70510
71336
  );
70511
71337
  }
70512
- process.stdout.write(
70513
- `${ui2.C.dim}remover: /skill delete <nome>${ui2.C.reset}
70514
- `
70515
- );
71338
+ process.stdout.write(`${C5.dim}remover: /skill delete <nome>${C5.reset}
71339
+ `);
70516
71340
  };
70517
71341
  const handleSkillCommand = (input) => {
70518
71342
  if (input === "/skillcreator") {
@@ -70525,9 +71349,9 @@ ${ui2.C.cyan}skills instaladas${ui2.C.reset} ${ui2.C.dim}(${skillsDir()})${ui2.C
70525
71349
  };
70526
71350
  process.stdout.write(
70527
71351
  `
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}
71352
+ ${C5.greenB}criar skill${C5.reset} ${C5.dim}(/cancelar para abortar)${C5.reset}
71353
+ ${C5.dim}skills ficam disponiveis para TODOS os modelos; o conteudo completo so e carregado quando o pedido casa com a skill.${C5.reset}
71354
+ ${C5.cyan}nome da skill?${C5.reset} ${C5.dim}(ex: xss-recon)${C5.reset}
70531
71355
  `
70532
71356
  );
70533
71357
  return;
@@ -70545,29 +71369,27 @@ ${ui2.C.cyan}nome da skill?${ui2.C.reset} ${ui2.C.dim}(ex: xss-recon)${ui2.C.res
70545
71369
  }
70546
71370
  if (sub === "delete" || sub === "rm" || sub === "remove") {
70547
71371
  if (!arg) {
70548
- process.stdout.write(
70549
- `${ui2.C.yellow}uso: /skill delete <nome>${ui2.C.reset}
70550
- `
70551
- );
71372
+ process.stdout.write(`${C5.yellow}uso: /skill delete <nome>${C5.reset}
71373
+ `);
70552
71374
  return;
70553
71375
  }
70554
71376
  if (deleteSkill(arg)) {
70555
71377
  await agent.refreshSkills();
70556
71378
  process.stdout.write(
70557
- `${ui2.C.green}\u2713 skill '${slugify(arg)}' removida${ui2.C.reset}
71379
+ `${C5.green}\u2713 skill '${slugify(arg)}' removida${C5.reset}
70558
71380
  `
70559
71381
  );
70560
71382
  } else {
70561
71383
  process.stdout.write(
70562
- `${ui2.C.yellow}skill '${arg}' nao encontrada${ui2.C.reset}
71384
+ `${C5.yellow}skill '${arg}' nao encontrada${C5.reset}
70563
71385
  `
70564
71386
  );
70565
71387
  }
70566
71388
  return;
70567
71389
  }
70568
71390
  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}
71391
+ `${C5.yellow}subcomando desconhecido: ${sub}${C5.reset}
71392
+ ${C5.dim}use: /skillcreator | /skills | /skill delete <nome>${C5.reset}
70571
71393
  `
70572
71394
  );
70573
71395
  };
@@ -70575,7 +71397,7 @@ ${ui2.C.dim}use: /skillcreator | /skills | /skill delete <nome>${ui2.C.reset}
70575
71397
  const text2 = sc.bodyLines.join("\n");
70576
71398
  const lines = text2 ? text2.split("\n").length : 0;
70577
71399
  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}
71400
+ `${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
71401
  `
70580
71402
  );
70581
71403
  };
@@ -70584,11 +71406,9 @@ ${ui2.C.dim}use: /skillcreator | /skills | /skill delete <nome>${ui2.C.reset}
70584
71406
  if (!sc) return;
70585
71407
  if (input === "/cancelar" || input === "/cancel") {
70586
71408
  skillCreator = null;
70587
- process.stdout.write(
70588
- `
70589
- ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70590
- `
70591
- );
71409
+ process.stdout.write(`
71410
+ ${C5.dim}criacao de skill cancelada${C5.reset}
71411
+ `);
70592
71412
  return;
70593
71413
  }
70594
71414
  switch (sc.phase) {
@@ -70596,7 +71416,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70596
71416
  const slug = slugify(input);
70597
71417
  if (!slug) {
70598
71418
  process.stdout.write(
70599
- `${ui2.C.yellow}nome invalido \u2014 tente de novo${ui2.C.reset}
71419
+ `${C5.yellow}nome invalido \u2014 tente de novo${C5.reset}
70600
71420
  `
70601
71421
  );
70602
71422
  return;
@@ -70604,22 +71424,20 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70604
71424
  sc.name = slug;
70605
71425
  if (listSkills().some((s) => s.name === slug)) {
70606
71426
  process.stdout.write(
70607
- `${ui2.C.yellow}ja existe uma skill '${slug}' \u2014 sera sobrescrita${ui2.C.reset}
71427
+ `${C5.yellow}ja existe uma skill '${slug}' \u2014 sera sobrescrita${C5.reset}
70608
71428
  `
70609
71429
  );
70610
71430
  }
70611
71431
  sc.phase = "desc";
70612
- process.stdout.write(
70613
- `${ui2.C.cyan}descricao curta (1 linha)?${ui2.C.reset}
70614
- `
70615
- );
71432
+ process.stdout.write(`${C5.cyan}descricao curta (1 linha)?${C5.reset}
71433
+ `);
70616
71434
  return;
70617
71435
  }
70618
71436
  case "desc": {
70619
71437
  sc.description = input;
70620
71438
  sc.phase = "triggers";
70621
71439
  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}
71440
+ `${C5.cyan}palavras-gatilho?${C5.reset} ${C5.dim}(separadas por virgula; Enter usa o proprio nome)${C5.reset}
70623
71441
  `
70624
71442
  );
70625
71443
  return;
@@ -70631,7 +71449,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70631
71449
  sc.phase = "body";
70632
71450
  sc.bodyLines.push(line.replace(/\r$/, ""));
70633
71451
  process.stdout.write(
70634
- `${ui2.C.yellow}isso parece a skill, nao gatilhos \u2014 capturei como conteudo.${ui2.C.reset}
71452
+ `${C5.yellow}isso parece a skill, nao gatilhos \u2014 capturei como conteudo.${C5.reset}
70635
71453
  `
70636
71454
  );
70637
71455
  printBodyTally(sc);
@@ -70640,7 +71458,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70640
71458
  sc.triggers = input ? input.split(",").map((t) => t.trim()).filter(Boolean) : [];
70641
71459
  sc.phase = "body";
70642
71460
  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}
71461
+ `${C5.cyan}cole ou escreva a skill agora${C5.reset} ${C5.dim}(qualquer tamanho). termine com uma linha contendo so /fim${C5.reset}
70644
71462
  `
70645
71463
  );
70646
71464
  return;
@@ -70650,7 +71468,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70650
71468
  const body = sc.bodyLines.join("\n").trim();
70651
71469
  if (!body) {
70652
71470
  process.stdout.write(
70653
- `${ui2.C.yellow}corpo vazio \u2014 cole algum conteudo ou /cancelar${ui2.C.reset}
71471
+ `${C5.yellow}corpo vazio \u2014 cole algum conteudo ou /cancelar${C5.reset}
70654
71472
  `
70655
71473
  );
70656
71474
  return;
@@ -70665,22 +71483,20 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70665
71483
  await agent.refreshSkills();
70666
71484
  process.stdout.write(
70667
71485
  `
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}
71486
+ ${C5.green}\u2713 skill '${res.skill.name}' ${res.overwritten ? "atualizada" : "criada"}${C5.reset} ${C5.dim}(${res.file})${C5.reset}
71487
+ ${C5.dim}ja disponivel para todos os modelos nesta sessao.${C5.reset}
70670
71488
  `
70671
71489
  );
70672
71490
  return;
70673
71491
  }
70674
71492
  if (input === "/desfazer" || input === "/undo") {
70675
71493
  if (sc.bodyLines.length === 0) {
70676
- process.stdout.write(
70677
- `${ui2.C.dim}nada para desfazer${ui2.C.reset}
70678
- `
70679
- );
71494
+ process.stdout.write(`${C5.dim}nada para desfazer${C5.reset}
71495
+ `);
70680
71496
  } else {
70681
71497
  sc.bodyLines.pop();
70682
71498
  process.stdout.write(
70683
- `${ui2.C.yellow}ultimo trecho removido.${ui2.C.reset}
71499
+ `${C5.yellow}ultimo trecho removido.${C5.reset}
70684
71500
  `
70685
71501
  );
70686
71502
  printBodyTally(sc);
@@ -70693,206 +71509,197 @@ ${ui2.C.dim}ja disponivel para todos os modelos nesta sessao.${ui2.C.reset}
70693
71509
  }
70694
71510
  }
70695
71511
  };
71512
+ const printModelResult = (result) => {
71513
+ process.stdout.write(
71514
+ `${result.ok ? `${C5.green}\u2713` : `${C5.red}\u2717`} ${result.message}${C5.reset}
71515
+ `
71516
+ );
71517
+ };
71518
+ const openModelSelector = async () => {
71519
+ const state = agent.getModelSelection();
71520
+ const items = [
71521
+ {
71522
+ label: "Auto \u2014 cadeia de fallback autom\xE1tica",
71523
+ hint: "tenta os modelos em ordem"
71524
+ },
71525
+ ...state.chain.map((c) => ({ label: c.label, hint: c.key }))
71526
+ ];
71527
+ const activeIdx = state.mode === "auto" ? 0 : Math.max(
71528
+ 0,
71529
+ 1 + state.chain.findIndex((c) => c.key === state.activeModelKey)
71530
+ );
71531
+ const choice2 = await inputUI.select("selecionar modelo", items, activeIdx);
71532
+ if (choice2 === null) {
71533
+ process.stdout.write(`${C5.dim}sele\xE7\xE3o de modelo cancelada${C5.reset}
71534
+ `);
71535
+ return;
71536
+ }
71537
+ const arg = choice2 === 0 ? "auto" : state.chain[choice2 - 1].key;
71538
+ try {
71539
+ printModelResult(await agent.setModelSelection(arg));
71540
+ } catch (err) {
71541
+ printFatal(err);
71542
+ }
71543
+ };
70696
71544
  const handleLine = async (line) => {
70697
71545
  if (closing) return;
70698
71546
  const input = line.trim();
70699
71547
  if (skillCreator) {
70700
71548
  await handleSkillCreatorLine(line, input);
70701
- if (!closing) prompt();
70702
71549
  return;
70703
71550
  }
70704
71551
  if (input === "/exit" || input === "/quit") {
70705
71552
  closing = true;
70706
- rl.close();
70707
71553
  return;
70708
71554
  }
70709
71555
  if (input === "/skillcreator" || input === "/skill" || input === "/skills") {
70710
71556
  handleSkillCommand(input);
70711
- if (!closing) prompt();
70712
71557
  return;
70713
71558
  }
70714
71559
  if (input.startsWith("/skill ") || input.startsWith("/skills ")) {
70715
71560
  await handleSkillSubcommand(input);
70716
- if (!closing) prompt();
70717
71561
  return;
70718
71562
  }
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
- }
71563
+ if (input === "/model" || input === "/models") {
71564
+ await openModelSelector();
71565
+ return;
71566
+ }
71567
+ if (input.startsWith("/model ") || input.startsWith("/models ")) {
70730
71568
  const arg = input.replace(/^\/models?\s*/, "");
70731
71569
  try {
70732
- const result = await agent.setModelSelection(arg);
70733
- process.stdout.write(formatModelSelection(result));
70734
- awaitingModelSelection = !result.ok;
71570
+ printModelResult(await agent.setModelSelection(arg));
70735
71571
  } catch (err) {
70736
- process.stderr.write(
70737
- `
70738
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70739
- `
70740
- );
70741
- awaitingModelSelection = false;
71572
+ printFatal(err);
70742
71573
  }
70743
- if (!closing) prompt();
70744
- return;
70745
- }
70746
- if (!input) {
70747
- prompt();
70748
71574
  return;
70749
71575
  }
70750
- if (input === "/model" || input === "/models" || input.startsWith("/model ") || input.startsWith("/models ")) {
70751
- const arg = input.replace(/^\/models?\s*/, "");
71576
+ if (input === "/system") {
71577
+ const sysText = agent.getSystemPrompt();
71578
+ const audit = agent.getSystemPromptAudit();
71579
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
71580
+ const filePath = import_node_path9.default.join(
71581
+ desktopDir(),
71582
+ `clawfast-system-prompt_${stamp}.html`
71583
+ );
71584
+ 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"}`;
71585
+ const b64 = Buffer.from(sysText, "utf8").toString("base64");
71586
+ 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
71587
  try {
70753
- const result = await agent.setModelSelection(arg || "list");
70754
- awaitingModelSelection = !arg && result.ok;
71588
+ await (0, import_promises2.writeFile)(filePath, html, "utf8");
70755
71589
  process.stdout.write(
70756
- formatModelSelection(result, { choosing: awaitingModelSelection })
71590
+ `${C5.green}\u2713 system prompt salvo${C5.reset} ${C5.dim}(${sysText.length.toLocaleString()} caracteres \u2014 abra no navegador)${C5.reset}
71591
+ ${C5.cyan}${filePath}${C5.reset}
71592
+ `
70757
71593
  );
70758
71594
  } catch (err) {
70759
- process.stderr.write(
70760
- `
70761
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
71595
+ process.stdout.write(
71596
+ `${C5.red}\u2717 n\xE3o consegui salvar o arquivo:${C5.reset} ${err instanceof Error ? err.message : String(err)}
70762
71597
  `
70763
71598
  );
70764
- awaitingModelSelection = false;
70765
71599
  }
70766
- if (!closing) prompt();
70767
71600
  return;
70768
71601
  }
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
- );
71602
+ if (input === "/nov" || input === "/novidades") {
70776
71603
  process.stdout.write(
70777
- `\x1B[90mfonte: ${audit.source} | verificado: ${audit.requiredMarkersVerified ? "sim" : "nao"} | chars: ${audit.chars.toLocaleString()}${audit.dumpPath ? ` | dump: ${audit.dumpPath}` : ""}\x1B[0m
71604
+ `
71605
+ ${C5.cyan}${renderNews(clawfastVersion())}${C5.reset}
70778
71606
  `
70779
71607
  );
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();
70784
- return;
70785
- }
70786
- if (input === "/nov" || input === "/novidades") {
70787
- process.stdout.write(`
70788
- ${ui2.C.cyan}${renderNews(clawfastVersion())}${ui2.C.reset}
70789
- `);
70790
- if (!closing) prompt();
70791
71608
  return;
70792
71609
  }
71610
+ if (!input) return;
70793
71611
  process.stdout.write("\n" + agentHeader2());
70794
71612
  activeAbort = new AbortController();
70795
71613
  turnActive = true;
70796
- rl.resume();
71614
+ inputUI.beginTurn(
71615
+ (l) => {
71616
+ if (agent.isRunningCommand()) agent.sendStdin(l);
71617
+ },
71618
+ () => {
71619
+ if (exitArmed) {
71620
+ closing = true;
71621
+ activeAbort?.abort();
71622
+ return;
71623
+ }
71624
+ if (activeAbort && !activeAbort.signal.aborted) {
71625
+ activeAbort.abort();
71626
+ process.stdout.write(
71627
+ `
71628
+ ${C5.dim}interrompido \u2014 Ctrl+C de novo para fechar${C5.reset}
71629
+ `
71630
+ );
71631
+ }
71632
+ armExit();
71633
+ }
71634
+ );
70797
71635
  try {
70798
71636
  await agent.send(input, activeAbort.signal);
70799
71637
  } catch (err) {
70800
- process.stderr.write(
70801
- `
70802
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70803
- `
70804
- );
71638
+ printFatal(err);
70805
71639
  } finally {
71640
+ inputUI.endTurn();
70806
71641
  activeAbort = null;
70807
71642
  turnActive = false;
70808
71643
  }
70809
- if (!closing) prompt();
70810
71644
  };
70811
- prompt();
70812
- rl.on("line", (rawLine) => {
70813
- const line = pasteInput.expand(rawLine);
71645
+ process.removeAllListeners("SIGINT");
71646
+ process.on("SIGINT", () => {
70814
71647
  if (turnActive) {
70815
- if (agent.isRunningCommand()) {
70816
- agent.sendStdin(line);
70817
- }
71648
+ activeAbort?.abort();
70818
71649
  return;
70819
71650
  }
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);
71651
+ void shutdown();
70838
71652
  });
70839
71653
  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"
71654
+ const currentSkillLabel = () => {
71655
+ if (!skillCreator) return void 0;
71656
+ switch (skillCreator.phase) {
71657
+ case "name":
71658
+ return "nome";
71659
+ case "desc":
71660
+ return "descri\xE7\xE3o";
71661
+ case "triggers":
71662
+ return "gatilhos";
71663
+ default:
71664
+ return "skill";
70858
71665
  }
70859
71666
  };
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}`);
71667
+ while (!closing) {
71668
+ const skillLabel = currentSkillLabel();
71669
+ const res = await inputUI.prompt(skillLabel ? { label: skillLabel } : {});
71670
+ if (closing) break;
71671
+ if (res.type === "eof") {
71672
+ closing = true;
71673
+ break;
71674
+ }
71675
+ if (res.type === "sigint") {
71676
+ if (exitArmed) {
71677
+ closing = true;
71678
+ break;
70880
71679
  }
71680
+ process.stdout.write(`${C5.dim}Ctrl+C de novo para fechar${C5.reset}
71681
+ `);
71682
+ armExit();
71683
+ continue;
71684
+ }
71685
+ if (!skillCreator && !res.value.trim()) continue;
71686
+ exitArmed = false;
71687
+ try {
71688
+ await handleLine(res.value);
71689
+ } catch (err) {
71690
+ printFatal(err);
70881
71691
  }
70882
71692
  }
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
- `;
71693
+ await shutdown();
70890
71694
  }
70891
- var import_node_readline3, deepseekEnabled, configuredModelProviders;
71695
+ var import_node_os6, import_node_path9, import_node_fs8, import_promises2, deepseekEnabled, configuredModelProviders;
70892
71696
  var init_index = __esm({
70893
71697
  "index.ts"() {
70894
71698
  "use strict";
70895
- import_node_readline3 = __toESM(require("node:readline"));
71699
+ import_node_os6 = __toESM(require("node:os"));
71700
+ import_node_path9 = __toESM(require("node:path"));
71701
+ import_node_fs8 = require("node:fs");
71702
+ import_promises2 = require("node:fs/promises");
70896
71703
  init_paste_input();
70897
71704
  init_boot_ui();
70898
71705
  init_config();