clawfast 1.0.2 → 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 +1562 -541
  3. package/package.json +1 -1
package/dist/clawfast.cjs CHANGED
@@ -85,9 +85,9 @@ var init_boot_ui = __esm({
85
85
  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
- var fs4 = require("fs");
89
- var path6 = require("path");
90
- var os5 = require("os");
88
+ var fs6 = require("fs");
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]",
@@ -217,7 +217,7 @@ var require_main = __commonJS({
217
217
  if (options && options.path && options.path.length > 0) {
218
218
  if (Array.isArray(options.path)) {
219
219
  for (const filepath of options.path) {
220
- if (fs4.existsSync(filepath)) {
220
+ if (fs6.existsSync(filepath)) {
221
221
  possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
222
222
  }
223
223
  }
@@ -225,15 +225,15 @@ var require_main = __commonJS({
225
225
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
226
226
  }
227
227
  } else {
228
- possibleVaultPath = path6.resolve(process.cwd(), ".env.vault");
228
+ possibleVaultPath = path10.resolve(process.cwd(), ".env.vault");
229
229
  }
230
- if (fs4.existsSync(possibleVaultPath)) {
230
+ if (fs6.existsSync(possibleVaultPath)) {
231
231
  return possibleVaultPath;
232
232
  }
233
233
  return null;
234
234
  }
235
235
  function _resolveHome(envPath) {
236
- return envPath[0] === "~" ? path6.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 = path6.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 path7 of optionPaths) {
281
+ for (const path11 of optionPaths) {
282
282
  try {
283
- const parsed = DotenvModule.parse(fs4.readFileSync(path7, { 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 ${path7} ${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 = path6.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) {
@@ -497,6 +497,101 @@ var init_config = __esm({
497
497
  }
498
498
  });
499
499
 
500
+ // src/version.ts
501
+ var clawfastVersion, isDevVersion, isNewerVersion;
502
+ var init_version = __esm({
503
+ "src/version.ts"() {
504
+ "use strict";
505
+ clawfastVersion = () => true ? "2.0.0" : "0.0.0-dev";
506
+ isDevVersion = () => clawfastVersion().includes("-dev");
507
+ isNewerVersion = (a, b) => {
508
+ const parse3 = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
509
+ const pa = parse3(a);
510
+ const pb = parse3(b);
511
+ const len = Math.max(pa.length, pb.length);
512
+ for (let i = 0; i < len; i++) {
513
+ const da = pa[i] ?? 0;
514
+ const db = pb[i] ?? 0;
515
+ if (da > db) return true;
516
+ if (da < db) return false;
517
+ }
518
+ return false;
519
+ };
520
+ }
521
+ });
522
+
523
+ // src/update.ts
524
+ var import_node_fs2, import_node_path2, import_node_child_process, CHECK_INTERVAL_MS, REGISTRY_URL, cacheFile, readCache, writeCache, getUpdateNotice, refreshUpdateCacheInBackground, runSelfUpdate;
525
+ var init_update = __esm({
526
+ "src/update.ts"() {
527
+ "use strict";
528
+ import_node_fs2 = __toESM(require("node:fs"));
529
+ import_node_path2 = __toESM(require("node:path"));
530
+ import_node_child_process = require("node:child_process");
531
+ init_config();
532
+ init_version();
533
+ CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
534
+ REGISTRY_URL = "https://registry.npmjs.org/clawfast/latest";
535
+ cacheFile = () => import_node_path2.default.join(clawfastHome(), "update-check.json");
536
+ readCache = () => {
537
+ try {
538
+ const raw = import_node_fs2.default.readFileSync(cacheFile(), "utf8");
539
+ const parsed = JSON.parse(raw);
540
+ if (typeof parsed?.latest === "string" && typeof parsed?.lastCheck === "number") {
541
+ return parsed;
542
+ }
543
+ } catch {
544
+ }
545
+ return null;
546
+ };
547
+ writeCache = (cache) => {
548
+ try {
549
+ import_node_fs2.default.mkdirSync(clawfastHome(), { recursive: true });
550
+ import_node_fs2.default.writeFileSync(cacheFile(), JSON.stringify(cache), "utf8");
551
+ } catch {
552
+ }
553
+ };
554
+ getUpdateNotice = (current) => {
555
+ if (isDevVersion()) return null;
556
+ const cache = readCache();
557
+ if (cache && isNewerVersion(cache.latest, current)) {
558
+ return `nova versao ${cache.latest} disponivel (voce tem ${current}) \u2014 rode: clawfast update`;
559
+ }
560
+ return null;
561
+ };
562
+ refreshUpdateCacheInBackground = (current) => {
563
+ if (isDevVersion()) return;
564
+ const cache = readCache();
565
+ if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) return;
566
+ void (async () => {
567
+ try {
568
+ const controller = new AbortController();
569
+ const timer2 = setTimeout(() => controller.abort(), 3e3);
570
+ const res = await fetch(REGISTRY_URL, {
571
+ signal: controller.signal,
572
+ headers: { accept: "application/json" }
573
+ });
574
+ clearTimeout(timer2);
575
+ if (!res.ok) return;
576
+ const body = await res.json();
577
+ if (typeof body.version === "string") {
578
+ writeCache({ lastCheck: Date.now(), latest: body.version });
579
+ }
580
+ } catch {
581
+ }
582
+ })();
583
+ };
584
+ runSelfUpdate = () => new Promise((resolve2) => {
585
+ const child = (0, import_node_child_process.spawn)("npm install -g clawfast@latest", {
586
+ stdio: "inherit",
587
+ shell: true
588
+ });
589
+ child.on("close", (code) => resolve2(code ?? 1));
590
+ child.on("error", () => resolve2(1));
591
+ });
592
+ }
593
+ });
594
+
500
595
  // src/paste-input.ts
501
596
  function createPasteInput(opts = {}) {
502
597
  const input = new import_node_stream.PassThrough();
@@ -604,14 +699,14 @@ var init_paste_input = __esm({
604
699
  /** Replace any paste chips in a submitted line with their real content. */
605
700
  expand(line) {
606
701
  if (this.pastes.size === 0) return line;
607
- let out2 = line;
702
+ let out3 = line;
608
703
  for (const [chip, content] of this.pastes) {
609
- if (out2.includes(chip)) {
610
- out2 = out2.split(chip).join(content);
704
+ if (out3.includes(chip)) {
705
+ out3 = out3.split(chip).join(content);
611
706
  this.pastes.delete(chip);
612
707
  }
613
708
  }
614
- return out2;
709
+ return out3;
615
710
  }
616
711
  /** How many captured pastes are still waiting to be expanded. */
617
712
  pendingCount() {
@@ -634,16 +729,16 @@ function listSkills() {
634
729
  const dir = skillsDir();
635
730
  let entries = [];
636
731
  try {
637
- entries = import_node_fs2.default.readdirSync(dir).filter((f) => f.endsWith(".md"));
732
+ entries = import_node_fs3.default.readdirSync(dir).filter((f) => f.endsWith(".md"));
638
733
  } catch {
639
734
  return [];
640
735
  }
641
736
  const skills = [];
642
737
  for (const entry of entries.sort()) {
643
- const file2 = import_node_path2.default.join(dir, entry);
738
+ const file2 = import_node_path3.default.join(dir, entry);
644
739
  let raw = "";
645
740
  try {
646
- raw = import_node_fs2.default.readFileSync(file2, "utf8");
741
+ raw = import_node_fs3.default.readFileSync(file2, "utf8");
647
742
  } catch {
648
743
  continue;
649
744
  }
@@ -668,9 +763,9 @@ function saveSkill(input) {
668
763
  throw new Error("nome de skill invalido (vazio apos normalizacao)");
669
764
  }
670
765
  const dir = skillsDir();
671
- import_node_fs2.default.mkdirSync(dir, { recursive: true });
672
- const file2 = import_node_path2.default.join(dir, `${slug}.md`);
673
- const overwritten = import_node_fs2.default.existsSync(file2);
766
+ import_node_fs3.default.mkdirSync(dir, { recursive: true });
767
+ const file2 = import_node_path3.default.join(dir, `${slug}.md`);
768
+ const overwritten = import_node_fs3.default.existsSync(file2);
674
769
  const triggers = (input.triggers ?? []).map((t) => t.trim().toLowerCase()).filter(Boolean);
675
770
  const frontmatter = [
676
771
  "---",
@@ -681,7 +776,7 @@ function saveSkill(input) {
681
776
  "---",
682
777
  ""
683
778
  ].join("\n");
684
- import_node_fs2.default.writeFileSync(file2, frontmatter + input.body.trim() + "\n", {
779
+ import_node_fs3.default.writeFileSync(file2, frontmatter + input.body.trim() + "\n", {
685
780
  encoding: "utf8"
686
781
  });
687
782
  return {
@@ -699,9 +794,9 @@ function saveSkill(input) {
699
794
  }
700
795
  function deleteSkill(name25) {
701
796
  const slug = slugify(name25);
702
- const file2 = import_node_path2.default.join(skillsDir(), `${slug}.md`);
797
+ const file2 = import_node_path3.default.join(skillsDir(), `${slug}.md`);
703
798
  try {
704
- import_node_fs2.default.unlinkSync(file2);
799
+ import_node_fs3.default.unlinkSync(file2);
705
800
  return true;
706
801
  } catch {
707
802
  return false;
@@ -745,14 +840,14 @@ As skills a seguir foram carregadas porque o pedido atual casou com elas (ou est
745
840
  ${blocks}
746
841
  </active_skills>`;
747
842
  }
748
- var import_node_fs2, import_node_path2, skillsDir, slugify, FRONTMATTER_RE, parseFrontmatter, parseTriggers, isTrue, escapeFrontmatterValue;
843
+ var import_node_fs3, import_node_path3, skillsDir, slugify, FRONTMATTER_RE, parseFrontmatter, parseTriggers, isTrue, escapeFrontmatterValue;
749
844
  var init_skills = __esm({
750
845
  "src/skills.ts"() {
751
846
  "use strict";
752
- import_node_fs2 = __toESM(require("node:fs"));
753
- import_node_path2 = __toESM(require("node:path"));
847
+ import_node_fs3 = __toESM(require("node:fs"));
848
+ import_node_path3 = __toESM(require("node:path"));
754
849
  init_config();
755
- skillsDir = () => import_node_path2.default.join(clawfastHome(), "skills");
850
+ skillsDir = () => import_node_path3.default.join(clawfastHome(), "skills");
756
851
  slugify = (name25) => name25.trim().toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
757
852
  FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
758
853
  parseFrontmatter = (raw) => {
@@ -774,6 +869,78 @@ var init_skills = __esm({
774
869
  }
775
870
  });
776
871
 
872
+ // src/news.ts
873
+ var import_node_fs4, import_node_path4, NEWS, latestNewsVersion, renderNews, stateFile, readState, writeState, consumePostUpdateLaunch;
874
+ var init_news = __esm({
875
+ "src/news.ts"() {
876
+ "use strict";
877
+ import_node_fs4 = __toESM(require("node:fs"));
878
+ import_node_path4 = __toESM(require("node:path"));
879
+ init_config();
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
+ ],
889
+ "1.0.3": [
890
+ "Atualizacao: `clawfast update` atualiza o CLI e mostra as boas-vindas; aparece um aviso quando ha versao nova; /nov lista as novidades.",
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.",
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).",
893
+ "Resiliencia a rate limit (429): cai para os outros modelos como contingencia e espera/retenta a cadeia automaticamente."
894
+ ]
895
+ };
896
+ latestNewsVersion = () => {
897
+ const keys = Object.keys(NEWS);
898
+ if (keys.length === 0) return null;
899
+ return keys.sort((a, b) => {
900
+ const pa = a.split(".").map(Number);
901
+ const pb = b.split(".").map(Number);
902
+ for (let i = 0; i < 3; i++) {
903
+ if ((pb[i] ?? 0) !== (pa[i] ?? 0)) return (pb[i] ?? 0) - (pa[i] ?? 0);
904
+ }
905
+ return 0;
906
+ })[0];
907
+ };
908
+ renderNews = (version3) => {
909
+ const key = NEWS[version3] ? version3 : latestNewsVersion();
910
+ if (!key || !NEWS[key]) {
911
+ return "Sem novidades registradas para esta versao.";
912
+ }
913
+ const lines = NEWS[key].map((item) => ` \u2022 ${item}`).join("\n");
914
+ return `Novidades da versao ${key}:
915
+ ${lines}`;
916
+ };
917
+ stateFile = () => import_node_path4.default.join(clawfastHome(), "state.json");
918
+ readState = () => {
919
+ try {
920
+ return JSON.parse(import_node_fs4.default.readFileSync(stateFile(), "utf8"));
921
+ } catch {
922
+ return {};
923
+ }
924
+ };
925
+ writeState = (state) => {
926
+ try {
927
+ import_node_fs4.default.mkdirSync(clawfastHome(), { recursive: true });
928
+ import_node_fs4.default.writeFileSync(stateFile(), JSON.stringify(state), "utf8");
929
+ } catch {
930
+ }
931
+ };
932
+ consumePostUpdateLaunch = (current) => {
933
+ const state = readState();
934
+ const previous = state.lastVersion;
935
+ if (previous !== current) {
936
+ writeState({ ...state, lastVersion: current });
937
+ return Boolean(previous);
938
+ }
939
+ return false;
940
+ };
941
+ }
942
+ });
943
+
777
944
  // ../node_modules/.pnpm/@ai-sdk+provider@3.0.10/node_modules/@ai-sdk/provider/dist/index.mjs
778
945
  function getErrorMessage(error51) {
779
946
  if (error51 == null) {
@@ -1346,10 +1513,10 @@ function mergeDefs(...defs) {
1346
1513
  function cloneDef(schema) {
1347
1514
  return mergeDefs(schema._zod.def);
1348
1515
  }
1349
- function getElementAtPath(obj, path6) {
1350
- if (!path6)
1516
+ function getElementAtPath(obj, path10) {
1517
+ if (!path10)
1351
1518
  return obj;
1352
- return path6.reduce((acc, key) => acc?.[key], obj);
1519
+ return path10.reduce((acc, key) => acc?.[key], obj);
1353
1520
  }
1354
1521
  function promiseAllObject(promisesObj) {
1355
1522
  const keys = Object.keys(promisesObj);
@@ -1677,11 +1844,11 @@ function explicitlyAborted(x, startIndex = 0) {
1677
1844
  }
1678
1845
  return false;
1679
1846
  }
1680
- function prefixIssues(path6, issues) {
1847
+ function prefixIssues(path10, issues) {
1681
1848
  return issues.map((iss) => {
1682
1849
  var _a25;
1683
1850
  (_a25 = iss).path ?? (_a25.path = []);
1684
- iss.path.unshift(path6);
1851
+ iss.path.unshift(path10);
1685
1852
  return iss;
1686
1853
  });
1687
1854
  }
@@ -1899,16 +2066,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1899
2066
  }
1900
2067
  function formatError(error51, mapper = (issue2) => issue2.message) {
1901
2068
  const fieldErrors = { _errors: [] };
1902
- const processError = (error52, path6 = []) => {
2069
+ const processError = (error52, path10 = []) => {
1903
2070
  for (const issue2 of error52.issues) {
1904
2071
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1905
- issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
2072
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1906
2073
  } else if (issue2.code === "invalid_key") {
1907
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
2074
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1908
2075
  } else if (issue2.code === "invalid_element") {
1909
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
2076
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1910
2077
  } else {
1911
- const fullpath = [...path6, ...issue2.path];
2078
+ const fullpath = [...path10, ...issue2.path];
1912
2079
  if (fullpath.length === 0) {
1913
2080
  fieldErrors._errors.push(mapper(issue2));
1914
2081
  } else {
@@ -1935,17 +2102,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1935
2102
  }
1936
2103
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1937
2104
  const result = { errors: [] };
1938
- const processError = (error52, path6 = []) => {
2105
+ const processError = (error52, path10 = []) => {
1939
2106
  var _a25, _b18;
1940
2107
  for (const issue2 of error52.issues) {
1941
2108
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1942
- issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
2109
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1943
2110
  } else if (issue2.code === "invalid_key") {
1944
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
2111
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1945
2112
  } else if (issue2.code === "invalid_element") {
1946
- processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
2113
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1947
2114
  } else {
1948
- const fullpath = [...path6, ...issue2.path];
2115
+ const fullpath = [...path10, ...issue2.path];
1949
2116
  if (fullpath.length === 0) {
1950
2117
  result.errors.push(mapper(issue2));
1951
2118
  continue;
@@ -1977,8 +2144,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1977
2144
  }
1978
2145
  function toDotPath(_path) {
1979
2146
  const segs = [];
1980
- const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1981
- for (const seg of path6) {
2147
+ const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2148
+ for (const seg of path10) {
1982
2149
  if (typeof seg === "number")
1983
2150
  segs.push(`[${seg}]`);
1984
2151
  else if (typeof seg === "symbol")
@@ -12290,11 +12457,11 @@ function _catch(Class2, innerType, catchValue) {
12290
12457
  });
12291
12458
  }
12292
12459
  // @__NO_SIDE_EFFECTS__
12293
- function _pipe(Class2, in_, out2) {
12460
+ function _pipe(Class2, in_, out3) {
12294
12461
  return new Class2({
12295
12462
  type: "pipe",
12296
12463
  in: in_,
12297
- out: out2
12464
+ out: out3
12298
12465
  });
12299
12466
  }
12300
12467
  // @__NO_SIDE_EFFECTS__
@@ -14530,19 +14697,19 @@ function _catch2(innerType, catchValue) {
14530
14697
  function nan(params) {
14531
14698
  return _nan(ZodNaN, params);
14532
14699
  }
14533
- function pipe(in_, out2) {
14700
+ function pipe(in_, out3) {
14534
14701
  return new ZodPipe({
14535
14702
  type: "pipe",
14536
14703
  in: in_,
14537
- out: out2
14704
+ out: out3
14538
14705
  // ...util.normalizeParams(params),
14539
14706
  });
14540
14707
  }
14541
- function codec(in_, out2, params) {
14708
+ function codec(in_, out3, params) {
14542
14709
  return new ZodCodec({
14543
14710
  type: "pipe",
14544
14711
  in: in_,
14545
- out: out2,
14712
+ out: out3,
14546
14713
  transform: params.decode,
14547
14714
  reverseTransform: params.encode
14548
14715
  });
@@ -15481,13 +15648,13 @@ function resolveRef(ref, ctx) {
15481
15648
  if (!ref.startsWith("#")) {
15482
15649
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
15483
15650
  }
15484
- const path6 = ref.slice(1).split("/").filter(Boolean);
15485
- if (path6.length === 0) {
15651
+ const path10 = ref.slice(1).split("/").filter(Boolean);
15652
+ if (path10.length === 0) {
15486
15653
  return ctx.rootSchema;
15487
15654
  }
15488
15655
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
15489
- if (path6[0] === defsKey) {
15490
- const key = path6[1];
15656
+ if (path10[0] === defsKey) {
15657
+ const key = path10[1];
15491
15658
  if (!key || !ctx.defs[key]) {
15492
15659
  throw new Error(`Reference not found: ${ref}`);
15493
15660
  }
@@ -16676,8 +16843,8 @@ var init_parseUtil = __esm({
16676
16843
  init_errors3();
16677
16844
  init_en2();
16678
16845
  makeIssue = (params) => {
16679
- const { data, path: path6, errorMaps, issueData } = params;
16680
- const fullPath = [...path6, ...issueData.path || []];
16846
+ const { data, path: path10, errorMaps, issueData } = params;
16847
+ const fullPath = [...path10, ...issueData.path || []];
16681
16848
  const fullIssue = {
16682
16849
  ...issueData,
16683
16850
  path: fullPath
@@ -16960,11 +17127,11 @@ var init_types = __esm({
16960
17127
  init_parseUtil();
16961
17128
  init_util2();
16962
17129
  ParseInputLazyPath = class {
16963
- constructor(parent, value, path6, key) {
17130
+ constructor(parent, value, path10, key) {
16964
17131
  this._cachedPath = [];
16965
17132
  this.parent = parent;
16966
17133
  this.data = value;
16967
- this._path = path6;
17134
+ this._path = path10;
16968
17135
  this._key = key;
16969
17136
  }
16970
17137
  get path() {
@@ -23003,8 +23170,8 @@ var require_auth_config = __commonJS({
23003
23170
  writeAuthConfig: () => writeAuthConfig
23004
23171
  });
23005
23172
  module2.exports = __toCommonJS(auth_config_exports);
23006
- var fs4 = __toESM2(require("fs"));
23007
- var path6 = __toESM2(require("path"));
23173
+ var fs6 = __toESM2(require("fs"));
23174
+ var path10 = __toESM2(require("path"));
23008
23175
  var import_token_util = require_token_util();
23009
23176
  function getAuthConfigPath() {
23010
23177
  const dataDir = (0, import_token_util.getVercelDataDir)();
@@ -23013,15 +23180,15 @@ var require_auth_config = __commonJS({
23013
23180
  `Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`
23014
23181
  );
23015
23182
  }
23016
- return path6.join(dataDir, "auth.json");
23183
+ return path10.join(dataDir, "auth.json");
23017
23184
  }
23018
23185
  function readAuthConfig() {
23019
23186
  try {
23020
23187
  const authPath = getAuthConfigPath();
23021
- if (!fs4.existsSync(authPath)) {
23188
+ if (!fs6.existsSync(authPath)) {
23022
23189
  return null;
23023
23190
  }
23024
- const content = fs4.readFileSync(authPath, "utf8");
23191
+ const content = fs6.readFileSync(authPath, "utf8");
23025
23192
  if (!content) {
23026
23193
  return null;
23027
23194
  }
@@ -23032,11 +23199,11 @@ var require_auth_config = __commonJS({
23032
23199
  }
23033
23200
  function writeAuthConfig(config3) {
23034
23201
  const authPath = getAuthConfigPath();
23035
- const authDir = path6.dirname(authPath);
23036
- if (!fs4.existsSync(authDir)) {
23037
- fs4.mkdirSync(authDir, { mode: 504, recursive: true });
23202
+ const authDir = path10.dirname(authPath);
23203
+ if (!fs6.existsSync(authDir)) {
23204
+ fs6.mkdirSync(authDir, { mode: 504, recursive: true });
23038
23205
  }
23039
- fs4.writeFileSync(authPath, JSON.stringify(config3, null, 2), { mode: 384 });
23206
+ fs6.writeFileSync(authPath, JSON.stringify(config3, null, 2), { mode: 384 });
23040
23207
  }
23041
23208
  function isValidAccessToken(authConfig, expirationBufferMs = 0) {
23042
23209
  if (!authConfig.token)
@@ -23227,8 +23394,8 @@ var require_token_util = __commonJS({
23227
23394
  saveToken: () => saveToken
23228
23395
  });
23229
23396
  module2.exports = __toCommonJS(token_util_exports);
23230
- var path6 = __toESM2(require("path"));
23231
- var fs4 = __toESM2(require("fs"));
23397
+ var path10 = __toESM2(require("path"));
23398
+ var fs6 = __toESM2(require("fs"));
23232
23399
  var import_token_error = require_token_error();
23233
23400
  var import_token_io = require_token_io();
23234
23401
  var import_auth_config = require_auth_config();
@@ -23240,7 +23407,7 @@ var require_token_util = __commonJS({
23240
23407
  if (!dataDir) {
23241
23408
  return null;
23242
23409
  }
23243
- return path6.join(dataDir, vercelFolder);
23410
+ return path10.join(dataDir, vercelFolder);
23244
23411
  }
23245
23412
  async function getVercelToken2(options) {
23246
23413
  const authConfig = (0, import_auth_config.readAuthConfig)();
@@ -23316,13 +23483,13 @@ var require_token_util = __commonJS({
23316
23483
  "Unable to find project root directory. Have you linked your project with `vc link?`"
23317
23484
  );
23318
23485
  }
23319
- const prjPath = path6.join(dir, ".vercel", "project.json");
23320
- if (!fs4.existsSync(prjPath)) {
23486
+ const prjPath = path10.join(dir, ".vercel", "project.json");
23487
+ if (!fs6.existsSync(prjPath)) {
23321
23488
  throw new import_token_error.VercelOidcTokenError(
23322
23489
  "project.json not found, have you linked your project with `vc link?`"
23323
23490
  );
23324
23491
  }
23325
- const prj = JSON.parse(fs4.readFileSync(prjPath, "utf8"));
23492
+ const prj = JSON.parse(fs6.readFileSync(prjPath, "utf8"));
23326
23493
  if (typeof prj.projectId !== "string" && typeof prj.orgId !== "string") {
23327
23494
  throw new TypeError(
23328
23495
  "Expected a string-valued projectId property. Try running `vc link` to re-link your project."
@@ -23337,11 +23504,11 @@ var require_token_util = __commonJS({
23337
23504
  "Unable to find user data directory. Please reach out to Vercel support."
23338
23505
  );
23339
23506
  }
23340
- const tokenPath = path6.join(dir, "com.vercel.token", `${projectId}.json`);
23507
+ const tokenPath = path10.join(dir, "com.vercel.token", `${projectId}.json`);
23341
23508
  const tokenJson = JSON.stringify(token);
23342
- fs4.mkdirSync(path6.dirname(tokenPath), { mode: 504, recursive: true });
23343
- fs4.writeFileSync(tokenPath, tokenJson);
23344
- fs4.chmodSync(tokenPath, 432);
23509
+ fs6.mkdirSync(path10.dirname(tokenPath), { mode: 504, recursive: true });
23510
+ fs6.writeFileSync(tokenPath, tokenJson);
23511
+ fs6.chmodSync(tokenPath, 432);
23345
23512
  return;
23346
23513
  }
23347
23514
  function loadToken(projectId) {
@@ -23351,11 +23518,11 @@ var require_token_util = __commonJS({
23351
23518
  "Unable to find user data directory. Please reach out to Vercel support."
23352
23519
  );
23353
23520
  }
23354
- const tokenPath = path6.join(dir, "com.vercel.token", `${projectId}.json`);
23355
- if (!fs4.existsSync(tokenPath)) {
23521
+ const tokenPath = path10.join(dir, "com.vercel.token", `${projectId}.json`);
23522
+ if (!fs6.existsSync(tokenPath)) {
23356
23523
  return null;
23357
23524
  }
23358
- const token = JSON.parse(fs4.readFileSync(tokenPath, "utf8"));
23525
+ const token = JSON.parse(fs6.readFileSync(tokenPath, "utf8"));
23359
23526
  assertVercelOidcTokenResponse(token);
23360
23527
  return token;
23361
23528
  }
@@ -25306,7 +25473,7 @@ var init_platform = __esm({
25306
25473
 
25307
25474
  // ../node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api/build/esm/version.js
25308
25475
  var VERSION3;
25309
- var init_version = __esm({
25476
+ var init_version2 = __esm({
25310
25477
  "../node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api/build/esm/version.js"() {
25311
25478
  "use strict";
25312
25479
  VERSION3 = "1.9.0";
@@ -25381,7 +25548,7 @@ var re, isCompatible;
25381
25548
  var init_semver = __esm({
25382
25549
  "../node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api/build/esm/internal/semver.js"() {
25383
25550
  "use strict";
25384
- init_version();
25551
+ init_version2();
25385
25552
  re = /^(\d+)\.(\d+)\.(\d+)(-(.+))?$/;
25386
25553
  isCompatible = _makeCompatibilityCheck(VERSION3);
25387
25554
  }
@@ -25430,7 +25597,7 @@ var init_global_utils = __esm({
25430
25597
  "../node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js"() {
25431
25598
  "use strict";
25432
25599
  init_platform();
25433
- init_version();
25600
+ init_version2();
25434
25601
  init_semver();
25435
25602
  major = VERSION3.split(".")[0];
25436
25603
  GLOBAL_OPENTELEMETRY_API_KEY = Symbol.for("opentelemetry.js.api." + major);
@@ -35381,7 +35548,7 @@ function createOpenRouter(options = {}) {
35381
35548
  );
35382
35549
  const createChatModel = (modelId, settings = {}) => new OpenRouterChatLanguageModel(modelId, settings, {
35383
35550
  provider: "openrouter.chat",
35384
- url: ({ path: path6 }) => `${baseURL}${path6}`,
35551
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35385
35552
  headers: getHeaders,
35386
35553
  compatibility,
35387
35554
  fetch: options.fetch,
@@ -35389,7 +35556,7 @@ function createOpenRouter(options = {}) {
35389
35556
  });
35390
35557
  const createCompletionModel = (modelId, settings = {}) => new OpenRouterCompletionLanguageModel(modelId, settings, {
35391
35558
  provider: "openrouter.completion",
35392
- url: ({ path: path6 }) => `${baseURL}${path6}`,
35559
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35393
35560
  headers: getHeaders,
35394
35561
  compatibility,
35395
35562
  fetch: options.fetch,
@@ -35397,21 +35564,21 @@ function createOpenRouter(options = {}) {
35397
35564
  });
35398
35565
  const createEmbeddingModel = (modelId, settings = {}) => new OpenRouterEmbeddingModel(modelId, settings, {
35399
35566
  provider: "openrouter.embedding",
35400
- url: ({ path: path6 }) => `${baseURL}${path6}`,
35567
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35401
35568
  headers: getHeaders,
35402
35569
  fetch: options.fetch,
35403
35570
  extraBody: options.extraBody
35404
35571
  });
35405
35572
  const createImageModel = (modelId, settings = {}) => new OpenRouterImageModel(modelId, settings, {
35406
35573
  provider: "openrouter.image",
35407
- url: ({ path: path6 }) => `${baseURL}${path6}`,
35574
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35408
35575
  headers: getHeaders,
35409
35576
  fetch: options.fetch,
35410
35577
  extraBody: options.extraBody
35411
35578
  });
35412
35579
  const createVideoModel = (modelId, settings = {}) => new OpenRouterVideoModel(modelId, settings, {
35413
35580
  provider: "openrouter.video",
35414
- url: ({ path: path6 }) => `${baseURL}${path6}`,
35581
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
35415
35582
  headers: getHeaders,
35416
35583
  fetch: options.fetch,
35417
35584
  extraBody: options.extraBody
@@ -39947,37 +40114,37 @@ function createOpenAI(options = {}) {
39947
40114
  );
39948
40115
  const createChatModel = (modelId) => new OpenAIChatLanguageModel(modelId, {
39949
40116
  provider: `${providerName}.chat`,
39950
- url: ({ path: path6 }) => `${baseURL}${path6}`,
40117
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
39951
40118
  headers: getHeaders,
39952
40119
  fetch: options.fetch
39953
40120
  });
39954
40121
  const createCompletionModel = (modelId) => new OpenAICompletionLanguageModel(modelId, {
39955
40122
  provider: `${providerName}.completion`,
39956
- url: ({ path: path6 }) => `${baseURL}${path6}`,
40123
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
39957
40124
  headers: getHeaders,
39958
40125
  fetch: options.fetch
39959
40126
  });
39960
40127
  const createEmbeddingModel = (modelId) => new OpenAIEmbeddingModel(modelId, {
39961
40128
  provider: `${providerName}.embedding`,
39962
- url: ({ path: path6 }) => `${baseURL}${path6}`,
40129
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
39963
40130
  headers: getHeaders,
39964
40131
  fetch: options.fetch
39965
40132
  });
39966
40133
  const createImageModel = (modelId) => new OpenAIImageModel(modelId, {
39967
40134
  provider: `${providerName}.image`,
39968
- url: ({ path: path6 }) => `${baseURL}${path6}`,
40135
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
39969
40136
  headers: getHeaders,
39970
40137
  fetch: options.fetch
39971
40138
  });
39972
40139
  const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
39973
40140
  provider: `${providerName}.transcription`,
39974
- url: ({ path: path6 }) => `${baseURL}${path6}`,
40141
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
39975
40142
  headers: getHeaders,
39976
40143
  fetch: options.fetch
39977
40144
  });
39978
40145
  const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
39979
40146
  provider: `${providerName}.speech`,
39980
- url: ({ path: path6 }) => `${baseURL}${path6}`,
40147
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
39981
40148
  headers: getHeaders,
39982
40149
  fetch: options.fetch
39983
40150
  });
@@ -39992,7 +40159,7 @@ function createOpenAI(options = {}) {
39992
40159
  const createResponsesModel = (modelId) => {
39993
40160
  return new OpenAIResponsesLanguageModel(modelId, {
39994
40161
  provider: `${providerName}.responses`,
39995
- url: ({ path: path6 }) => `${baseURL}${path6}`,
40162
+ url: ({ path: path10 }) => `${baseURL}${path10}`,
39996
40163
  headers: getHeaders,
39997
40164
  fetch: options.fetch,
39998
40165
  fileIdPrefixes: ["file-"]
@@ -45213,7 +45380,7 @@ function supportsMultimodalToolResults(modelName) {
45213
45380
  const normalized = modelName.toLowerCase();
45214
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");
45215
45382
  }
45216
- 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;
45217
45384
  var init_providers = __esm({
45218
45385
  "../lib/ai/providers.ts"() {
45219
45386
  "use strict";
@@ -45373,10 +45540,43 @@ var init_providers = __esm({
45373
45540
  name: "openai",
45374
45541
  apiKey: process.env.OPENAI_API_KEY
45375
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
+ };
45376
45575
  nvidia = createOpenAI({
45377
45576
  name: "nvidia",
45378
45577
  baseURL: process.env.NVIDIA_BASE_URL || "https://integrate.api.nvidia.com/v1",
45379
- apiKey: process.env.NVIDIA_API_KEY
45578
+ apiKey: process.env.NVIDIA_API_KEY,
45579
+ fetch: nvidiaPatchFetch
45380
45580
  });
45381
45581
  deepseek = createOpenAI({
45382
45582
  name: "deepseek",
@@ -45404,7 +45604,9 @@ var init_providers = __esm({
45404
45604
  "model-opus-4.6": nvidia("nvidia/nemotron-3-ultra-550b-a55b"),
45405
45605
  "model-kimi-k2.6": or("qwen/qwen3-coder:free"),
45406
45606
  // NVIDIA build models — primary provider for the local CLI (chat-completions).
45407
- "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
+ ),
45408
45610
  "model-nvidia-kimi-k2.6": nvidia.chat("moonshotai/kimi-k2.6"),
45409
45611
  "model-nvidia-glm-5.1": nvidia.chat("z-ai/glm-5.1"),
45410
45612
  "model-nvidia-qwen3.5-397b": nvidia.chat("qwen/qwen3.5-397b-a17b"),
@@ -45441,8 +45643,8 @@ var init_providers = __esm({
45441
45643
  };
45442
45644
  CLI_MODEL_CHAIN = [
45443
45645
  ...hasEnvValue("NVIDIA_API_KEY") ? [
45444
- "model-nvidia-minimax-m3",
45445
- // NVIDIA minimaxai/minimax-m3
45646
+ "model-nvidia-mistral-medium-3.5",
45647
+ // NVIDIA mistralai/mistral-medium-3.5-128b
45446
45648
  "model-nvidia-kimi-k2.6",
45447
45649
  // NVIDIA moonshotai/kimi-k2.6
45448
45650
  "model-nvidia-glm-5.1",
@@ -45469,7 +45671,7 @@ var init_providers = __esm({
45469
45671
  "model-deepseek-v4-flash": "May 2025",
45470
45672
  "model-opus-4.6": "May 2025",
45471
45673
  "model-kimi-k2.6": "April 2024",
45472
- "model-nvidia-minimax-m3": "Unknown",
45674
+ "model-nvidia-mistral-medium-3.5": "Unknown",
45473
45675
  "model-nvidia-kimi-k2.6": "April 2024",
45474
45676
  "model-nvidia-glm-5.1": "Unknown",
45475
45677
  "model-nvidia-qwen3.5-397b": "Unknown",
@@ -45493,7 +45695,7 @@ var init_providers = __esm({
45493
45695
  "model-deepseek-v4-flash": "DeepSeek V4 Flash",
45494
45696
  "model-opus-4.6": "Anthropic Claude Opus 4.6",
45495
45697
  "model-kimi-k2.6": "Moonshot Kimi K2.6",
45496
- "model-nvidia-minimax-m3": "NVIDIA - MiniMax M3",
45698
+ "model-nvidia-mistral-medium-3.5": "NVIDIA - Mistral Medium 3.5",
45497
45699
  "model-nvidia-kimi-k2.6": "NVIDIA - Moonshot Kimi K2.6",
45498
45700
  "model-nvidia-glm-5.1": "NVIDIA - Z.ai GLM 5.1",
45499
45701
  "model-nvidia-qwen3.5-397b": "NVIDIA - Qwen3.5 397B A17B",
@@ -48528,8 +48730,8 @@ var init_background_process_tracker = __esm({
48528
48730
  /**
48529
48731
  * Normalize file path for comparison
48530
48732
  */
48531
- normalizePath(path6) {
48532
- let normalized = path6.trim().replace(/\/+/g, "/");
48733
+ normalizePath(path10) {
48734
+ let normalized = path10.trim().replace(/\/+/g, "/");
48533
48735
  if (normalized.startsWith("./")) {
48534
48736
  normalized = normalized.slice(2);
48535
48737
  }
@@ -48767,8 +48969,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
48767
48969
  return decodedFile;
48768
48970
  };
48769
48971
  }
48770
- function normalizeWindowsPath(path6) {
48771
- return path6.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
48972
+ function normalizeWindowsPath(path10) {
48973
+ return path10.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
48772
48974
  }
48773
48975
  var import_path;
48774
48976
  var init_module_node = __esm({
@@ -51657,9 +51859,9 @@ async function addSourceContext(frames) {
51657
51859
  LRU_FILE_CONTENTS_CACHE.reduce();
51658
51860
  return frames;
51659
51861
  }
51660
- function getContextLinesFromFile(path6, ranges, output) {
51862
+ function getContextLinesFromFile(path10, ranges, output) {
51661
51863
  return new Promise((resolve2) => {
51662
- const stream = (0, import_node_fs3.createReadStream)(path6);
51864
+ const stream = (0, import_node_fs5.createReadStream)(path10);
51663
51865
  const lineReaded = (0, import_node_readline2.createInterface)({
51664
51866
  input: stream
51665
51867
  });
@@ -51674,7 +51876,7 @@ function getContextLinesFromFile(path6, ranges, output) {
51674
51876
  let rangeStart = range[0];
51675
51877
  let rangeEnd = range[1];
51676
51878
  function onStreamError() {
51677
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path6, 1);
51879
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path10, 1);
51678
51880
  lineReaded.close();
51679
51881
  lineReaded.removeAllListeners();
51680
51882
  destroyStreamAndResolve();
@@ -51735,8 +51937,8 @@ function clearLineContext(frame2) {
51735
51937
  delete frame2.context_line;
51736
51938
  delete frame2.post_context;
51737
51939
  }
51738
- function shouldSkipContextLinesForFile(path6) {
51739
- return path6.startsWith("node:") || path6.endsWith(".min.js") || path6.endsWith(".min.cjs") || path6.endsWith(".min.mjs") || path6.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:");
51740
51942
  }
51741
51943
  function shouldSkipContextLinesForFrame(frame2) {
51742
51944
  if (void 0 !== frame2.lineno && frame2.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -51755,22 +51957,22 @@ function makeLineReaderRanges(lines) {
51755
51957
  const line = lines[0];
51756
51958
  if ("number" != typeof line) return [];
51757
51959
  let current = makeContextRange(line);
51758
- const out2 = [];
51960
+ const out3 = [];
51759
51961
  while (true) {
51760
51962
  if (i === lines.length - 1) {
51761
- out2.push(current);
51963
+ out3.push(current);
51762
51964
  break;
51763
51965
  }
51764
51966
  const next = lines[i + 1];
51765
51967
  if ("number" != typeof next) break;
51766
51968
  if (next <= current[1]) current[1] = next + DEFAULT_LINES_OF_CONTEXT;
51767
51969
  else {
51768
- out2.push(current);
51970
+ out3.push(current);
51769
51971
  current = makeContextRange(next);
51770
51972
  }
51771
51973
  i++;
51772
51974
  }
51773
- return out2;
51975
+ return out3;
51774
51976
  }
51775
51977
  function makeContextRange(line) {
51776
51978
  return [
@@ -51807,12 +52009,12 @@ function snipLine(line, colno) {
51807
52009
  if (end < lineLength) newLine += "...";
51808
52010
  return newLine;
51809
52011
  }
51810
- var import_node_fs3, import_node_readline2, LRU_FILE_CONTENTS_CACHE, LRU_FILE_CONTENTS_FS_READ_FAILED, DEFAULT_LINES_OF_CONTEXT, MAX_CONTEXTLINES_COLNO, MAX_CONTEXTLINES_LINENO;
52012
+ var import_node_fs5, import_node_readline2, LRU_FILE_CONTENTS_CACHE, LRU_FILE_CONTENTS_FS_READ_FAILED, DEFAULT_LINES_OF_CONTEXT, MAX_CONTEXTLINES_COLNO, MAX_CONTEXTLINES_LINENO;
51811
52013
  var init_context_lines_node = __esm({
51812
52014
  "../node_modules/.pnpm/posthog-node@5.35.13_rxjs@7.8.2/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs"() {
51813
52015
  "use strict";
51814
52016
  init_dist8();
51815
- import_node_fs3 = require("node:fs");
52017
+ import_node_fs5 = require("node:fs");
51816
52018
  import_node_readline2 = require("node:readline");
51817
52019
  LRU_FILE_CONTENTS_CACHE = new error_tracking_exports.ReduceableCache(25);
51818
52020
  LRU_FILE_CONTENTS_FS_READ_FAILED = new error_tracking_exports.ReduceableCache(20);
@@ -51844,7 +52046,7 @@ var init_relative_path_node = __esm({
51844
52046
 
51845
52047
  // ../node_modules/.pnpm/posthog-node@5.35.13_rxjs@7.8.2/node_modules/posthog-node/dist/version.mjs
51846
52048
  var version2;
51847
- var init_version2 = __esm({
52049
+ var init_version3 = __esm({
51848
52050
  "../node_modules/.pnpm/posthog-node@5.35.13_rxjs@7.8.2/node_modules/posthog-node/dist/version.mjs"() {
51849
52051
  "use strict";
51850
52052
  version2 = "5.35.13";
@@ -52962,7 +53164,7 @@ var MINIMUM_POLLING_INTERVAL, THIRTY_SECONDS, MAX_CACHE_SIZE, WAITUNTIL_DEBOUNCE
52962
53164
  var init_client = __esm({
52963
53165
  "../node_modules/.pnpm/posthog-node@5.35.13_rxjs@7.8.2/node_modules/posthog-node/dist/client.mjs"() {
52964
53166
  "use strict";
52965
- init_version2();
53167
+ init_version3();
52966
53168
  init_dist8();
52967
53169
  init_types5();
52968
53170
  init_feature_flag_evaluations();
@@ -55288,8 +55490,8 @@ async function createE2BPtyHandle(sandbox, opts) {
55288
55490
  sendInput(bytes) {
55289
55491
  return pty.sendInput(pid, bytes);
55290
55492
  },
55291
- async resize(cols, rows) {
55292
- await pty.resize(pid, { cols, rows });
55493
+ async resize(cols2, rows) {
55494
+ await pty.resize(pid, { cols: cols2, rows });
55293
55495
  },
55294
55496
  async kill() {
55295
55497
  const killed = await pty.kill(pid);
@@ -55430,9 +55632,9 @@ var init_pty_session_manager = __esm({
55430
55632
  consumeDelta(session) {
55431
55633
  const total = this.totalBufferBytes(session);
55432
55634
  const start = Math.min(session.readCursor, total);
55433
- const out2 = this.sliceBuffer(session, start, total);
55635
+ const out3 = this.sliceBuffer(session, start, total);
55434
55636
  session.readCursor = total;
55435
- return out2;
55637
+ return out3;
55436
55638
  }
55437
55639
  /**
55438
55640
  * Returns the full accumulated buffer without advancing `readCursor`.
@@ -55490,7 +55692,7 @@ var init_pty_session_manager = __esm({
55490
55692
  }
55491
55693
  sliceBuffer(session, start, end) {
55492
55694
  if (end <= start) return new Uint8Array(0);
55493
- const out2 = new Uint8Array(end - start);
55695
+ const out3 = new Uint8Array(end - start);
55494
55696
  let outOffset = 0;
55495
55697
  let cursor = 0;
55496
55698
  for (const chunk of session.buffer) {
@@ -55503,11 +55705,11 @@ var init_pty_session_manager = __esm({
55503
55705
  if (chunkStart >= end) break;
55504
55706
  const sliceStart = Math.max(0, start - chunkStart);
55505
55707
  const sliceEnd = Math.min(chunk.byteLength, end - chunkStart);
55506
- out2.set(chunk.subarray(sliceStart, sliceEnd), outOffset);
55708
+ out3.set(chunk.subarray(sliceStart, sliceEnd), outOffset);
55507
55709
  outOffset += sliceEnd - sliceStart;
55508
55710
  cursor = chunkEnd;
55509
55711
  }
55510
- return out2;
55712
+ return out3;
55511
55713
  }
55512
55714
  async killAndRemove(session, _reason) {
55513
55715
  if (session.closing) {
@@ -55765,7 +55967,7 @@ var require_xterm_headless = __commonJS({
55765
55967
  };
55766
55968
  Object.defineProperty(t2, "__esModule", { value: true }), t2.InputHandler = t2.WindowsOptionsReportType = void 0, t2.isValidColorIndex = k;
55767
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;
55768
- function C4(e3, t3) {
55970
+ function C5(e3, t3) {
55769
55971
  if (e3 > 24) return t3.setWinLines || false;
55770
55972
  switch (e3) {
55771
55973
  case 1:
@@ -55900,7 +56102,7 @@ var require_xterm_headless = __commonJS({
55900
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);
55901
56103
  }
55902
56104
  registerCsiHandler(e3, t3) {
55903
- 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)));
55904
56106
  }
55905
56107
  registerDcsHandler(e3, t3) {
55906
56108
  return this._parser.registerDcsHandler(e3, new v.DcsHandler(t3));
@@ -56414,7 +56616,7 @@ var require_xterm_headless = __commonJS({
56414
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;
56415
56617
  }
56416
56618
  windowOptions(e3) {
56417
- if (!C4(e3.params[0], this._optionsService.rawOptions.windowOptions)) return true;
56619
+ if (!C5(e3.params[0], this._optionsService.rawOptions.windowOptions)) return true;
56418
56620
  const t3 = e3.length > 1 ? e3.params[1] : 0;
56419
56621
  switch (e3.params[0]) {
56420
56622
  case 14:
@@ -61541,12 +61743,12 @@ function applyDelta(source, delta) {
61541
61743
  zDelta.pos += cnt;
61542
61744
  break;
61543
61745
  case ";": {
61544
- const out2 = zOut.toByteArray(source);
61545
- if (cnt !== checksum(out2))
61746
+ const out3 = zOut.toByteArray(source);
61747
+ if (cnt !== checksum(out3))
61546
61748
  throw new Error("bad checksum");
61547
61749
  if (total !== limit)
61548
61750
  throw new Error("generated size does not match predicted size");
61549
- return out2;
61751
+ return out3;
61550
61752
  }
61551
61753
  default:
61552
61754
  throw new Error("unknown delta operator");
@@ -66120,11 +66322,11 @@ async function createCentrifugoPtyHandle(sandbox, opts) {
66120
66322
  };
66121
66323
  await publish(payload);
66122
66324
  },
66123
- async resize(cols, rows) {
66325
+ async resize(cols2, rows) {
66124
66326
  const payload = {
66125
66327
  type: "pty_resize",
66126
66328
  sessionId,
66127
- cols,
66329
+ cols: cols2,
66128
66330
  rows,
66129
66331
  targetConnectionId: connectionId
66130
66332
  };
@@ -66359,7 +66561,7 @@ In using these tools, adhere to the following guidelines:
66359
66561
  timeout,
66360
66562
  interactive
66361
66563
  }, { toolCallId, abortSignal }) => {
66362
- const cols = DEFAULT_PTY_COLS;
66564
+ const cols2 = DEFAULT_PTY_COLS;
66363
66565
  const rows = DEFAULT_PTY_ROWS;
66364
66566
  let activePtySessionId;
66365
66567
  let emitQueue = Promise.resolve();
@@ -66454,20 +66656,20 @@ In using these tools, adhere to the following guidelines:
66454
66656
  }
66455
66657
  }
66456
66658
  const session = await ptySessionManager2.create(chatId, {
66457
- cols,
66659
+ cols: cols2,
66458
66660
  rows,
66459
66661
  createHandle: async () => {
66460
66662
  if (isCentrifugo) {
66461
66663
  const { createCentrifugoPtyHandle: createCentrifugoPtyHandle2 } = await Promise.resolve().then(() => (init_centrifugo_pty_adapter(), centrifugo_pty_adapter_exports));
66462
66664
  return createCentrifugoPtyHandle2(sandbox, {
66463
66665
  command,
66464
- cols,
66666
+ cols: cols2,
66465
66667
  rows,
66466
66668
  envs: caidoEnvVars
66467
66669
  });
66468
66670
  }
66469
66671
  return createE2BPtyHandle(sandbox, {
66470
- cols,
66672
+ cols: cols2,
66471
66673
  rows,
66472
66674
  envs: caidoEnvVars
66473
66675
  });
@@ -67146,8 +67348,8 @@ var init_logger2 = __esm({
67146
67348
  });
67147
67349
 
67148
67350
  // ../lib/ai/tools/file.ts
67149
- function isSpritPath(path6) {
67150
- return path6.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
67351
+ function isSpritPath(path10) {
67352
+ return path10.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
67151
67353
  }
67152
67354
  function getViewSandboxType(sandbox) {
67153
67355
  return isCentrifugoSandbox(sandbox) ? "centrifugo" : "e2b";
@@ -67178,7 +67380,7 @@ function captureFileViewImageUsage(args) {
67178
67380
  const {
67179
67381
  context: context2,
67180
67382
  sandbox,
67181
- path: path6,
67383
+ path: path10,
67182
67384
  outcome,
67183
67385
  durationMs,
67184
67386
  mediaType,
@@ -67196,7 +67398,7 @@ function captureFileViewImageUsage(args) {
67196
67398
  model: getActiveModelName(context2),
67197
67399
  configured_model: context2.modelName,
67198
67400
  sandbox_type: getViewSandboxType(sandbox),
67199
- file_extension: getFileExtension(path6),
67401
+ file_extension: getFileExtension(path10),
67200
67402
  outcome,
67201
67403
  success: outcome === "success",
67202
67404
  duration_ms: durationMs,
@@ -67270,22 +67472,22 @@ async function runSandboxCommand(sandbox, command, envVars, timeoutMs = 6e4) {
67270
67472
  function isWindowsSandbox(sandbox) {
67271
67473
  return isCentrifugoSandbox(sandbox) && sandbox.isWindows();
67272
67474
  }
67273
- function getWindowsNativePath(path6) {
67274
- if (/^[A-Za-z]:[\\/]/.test(path6)) return path6;
67275
- if (path6.startsWith("/tmp/")) {
67276
- return `C:\\temp${path6.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, "\\")}`;
67277
67479
  }
67278
- return path6.replace(/\//g, "\\");
67480
+ return path10.replace(/\//g, "\\");
67279
67481
  }
67280
- function getPythonPathForSandbox(sandbox, path6) {
67281
- return isWindowsSandbox(sandbox) ? getWindowsNativePath(path6) : path6;
67482
+ function getPythonPathForSandbox(sandbox, path10) {
67483
+ return isWindowsSandbox(sandbox) ? getWindowsNativePath(path10) : path10;
67282
67484
  }
67283
- function toWindowsBashPath(path6) {
67284
- const drive = path6.match(/^([A-Za-z]):[\\/](.*)$/);
67485
+ function toWindowsBashPath(path10) {
67486
+ const drive = path10.match(/^([A-Za-z]):[\\/](.*)$/);
67285
67487
  if (drive) {
67286
67488
  return `/${drive[1].toLowerCase()}/${drive[2].replace(/\\/g, "/")}`;
67287
67489
  }
67288
- return path6.replace(/\\/g, "/");
67490
+ return path10.replace(/\\/g, "/");
67289
67491
  }
67290
67492
  async function detectSandboxShell(sandbox) {
67291
67493
  if (!isWindowsSandbox(sandbox)) return "bash";
@@ -67324,8 +67526,8 @@ PY`;
67324
67526
  }
67325
67527
  }
67326
67528
  }
67327
- async function getSandboxFileState(sandbox, path6) {
67328
- const pythonPath = getPythonPathForSandbox(sandbox, path6);
67529
+ async function getSandboxFileState(sandbox, path10) {
67530
+ const pythonPath = getPythonPathForSandbox(sandbox, path10);
67329
67531
  const result = await runPythonScript(
67330
67532
  sandbox,
67331
67533
  FILE_STATE_SCRIPT,
@@ -67342,23 +67544,23 @@ async function getSandboxFileState(sandbox, path6) {
67342
67544
  if (result.exitCode !== 0) {
67343
67545
  return {
67344
67546
  kind: "unknown",
67345
- path: path6,
67547
+ path: path10,
67346
67548
  error: result.stderr || result.stdout || "file state command failed"
67347
67549
  };
67348
67550
  }
67349
67551
  try {
67350
67552
  const payload = JSON.parse(result.stdout.trim());
67351
67553
  if (payload.kind === "file" && typeof payload.sizeBytes === "number" && Number.isFinite(payload.sizeBytes)) {
67352
- return { ...payload, path: path6 };
67554
+ return { ...payload, path: path10 };
67353
67555
  }
67354
67556
  if (payload.kind === "missing" || payload.kind === "not_file") {
67355
- return { ...payload, path: path6 };
67557
+ return { ...payload, path: path10 };
67356
67558
  }
67357
67559
  } catch {
67358
67560
  }
67359
67561
  return {
67360
67562
  kind: "unknown",
67361
- path: path6,
67563
+ path: path10,
67362
67564
  error: result.stderr || result.stdout || "invalid file state response"
67363
67565
  };
67364
67566
  }
@@ -67390,8 +67592,8 @@ ${numberedContent}${truncatedNotice}${footerNotice}`;
67390
67592
  })
67391
67593
  };
67392
67594
  }
67393
- async function readSandboxTextFile(sandbox, path6, range) {
67394
- const pythonPath = getPythonPathForSandbox(sandbox, path6);
67595
+ async function readSandboxTextFile(sandbox, path10, range) {
67596
+ const pythonPath = getPythonPathForSandbox(sandbox, path10);
67395
67597
  const envVars = {
67396
67598
  HACKERAI_FILE_READ_PATH: pythonPath,
67397
67599
  HACKERAI_FILE_READ_RANGE_START: String(range?.[0] ?? 0),
@@ -67419,40 +67621,40 @@ async function readSandboxTextFile(sandbox, path6, range) {
67419
67621
  }
67420
67622
  return payload;
67421
67623
  }
67422
- async function readSandboxTextFileWithFallback(sandbox, path6, range) {
67624
+ async function readSandboxTextFileWithFallback(sandbox, path10, range) {
67423
67625
  try {
67424
- return await readSandboxTextFile(sandbox, path6, range);
67626
+ return await readSandboxTextFile(sandbox, path10, range);
67425
67627
  } catch (error51) {
67426
67628
  const errorMessage = error51 instanceof Error ? error51.message : String(error51);
67427
67629
  if (errorMessage.startsWith("Invalid ") || errorMessage.includes("File not found")) {
67428
67630
  throw error51;
67429
67631
  }
67430
- const state = await getSandboxFileState(sandbox, path6);
67632
+ const state = await getSandboxFileState(sandbox, path10);
67431
67633
  if (state.kind === "unknown") {
67432
67634
  throw new Error(
67433
- `Unable to determine file size for ${path6}; 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}`
67434
67636
  );
67435
67637
  }
67436
67638
  if (state.kind === "missing") {
67437
- throw new Error(`File not found or is not a regular file: ${path6}`);
67639
+ throw new Error(`File not found or is not a regular file: ${path10}`);
67438
67640
  }
67439
67641
  if (state.kind === "not_file") {
67440
- throw new Error(`File is not a regular file: ${path6}`);
67642
+ throw new Error(`File is not a regular file: ${path10}`);
67441
67643
  }
67442
67644
  if (state.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
67443
67645
  if (range) {
67444
67646
  throw new Error(
67445
- `Unable to perform a bounded range read for ${path6}, 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.`
67446
67648
  );
67447
67649
  }
67448
67650
  return {
67449
- path: path6,
67651
+ path: path10,
67450
67652
  sizeBytes: state.sizeBytes,
67451
67653
  totalLines: 0,
67452
67654
  tooLarge: true
67453
67655
  };
67454
67656
  }
67455
- const fileContent = await sandbox.files.read(path6, {
67657
+ const fileContent = await sandbox.files.read(path10, {
67456
67658
  user: "user"
67457
67659
  });
67458
67660
  const lines = fileContent.split("\n");
@@ -67481,7 +67683,7 @@ async function readSandboxTextFileWithFallback(sandbox, path6, range) {
67481
67683
  const startIndex = start - 1;
67482
67684
  const endIndex = end === -1 ? lines.length : end;
67483
67685
  return {
67484
- path: path6,
67686
+ path: path10,
67485
67687
  sizeBytes: Buffer.byteLength(fileContent),
67486
67688
  totalLines: lines.length,
67487
67689
  content: lines.slice(startIndex, endIndex).join("\n"),
@@ -67489,7 +67691,7 @@ async function readSandboxTextFileWithFallback(sandbox, path6, range) {
67489
67691
  };
67490
67692
  }
67491
67693
  return {
67492
- path: path6,
67694
+ path: path10,
67493
67695
  sizeBytes: Buffer.byteLength(fileContent),
67494
67696
  totalLines: lines.length,
67495
67697
  content: fileContent,
@@ -67497,7 +67699,7 @@ async function readSandboxTextFileWithFallback(sandbox, path6, range) {
67497
67699
  };
67498
67700
  }
67499
67701
  }
67500
- async function appendSandboxTextFile(sandbox, path6, text2) {
67702
+ async function appendSandboxTextFile(sandbox, path10, text2) {
67501
67703
  const tempPath = `/tmp/hackerai_append_${Date.now()}_${Math.random().toString(36).slice(2)}.tmp`;
67502
67704
  await sandbox.files.write(tempPath, text2, {
67503
67705
  user: "user"
@@ -67506,7 +67708,7 @@ async function appendSandboxTextFile(sandbox, path6, text2) {
67506
67708
  sandbox,
67507
67709
  APPEND_TEXT_FILE_SCRIPT,
67508
67710
  {
67509
- HACKERAI_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path6),
67711
+ HACKERAI_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path10),
67510
67712
  HACKERAI_FILE_APPEND_SOURCE_PATH: getPythonPathForSandbox(
67511
67713
  sandbox,
67512
67714
  tempPath
@@ -67518,13 +67720,13 @@ async function appendSandboxTextFile(sandbox, path6, text2) {
67518
67720
  throw new Error(result.stderr || result.stdout || "Failed to append file");
67519
67721
  }
67520
67722
  }
67521
- async function readSandboxFileForView(sandbox, path6, includeData) {
67723
+ async function readSandboxFileForView(sandbox, path10, includeData) {
67522
67724
  if (isCentrifugoSandbox(sandbox) && sandbox.isWindows()) {
67523
67725
  throw new Error(
67524
67726
  "The view action is not available for Windows local sandboxes yet. Use a Linux/E2B sandbox or inspect the image manually."
67525
67727
  );
67526
67728
  }
67527
- const sandboxPath = getSandboxViewPath(sandbox, path6);
67729
+ const sandboxPath = getSandboxViewPath(sandbox, path10);
67528
67730
  const viewEnvVars = {
67529
67731
  HACKERAI_FILE_VIEW_PATH: sandboxPath,
67530
67732
  HACKERAI_FILE_VIEW_INCLUDE_DATA: includeData ? "1" : "0",
@@ -67867,19 +68069,19 @@ try:
67867
68069
  except OSError:
67868
68070
  pass
67869
68071
  `;
67870
- getFilename = (path6) => path6.split("/").pop() || path6;
67871
- getFileExtension = (path6) => {
67872
- const filename = getFilename(path6);
68072
+ getFilename = (path10) => path10.split("/").pop() || path10;
68073
+ getFileExtension = (path10) => {
68074
+ const filename = getFilename(path10);
67873
68075
  const dotIndex = filename.lastIndexOf(".");
67874
68076
  if (dotIndex <= 0 || dotIndex === filename.length - 1) return void 0;
67875
68077
  return filename.slice(dotIndex + 1).toLowerCase();
67876
68078
  };
67877
- getSandboxViewPath = (sandbox, path6) => {
68079
+ getSandboxViewPath = (sandbox, path10) => {
67878
68080
  const maybeSandbox = sandbox;
67879
- if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path6.startsWith("/tmp/")) {
67880
- return `C:\\temp${path6.slice(4).replace(/\//g, "\\")}`;
68081
+ if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path10.startsWith("/tmp/")) {
68082
+ return `C:\\temp${path10.slice(4).replace(/\//g, "\\")}`;
67881
68083
  }
67882
- return path6;
68084
+ return path10;
67883
68085
  };
67884
68086
  stripTrailingWs = (line) => line.replace(/[ \t]+$/u, "");
67885
68087
  editSchema = external_exports.object({
@@ -67953,7 +68155,7 @@ ${instructionsDescription}`,
67953
68155
  "A list of edits to be sequentially applied to the file. Required for `edit` action."
67954
68156
  )
67955
68157
  }),
67956
- execute: async ({ action, path: path6, text: text2, range, edits }) => {
68158
+ execute: async ({ action, path: path10, text: text2, range, edits }) => {
67957
68159
  try {
67958
68160
  const { sandbox } = await sandboxManager.getSandbox();
67959
68161
  switch (action) {
@@ -67963,7 +68165,7 @@ ${instructionsDescription}`,
67963
68165
  captureFileViewImageUsage({
67964
68166
  context: context2,
67965
68167
  sandbox,
67966
- path: path6,
68168
+ path: path10,
67967
68169
  outcome: "unsupported_model",
67968
68170
  durationMs: Date.now() - viewStartedAt,
67969
68171
  failureReason: "unsupported_model"
@@ -67972,26 +68174,26 @@ ${instructionsDescription}`,
67972
68174
  }
67973
68175
  let viewPayload;
67974
68176
  try {
67975
- viewPayload = await readSandboxFileForView(sandbox, path6, false);
68177
+ viewPayload = await readSandboxFileForView(sandbox, path10, false);
67976
68178
  } catch (error51) {
67977
68179
  captureFileViewImageUsage({
67978
68180
  context: context2,
67979
68181
  sandbox,
67980
- path: path6,
68182
+ path: path10,
67981
68183
  outcome: "inspection_failed",
67982
68184
  durationMs: Date.now() - viewStartedAt,
67983
68185
  failureReason: classifyFileViewError(error51)
67984
68186
  });
67985
68187
  throw error51;
67986
68188
  }
67987
- const filename = getFilename(path6);
68189
+ const filename = getFilename(path10);
67988
68190
  let previewFiles = [];
67989
68191
  let previewUploadError;
67990
68192
  try {
67991
68193
  previewFiles = await uploadViewPreviewFiles({
67992
68194
  context: context2,
67993
68195
  sandbox,
67994
- sourcePath: path6,
68196
+ sourcePath: path10,
67995
68197
  payload: viewPayload
67996
68198
  });
67997
68199
  } catch (error51) {
@@ -68005,7 +68207,7 @@ ${instructionsDescription}`,
68005
68207
  user_id: context2.userID,
68006
68208
  sandbox_type: getViewSandboxType(sandbox),
68007
68209
  file_name: filename,
68008
- source_path: path6,
68210
+ source_path: path10,
68009
68211
  kind: viewPayload.kind,
68010
68212
  media_type: viewPayload.mediaType,
68011
68213
  size_bytes: viewPayload.sizeBytes,
@@ -68016,7 +68218,7 @@ ${instructionsDescription}`,
68016
68218
  captureFileViewImageUsage({
68017
68219
  context: context2,
68018
68220
  sandbox,
68019
- path: path6,
68221
+ path: path10,
68020
68222
  outcome: "success",
68021
68223
  durationMs: Date.now() - viewStartedAt,
68022
68224
  mediaType: viewPayload.mediaType,
@@ -68026,7 +68228,7 @@ ${instructionsDescription}`,
68026
68228
  return {
68027
68229
  action: "view",
68028
68230
  content: `Viewing image file: ${filename} (${viewPayload.mediaType}, ${viewPayload.sizeBytes} bytes).`,
68029
- path: path6,
68231
+ path: path10,
68030
68232
  filename,
68031
68233
  mediaType: viewPayload.mediaType,
68032
68234
  sizeBytes: viewPayload.sizeBytes,
@@ -68036,8 +68238,8 @@ ${instructionsDescription}`,
68036
68238
  };
68037
68239
  }
68038
68240
  case "read": {
68039
- const filename = path6.split("/").pop() || path6;
68040
- const spritChunked = isSpritPath(path6);
68241
+ const filename = path10.split("/").pop() || path10;
68242
+ const spritChunked = isSpritPath(path10);
68041
68243
  let effectiveRange = range;
68042
68244
  if (spritChunked) {
68043
68245
  const start = range && range[0] > 0 ? range[0] : 1;
@@ -68050,7 +68252,7 @@ ${instructionsDescription}`,
68050
68252
  }
68051
68253
  const readPayload = await readSandboxTextFileWithFallback(
68052
68254
  sandbox,
68053
- path6,
68255
+ path10,
68054
68256
  effectiveRange
68055
68257
  );
68056
68258
  if (readPayload.tooLarge) {
@@ -68087,46 +68289,46 @@ File is too large to read in full (${formatBytes(readPayload.sizeBytes)}, ${tota
68087
68289
  if (text2 === void 0) {
68088
68290
  return { error: "text is required for write action" };
68089
68291
  }
68090
- await sandbox.files.write(path6, text2, {
68292
+ await sandbox.files.write(path10, text2, {
68091
68293
  user: "user"
68092
68294
  });
68093
- return `File written: ${path6}`;
68295
+ return `File written: ${path10}`;
68094
68296
  }
68095
68297
  case "append": {
68096
68298
  if (text2 === void 0) {
68097
68299
  return { error: "text is required for append action" };
68098
68300
  }
68099
- const existingState = await getSandboxFileState(sandbox, path6);
68301
+ const existingState = await getSandboxFileState(sandbox, path10);
68100
68302
  if (existingState.kind === "unknown") {
68101
68303
  return {
68102
- error: `Cannot append safely because the existing file size could not be determined for ${path6}. ${existingState.error}`
68304
+ error: `Cannot append safely because the existing file size could not be determined for ${path10}. ${existingState.error}`
68103
68305
  };
68104
68306
  }
68105
68307
  if (existingState.kind === "not_file") {
68106
68308
  return {
68107
- error: `Cannot append to ${path6} because it is not a file.`
68309
+ error: `Cannot append to ${path10} because it is not a file.`
68108
68310
  };
68109
68311
  }
68110
68312
  if (existingState.kind === "file" && existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68111
- await appendSandboxTextFile(sandbox, path6, text2);
68313
+ await appendSandboxTextFile(sandbox, path10, text2);
68112
68314
  return {
68113
- content: `File appended: ${path6}
68315
+ content: `File appended: ${path10}
68114
68316
  Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff preview was skipped to avoid loading the entire file into memory.`
68115
68317
  };
68116
68318
  }
68117
68319
  let existingContent = "";
68118
68320
  try {
68119
- existingContent = await sandbox.files.read(path6, {
68321
+ existingContent = await sandbox.files.read(path10, {
68120
68322
  user: "user"
68121
68323
  });
68122
68324
  } catch {
68123
68325
  }
68124
68326
  const newContent = existingContent + text2;
68125
- await sandbox.files.write(path6, newContent, {
68327
+ await sandbox.files.write(path10, newContent, {
68126
68328
  user: "user"
68127
68329
  });
68128
68330
  return {
68129
- content: `File appended: ${path6}`,
68331
+ content: `File appended: ${path10}`,
68130
68332
  originalContent: truncateOutput({
68131
68333
  content: existingContent,
68132
68334
  mode: "read-file"
@@ -68141,31 +68343,31 @@ Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff previ
68141
68343
  if (!edits || edits.length === 0) {
68142
68344
  return { error: "edits array is required for edit action" };
68143
68345
  }
68144
- const existingState = await getSandboxFileState(sandbox, path6);
68346
+ const existingState = await getSandboxFileState(sandbox, path10);
68145
68347
  if (existingState.kind === "unknown") {
68146
68348
  return {
68147
- error: `Cannot edit ${path6} 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}`
68148
68350
  };
68149
68351
  }
68150
68352
  if (existingState.kind === "missing") {
68151
68353
  return {
68152
- error: `Cannot edit file ${path6} - file is empty or does not exist`
68354
+ error: `Cannot edit file ${path10} - file is empty or does not exist`
68153
68355
  };
68154
68356
  }
68155
68357
  if (existingState.kind === "not_file") {
68156
- return { error: `Cannot edit ${path6} because it is not a file.` };
68358
+ return { error: `Cannot edit ${path10} because it is not a file.` };
68157
68359
  }
68158
68360
  if (existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68159
68361
  return {
68160
- error: `File ${path6} 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.`
68161
68363
  };
68162
68364
  }
68163
- const originalContent = await sandbox.files.read(path6, {
68365
+ const originalContent = await sandbox.files.read(path10, {
68164
68366
  user: "user"
68165
68367
  });
68166
68368
  if (!originalContent) {
68167
68369
  return {
68168
- error: `Cannot edit file ${path6} - file is empty or does not exist`
68370
+ error: `Cannot edit file ${path10} - file is empty or does not exist`
68169
68371
  };
68170
68372
  }
68171
68373
  const resolvedEdits = [];
@@ -68210,7 +68412,7 @@ ${hint}` : "")
68210
68412
  }
68211
68413
  }
68212
68414
  }
68213
- await sandbox.files.write(path6, content, {
68415
+ await sandbox.files.write(path10, content, {
68214
68416
  user: "user"
68215
68417
  });
68216
68418
  const lines = content.split("\n");
@@ -68450,11 +68652,11 @@ function findGitBash() {
68450
68652
  if ((0, import_fs.existsSync)(c)) return c;
68451
68653
  }
68452
68654
  try {
68453
- const out2 = (0, import_child_process.execSync)("where git", {
68655
+ const out3 = (0, import_child_process.execSync)("where git", {
68454
68656
  encoding: "utf8",
68455
68657
  stdio: ["ignore", "pipe", "ignore"]
68456
68658
  });
68457
- 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"));
68458
68660
  if (gitExe) {
68459
68661
  const bash = (0, import_path3.join)((0, import_path3.dirname)((0, import_path3.dirname)(gitExe.trim())), "bin", "bash.exe");
68460
68662
  if ((0, import_fs.existsSync)(bash)) return bash;
@@ -68486,20 +68688,20 @@ var init_utils4 = __esm({
68486
68688
 
68487
68689
  // src/local-sandbox.ts
68488
68690
  function inferShellFlag(shell2) {
68489
- const base = import_node_path3.default.basename(shell2).toLowerCase();
68691
+ const base = import_node_path5.default.basename(shell2).toLowerCase();
68490
68692
  if (base === "cmd" || base === "cmd.exe") return "/C";
68491
68693
  if (base === "powershell" || base === "powershell.exe" || base === "pwsh") {
68492
68694
  return "-Command";
68493
68695
  }
68494
68696
  return "-c";
68495
68697
  }
68496
- var import_node_child_process, import_node_fs4, import_node_path3, import_node_os2, import_node_url, import_meta, LocalSandbox;
68698
+ var import_node_child_process2, import_node_fs6, import_node_path5, import_node_os2, import_node_url, import_meta, LocalSandbox;
68497
68699
  var init_local_sandbox = __esm({
68498
68700
  "src/local-sandbox.ts"() {
68499
68701
  "use strict";
68500
- import_node_child_process = require("node:child_process");
68501
- import_node_fs4 = require("node:fs");
68502
- import_node_path3 = __toESM(require("node:path"));
68702
+ import_node_child_process2 = require("node:child_process");
68703
+ import_node_fs6 = require("node:fs");
68704
+ import_node_path5 = __toESM(require("node:path"));
68503
68705
  import_node_os2 = __toESM(require("node:os"));
68504
68706
  import_node_url = require("node:url");
68505
68707
  init_utils4();
@@ -68523,7 +68725,7 @@ var init_local_sandbox = __esm({
68523
68725
  this.shellFlag,
68524
68726
  command
68525
68727
  );
68526
- child = (0, import_node_child_process.spawn)(this.shellBin, spawnSpec.args, {
68728
+ child = (0, import_node_child_process2.spawn)(this.shellBin, spawnSpec.args, {
68527
68729
  cwd,
68528
68730
  env,
68529
68731
  detached: !!opts?.background,
@@ -68597,15 +68799,15 @@ var init_local_sandbox = __esm({
68597
68799
  this.files = {
68598
68800
  write: async (filePath, content) => {
68599
68801
  const resolved = this.resolvePath(filePath);
68600
- await import_node_fs4.promises.mkdir(import_node_path3.default.dirname(resolved), { recursive: true });
68802
+ await import_node_fs6.promises.mkdir(import_node_path5.default.dirname(resolved), { recursive: true });
68601
68803
  const data = typeof content === "string" ? content : content instanceof ArrayBuffer ? Buffer.from(content) : content;
68602
- await import_node_fs4.promises.writeFile(resolved, data);
68804
+ await import_node_fs6.promises.writeFile(resolved, data);
68603
68805
  },
68604
68806
  read: async (filePath) => {
68605
- return import_node_fs4.promises.readFile(this.resolvePath(filePath), "utf8");
68807
+ return import_node_fs6.promises.readFile(this.resolvePath(filePath), "utf8");
68606
68808
  },
68607
68809
  remove: async (filePath) => {
68608
- await import_node_fs4.promises.rm(this.resolvePath(filePath), {
68810
+ await import_node_fs6.promises.rm(this.resolvePath(filePath), {
68609
68811
  recursive: true,
68610
68812
  force: true
68611
68813
  });
@@ -68613,8 +68815,8 @@ var init_local_sandbox = __esm({
68613
68815
  list: async (dirPath = ".") => {
68614
68816
  const resolved = this.resolvePath(dirPath);
68615
68817
  try {
68616
- const entries = await import_node_fs4.promises.readdir(resolved, { withFileTypes: true });
68617
- return entries.filter((e) => e.isFile()).map((e) => ({ name: import_node_path3.default.join(resolved, e.name) }));
68818
+ const entries = await import_node_fs6.promises.readdir(resolved, { withFileTypes: true });
68819
+ return entries.filter((e) => e.isFile()).map((e) => ({ name: import_node_path5.default.join(resolved, e.name) }));
68618
68820
  } catch {
68619
68821
  return [];
68620
68822
  }
@@ -68629,12 +68831,13 @@ var init_local_sandbox = __esm({
68629
68831
  this.shellBin = shell2.shell;
68630
68832
  this.shellFlag = shell2.shellFlag;
68631
68833
  }
68632
- const base = opts?.workdir || process.env.CLI_WORKDIR || import_node_path3.default.join(process.cwd(), "SPRIT");
68633
- this.workdir = import_node_path3.default.resolve(base).replace(/\\/g, "/");
68834
+ const base = opts?.workdir || process.env.CLI_WORKDIR || import_node_path5.default.join(process.cwd(), "SPRIT");
68835
+ this.workdir = import_node_path5.default.resolve(base).replace(/\\/g, "/");
68634
68836
  }
68635
68837
  async init() {
68636
- await import_node_fs4.promises.mkdir(this.workdir, { recursive: true });
68838
+ await import_node_fs6.promises.mkdir(this.workdir, { recursive: true });
68637
68839
  await this.seedReconToolkit();
68840
+ await this.seedAuditToolkit();
68638
68841
  }
68639
68842
  /**
68640
68843
  * Seed the deep-recon toolkit (recon_deep.py + console_recon.js + README)
@@ -68649,8 +68852,8 @@ var init_local_sandbox = __esm({
68649
68852
  const assetsDir = (0, import_node_url.fileURLToPath)(
68650
68853
  new URL("../assets/recon", import_meta.url)
68651
68854
  );
68652
- const destDir = import_node_path3.default.join(this.workdir, "recon");
68653
- await import_node_fs4.promises.mkdir(destDir, { recursive: true });
68855
+ const destDir = import_node_path5.default.join(this.workdir, "recon");
68856
+ await import_node_fs6.promises.mkdir(destDir, { recursive: true });
68654
68857
  const files = [
68655
68858
  ["recon_deep.py", true],
68656
68859
  ["console_recon.js", true],
@@ -68658,17 +68861,40 @@ var init_local_sandbox = __esm({
68658
68861
  ["scope.txt", false]
68659
68862
  ];
68660
68863
  for (const [name25, overwrite] of files) {
68661
- const dest = import_node_path3.default.join(destDir, name25);
68864
+ const dest = import_node_path5.default.join(destDir, name25);
68662
68865
  if (!overwrite) {
68663
68866
  try {
68664
- await import_node_fs4.promises.access(dest);
68867
+ await import_node_fs6.promises.access(dest);
68665
68868
  continue;
68666
68869
  } catch {
68667
68870
  }
68668
68871
  }
68669
68872
  try {
68670
- const content = await import_node_fs4.promises.readFile(import_node_path3.default.join(assetsDir, name25));
68671
- await import_node_fs4.promises.writeFile(dest, content);
68873
+ const content = await import_node_fs6.promises.readFile(import_node_path5.default.join(assetsDir, name25));
68874
+ await import_node_fs6.promises.writeFile(dest, content);
68875
+ } catch {
68876
+ }
68877
+ }
68878
+ } catch {
68879
+ }
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);
68672
68898
  } catch {
68673
68899
  }
68674
68900
  }
@@ -68720,6 +68946,21 @@ EDITING SCRIPTS:
68720
68946
  getOsContext() {
68721
68947
  return this.getSandboxContext();
68722
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
+ }
68723
68964
  getWorkdir() {
68724
68965
  return this.workdir;
68725
68966
  }
@@ -68771,7 +69012,7 @@ EDITING SCRIPTS:
68771
69012
  const pid = child.pid;
68772
69013
  if (pid && import_node_os2.default.platform() === "win32") {
68773
69014
  try {
68774
- (0, import_node_child_process.spawn)("taskkill", ["/PID", String(pid), "/T", "/F"], {
69015
+ (0, import_node_child_process2.spawn)("taskkill", ["/PID", String(pid), "/T", "/F"], {
68775
69016
  windowsHide: true
68776
69017
  });
68777
69018
  return;
@@ -68784,15 +69025,15 @@ EDITING SCRIPTS:
68784
69025
  }
68785
69026
  }
68786
69027
  resolvePath(p) {
68787
- if (import_node_path3.default.isAbsolute(p)) return p;
68788
- return import_node_path3.default.join(this.workdir, p);
69028
+ if (import_node_path5.default.isAbsolute(p)) return p;
69029
+ return import_node_path5.default.join(this.workdir, p);
68789
69030
  }
68790
69031
  isBashLikeShell() {
68791
- const base = import_node_path3.default.basename(this.shellBin).toLowerCase();
69032
+ const base = import_node_path5.default.basename(this.shellBin).toLowerCase();
68792
69033
  return base === "bash" || base === "bash.exe" || base === "sh";
68793
69034
  }
68794
69035
  isCmdShell() {
68795
- const base = import_node_path3.default.basename(this.shellBin).toLowerCase();
69036
+ const base = import_node_path5.default.basename(this.shellBin).toLowerCase();
68796
69037
  return base === "cmd" || base === "cmd.exe";
68797
69038
  }
68798
69039
  getWindowsShellNotes() {
@@ -68996,7 +69237,7 @@ function formatToolCall(toolName, input) {
68996
69237
  return `${C2.cyan}executando${C2.reset} ${C2.bold}$ ${truncate3(cmd, 400)}${C2.reset}${bg}`;
68997
69238
  }
68998
69239
  case "file": {
68999
- const path6 = String(i.path ?? "");
69240
+ const path10 = String(i.path ?? "");
69000
69241
  const brief = i.brief ? `${C2.dim} - ${truncate3(String(i.brief))}${C2.reset}` : "";
69001
69242
  const map2 = {
69002
69243
  write: `${C2.green}criando arquivo${C2.reset}`,
@@ -69007,7 +69248,7 @@ function formatToolCall(toolName, input) {
69007
69248
  };
69008
69249
  const action = typeof i.action === "string" ? i.action : "";
69009
69250
  const label = map2[action] ?? (action ? `${C2.blue}arquivo (${action})${C2.reset}` : `${C2.blue}preparando operacao de arquivo${C2.reset}`);
69010
- const target = path6 ? ` ${C2.bold}${path6}${C2.reset}` : "";
69251
+ const target = path10 ? ` ${C2.bold}${path10}${C2.reset}` : "";
69011
69252
  return `${label}${target}${brief}`;
69012
69253
  }
69013
69254
  case "todo_write":
@@ -69083,7 +69324,7 @@ function killProxy(child) {
69083
69324
  started.delete(child);
69084
69325
  try {
69085
69326
  if (process.platform === "win32") {
69086
- (0, import_node_child_process2.spawnSync)("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
69327
+ (0, import_node_child_process3.spawnSync)("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
69087
69328
  stdio: "ignore"
69088
69329
  });
69089
69330
  } else {
@@ -69114,12 +69355,12 @@ async function ensureProxyReady(id, log2) {
69114
69355
  };
69115
69356
  }
69116
69357
  let freshSetup = false;
69117
- if (!(0, import_node_fs5.existsSync)(dir)) {
69358
+ if (!(0, import_node_fs7.existsSync)(dir)) {
69118
69359
  log2(`${def.label}: baixando o proxy (uma vez) em ${dir} \u2026`);
69119
69360
  const root = proxiesRoot();
69120
- (0, import_node_fs5.mkdirSync)(root, { recursive: true });
69361
+ (0, import_node_fs7.mkdirSync)(root, { recursive: true });
69121
69362
  const cloned = run("git", ["clone", def.repoUrl, dir], root);
69122
- if (!cloned.ok || !(0, import_node_fs5.existsSync)(dir)) {
69363
+ if (!cloned.ok || !(0, import_node_fs7.existsSync)(dir)) {
69123
69364
  return {
69124
69365
  ok: false,
69125
69366
  message: `${def.label}: falha ao clonar o proxy (git).`
@@ -69127,7 +69368,7 @@ async function ensureProxyReady(id, log2) {
69127
69368
  }
69128
69369
  freshSetup = true;
69129
69370
  }
69130
- if (!(0, import_node_fs5.existsSync)(import_node_path4.default.join(dir, "node_modules"))) {
69371
+ if (!(0, import_node_fs7.existsSync)(import_node_path6.default.join(dir, "node_modules"))) {
69131
69372
  log2(`${def.label}: instalando depend\xEAncias (pode demorar) \u2026`);
69132
69373
  if (!run("npm", ["install"], dir).ok) {
69133
69374
  return { ok: false, message: `${def.label}: 'npm install' falhou.` };
@@ -69145,7 +69386,7 @@ async function ensureProxyReady(id, log2) {
69145
69386
  }
69146
69387
  }
69147
69388
  log2(`${def.label}: iniciando o proxy\u2026`);
69148
- const child = (0, import_node_child_process2.spawn)(asShellCommand("npm", ["start"]), {
69389
+ const child = (0, import_node_child_process3.spawn)(asShellCommand("npm", ["start"]), {
69149
69390
  cwd: dir,
69150
69391
  shell: true,
69151
69392
  stdio: ["ignore", "ignore", "ignore"],
@@ -69172,14 +69413,14 @@ async function ensureProxyReady(id, log2) {
69172
69413
  message: `${def.label}: o proxy n\xE3o respondeu em 90s. Tente de novo, ou rode 'npm run login' em ${dir}.`
69173
69414
  };
69174
69415
  }
69175
- var import_node_os3, import_node_path4, import_node_fs5, import_node_child_process2, DEFS, PROXY_MODEL_KEYS, proxyIdForModelKey, proxiesRoot, dirFor, healthUrl, baseUrl, wait, started, exitHooksInstalled, quoteArg, asShellCommand, run, hasCommand;
69416
+ var import_node_os3, import_node_path6, import_node_fs7, import_node_child_process3, DEFS, PROXY_MODEL_KEYS, proxyIdForModelKey, proxiesRoot, dirFor, healthUrl, baseUrl, wait, started, exitHooksInstalled, quoteArg, asShellCommand, run, hasCommand;
69176
69417
  var init_proxy_manager2 = __esm({
69177
69418
  "src/proxy-manager.ts"() {
69178
69419
  "use strict";
69179
69420
  import_node_os3 = __toESM(require("node:os"));
69180
- import_node_path4 = __toESM(require("node:path"));
69181
- import_node_fs5 = require("node:fs");
69182
- import_node_child_process2 = require("node:child_process");
69421
+ import_node_path6 = __toESM(require("node:path"));
69422
+ import_node_fs7 = require("node:fs");
69423
+ import_node_child_process3 = require("node:child_process");
69183
69424
  DEFS = {
69184
69425
  deepseek: {
69185
69426
  id: "deepseek",
@@ -69211,11 +69452,11 @@ var init_proxy_manager2 = __esm({
69211
69452
  if (key === PROXY_MODEL_KEYS.kimi) return "kimi";
69212
69453
  return null;
69213
69454
  };
69214
- proxiesRoot = () => import_node_path4.default.join(
69215
- process.env.CLAWFAST_HOME?.trim() || import_node_path4.default.join(import_node_os3.default.homedir(), ".clawfast"),
69455
+ proxiesRoot = () => import_node_path6.default.join(
69456
+ process.env.CLAWFAST_HOME?.trim() || import_node_path6.default.join(import_node_os3.default.homedir(), ".clawfast"),
69216
69457
  "proxies"
69217
69458
  );
69218
- dirFor = (def) => process.env[def.dirEnv]?.trim() || import_node_path4.default.join(proxiesRoot(), def.folder);
69459
+ dirFor = (def) => process.env[def.dirEnv]?.trim() || import_node_path6.default.join(proxiesRoot(), def.folder);
69219
69460
  healthUrl = (def) => `http://localhost:${def.port}/health`;
69220
69461
  baseUrl = (def) => `http://localhost:${def.port}/v1`;
69221
69462
  wait = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -69224,7 +69465,7 @@ var init_proxy_manager2 = __esm({
69224
69465
  quoteArg = (s) => /[\s"&|<>^()]/.test(s) ? `"${s.replace(/"/g, '\\"')}"` : s;
69225
69466
  asShellCommand = (cmd, args) => [cmd, ...args.map(quoteArg)].join(" ");
69226
69467
  run = (cmd, args, cwd) => {
69227
- const res = (0, import_node_child_process2.spawnSync)(asShellCommand(cmd, args), {
69468
+ const res = (0, import_node_child_process3.spawnSync)(asShellCommand(cmd, args), {
69228
69469
  cwd,
69229
69470
  shell: true,
69230
69471
  stdio: "inherit",
@@ -69234,7 +69475,7 @@ var init_proxy_manager2 = __esm({
69234
69475
  };
69235
69476
  hasCommand = (cmd) => {
69236
69477
  const probe = process.platform === "win32" ? "where" : "which";
69237
- return (0, import_node_child_process2.spawnSync)(asShellCommand(probe, [cmd]), {
69478
+ return (0, import_node_child_process3.spawnSync)(asShellCommand(probe, [cmd]), {
69238
69479
  stdio: "ignore",
69239
69480
  shell: true
69240
69481
  }).status === 0;
@@ -69242,15 +69483,210 @@ var init_proxy_manager2 = __esm({
69242
69483
  }
69243
69484
  });
69244
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
+
69245
69673
  // src/agent.ts
69246
69674
  var agent_exports = {};
69247
69675
  __export(agent_exports, {
69248
69676
  createAgent: () => createAgent
69249
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
+ }
69250
69684
  function looksUnfinished(text2) {
69251
69685
  if (!text2) return false;
69252
- if (/<tool_call/i.test(text2)) return true;
69253
- 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));
69254
69690
  }
69255
69691
  function decideAutoContinue(finishReason, lastStepText, turnToolCalls, autoContinues) {
69256
69692
  if (autoContinues >= MAX_AUTO_CONTINUES) return null;
@@ -69265,8 +69701,12 @@ function decideAutoContinue(finishReason, lastStepText, turnToolCalls, autoConti
69265
69701
  if (!text2 && turnToolCalls === 0) {
69266
69702
  return { nudge: true, reason: "resposta vazia do modelo" };
69267
69703
  }
69268
- if (turnToolCalls > 0 && looksUnfinished(text2)) {
69269
- 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
+ };
69270
69710
  }
69271
69711
  if (turnToolCalls === 0 && looksUnfinished(text2) && !BENIGN_CLOSER_RE.test(text2.slice(-200))) {
69272
69712
  return {
@@ -69379,7 +69819,7 @@ async function createAgent() {
69379
69819
  const sandboxManager = new LocalSandboxManager(sandbox);
69380
69820
  const writer = createConsoleWriter();
69381
69821
  const render = createRenderer();
69382
- const initialModelName = CLI_MODEL_CHAIN[0] ?? "model-nvidia-minimax-m3";
69822
+ const initialModelName = CLI_MODEL_CHAIN[0] ?? "model-nvidia-mistral-medium-3.5";
69383
69823
  let currentModelName = initialModelName;
69384
69824
  let selectedModelKey = null;
69385
69825
  const context2 = {
@@ -69447,6 +69887,8 @@ async function createAgent() {
69447
69887
  );
69448
69888
  }
69449
69889
  const history = [];
69890
+ let auditMode = false;
69891
+ const projectRoot = projectRootFromWorkdir(sandbox.getWorkdir());
69450
69892
  function getActiveModelChain() {
69451
69893
  return selectedModelKey ? [selectedModelKey] : CLI_MODEL_CHAIN;
69452
69894
  }
@@ -69472,7 +69914,7 @@ async function createAgent() {
69472
69914
  provider: "NVIDIA build",
69473
69915
  reason: "faltando NVIDIA_API_KEY em .env.local (https://build.nvidia.com/)",
69474
69916
  models: [
69475
- "model-nvidia-minimax-m3",
69917
+ "model-nvidia-mistral-medium-3.5",
69476
69918
  "model-nvidia-kimi-k2.6",
69477
69919
  "model-nvidia-glm-5.1",
69478
69920
  "model-nvidia-qwen3.5-397b"
@@ -69632,12 +70074,30 @@ ${seen}`);
69632
70074
  }
69633
70075
  async function send(userInput, signal) {
69634
70076
  history.push({ role: "user", content: userInput });
69635
- const matchedSkills = selectSkillsForInput(userInput);
69636
- const turnSystem = matchedSkills.length ? system + renderSkillBodies(matchedSkills) : system;
69637
- if (matchedSkills.length) {
70077
+ if (!auditMode && detectProjectAuditIntent(userInput)) {
70078
+ auditMode = true;
69638
70079
  render.info(
69639
- `\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.`
69640
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
+ }
69641
70101
  }
69642
70102
  let lastError = null;
69643
70103
  let autoContinues = 0;
@@ -69646,6 +70106,7 @@ ${seen}`);
69646
70106
  const usingFixedModel = selectedModelKey !== null;
69647
70107
  let rateLimitWaits = 0;
69648
70108
  let addedRateLimitFallbacks = false;
70109
+ let stallRetries = 0;
69649
70110
  for (let idx = 0; idx < modelChain.length; idx++) {
69650
70111
  const modelKey = modelChain[idx];
69651
70112
  currentModelName = modelKey;
@@ -69660,6 +70121,27 @@ ${seen}`);
69660
70121
  render.fallback(`trocando para fallback: ${labelFor(modelKey)}`);
69661
70122
  }
69662
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
+ };
69663
70145
  try {
69664
70146
  const result = streamText({
69665
70147
  model: myProvider.languageModel(modelKey),
@@ -69668,7 +70150,7 @@ ${seen}`);
69668
70150
  tools,
69669
70151
  stopWhen: stepCountIs(MAX_STEPS),
69670
70152
  maxOutputTokens: MAX_OUTPUT_TOKENS,
69671
- abortSignal: signal,
70153
+ abortSignal: stallController.signal,
69672
70154
  onError: ({ error: error51 }) => {
69673
70155
  streamError = error51;
69674
70156
  }
@@ -69677,38 +70159,72 @@ ${seen}`);
69677
70159
  let bufferedProxyText = "";
69678
70160
  let turnToolCalls = 0;
69679
70161
  const shouldBufferProxyText = isWebSessionProxyModel(modelKey);
69680
- for await (const part of result.fullStream) {
69681
- switch (part.type) {
69682
- case "text-delta": {
69683
- const delta = part.text ?? part.delta ?? "";
69684
- lastStepText += delta;
69685
- if (shouldBufferProxyText) {
69686
- bufferedProxyText += delta;
69687
- } else {
69688
- 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;
69689
70180
  }
69690
- 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;
69691
70212
  }
69692
- case "reasoning-delta":
69693
- render.reasoning(part.text ?? part.delta ?? "");
69694
- break;
69695
- case "tool-call":
69696
- turnToolCalls++;
69697
- render.toolCall(part.toolName, part.input ?? part.args);
69698
- break;
69699
- case "tool-result":
69700
- render.toolResult(part.toolName, part.output ?? part.result);
69701
- break;
69702
- case "start-step":
69703
- lastStepText = "";
69704
- bufferedProxyText = "";
69705
- break;
69706
- case "error":
69707
- streamError = part.error;
69708
- break;
69709
- default:
69710
- break;
69711
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
+ );
69712
70228
  }
69713
70229
  if (streamError) throw streamError;
69714
70230
  const response = await result.response;
@@ -69716,12 +70232,13 @@ ${seen}`);
69716
70232
  const finishReason = String(
69717
70233
  await result.finishReason.catch(() => "unknown")
69718
70234
  );
69719
- 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)) {
69720
70237
  const bridged = parseProxyToolCalls(lastStepText);
69721
70238
  if (bridged) {
69722
70239
  bridgeSteps++;
69723
70240
  render.info(
69724
- `\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)}`
69725
70242
  );
69726
70243
  const resultText = await runBridgedToolCalls(bridged, signal);
69727
70244
  if (signal?.aborted) {
@@ -69730,7 +70247,7 @@ ${seen}`);
69730
70247
  }
69731
70248
  history.push({
69732
70249
  role: "user",
69733
- content: `${BRIDGE_RESULT_PREAMBLE}
70250
+ content: `${leakedCall ? LEAKED_CALL_RESULT_PREAMBLE : BRIDGE_RESULT_PREAMBLE}
69734
70251
 
69735
70252
  ${resultText}`
69736
70253
  });
@@ -69779,6 +70296,28 @@ ${resultText}`
69779
70296
  render.endTurn();
69780
70297
  return;
69781
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
+ }
69782
70321
  lastError = err ?? streamError;
69783
70322
  const msg = lastError instanceof Error ? lastError.message : String(lastError);
69784
70323
  const rateLimited = isRateLimitError(msg);
@@ -69857,13 +70396,13 @@ ${resultText}`
69857
70396
  close
69858
70397
  };
69859
70398
  }
69860
- var import_promises, import_node_path5, 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;
69861
70400
  var init_agent = __esm({
69862
70401
  "src/agent.ts"() {
69863
70402
  "use strict";
69864
70403
  init_dist5();
69865
70404
  import_promises = require("node:fs/promises");
69866
- import_node_path5 = __toESM(require("node:path"));
70405
+ import_node_path8 = __toESM(require("node:path"));
69867
70406
  init_providers();
69868
70407
  init_system_prompt();
69869
70408
  init_notes();
@@ -69882,10 +70421,16 @@ var init_agent = __esm({
69882
70421
  init_render();
69883
70422
  init_skills();
69884
70423
  init_proxy_manager2();
70424
+ init_audit_mode();
69885
70425
  MAX_STEPS = 100;
69886
70426
  MAX_OUTPUT_TOKENS = 16384;
69887
70427
  MAX_AUTO_CONTINUES = 3;
69888
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;
69889
70434
  isRateLimitError = (msg) => /\b429\b|too many requests|rate.?limit|resource_exhausted|quota|insufficient_quota/i.test(
69890
70435
  msg
69891
70436
  );
@@ -69901,11 +70446,14 @@ var init_agent = __esm({
69901
70446
  { once: true }
69902
70447
  );
69903
70448
  });
69904
- 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;
69905
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;
69906
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.";
69907
70454
  MAX_BRIDGE_STEPS = 50;
69908
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.";
69909
70457
  truncateBridgeSummary = (value, max = 180) => value.length > max ? `${value.slice(0, max)}...` : value;
69910
70458
  isWebSessionProxyModel = (modelName) => modelName === "model-deepseek-proxy" || modelName === "model-kimi-proxy";
69911
70459
  proxyToolProtocolPolicy = () => `
@@ -69941,7 +70489,7 @@ Regras:
69941
70489
  "DANGEROUS MODE"
69942
70490
  ];
69943
70491
  MODEL_LABELS = {
69944
- "model-nvidia-minimax-m3": "NVIDIA - minimaxai/minimax-m3",
70492
+ "model-nvidia-mistral-medium-3.5": "NVIDIA - mistralai/mistral-medium-3.5-128b",
69945
70493
  "model-nvidia-kimi-k2.6": "NVIDIA - moonshotai/kimi-k2.6",
69946
70494
  "model-nvidia-glm-5.1": "NVIDIA - z-ai/glm-5.1",
69947
70495
  "model-nvidia-qwen3.5-397b": "NVIDIA - qwen/qwen3.5-397b-a17b",
@@ -70086,7 +70634,7 @@ ${section}` : "";
70086
70634
  return null;
70087
70635
  }
70088
70636
  await (0, import_promises.mkdir)(workdir, { recursive: true });
70089
- const outputPath = import_node_path5.default.join(workdir, "system-prompt.txt");
70637
+ const outputPath = import_node_path8.default.join(workdir, "system-prompt.txt");
70090
70638
  await (0, import_promises.writeFile)(outputPath, system, "utf8");
70091
70639
  return outputPath;
70092
70640
  };
@@ -70117,7 +70665,9 @@ __export(ui_exports, {
70117
70665
  agentHeader: () => agentHeader,
70118
70666
  buildBanner: () => buildBanner,
70119
70667
  shellPrompt: () => shellPrompt,
70120
- ui: () => ui
70668
+ shortCwd: () => shortCwd,
70669
+ ui: () => ui,
70670
+ vlen: () => vlen
70121
70671
  });
70122
70672
  function shortCwd() {
70123
70673
  const cwd = process.cwd();
@@ -70130,15 +70680,15 @@ function shortCwd() {
70130
70680
  }
70131
70681
  function asciiTitle(text2) {
70132
70682
  const rows = 6;
70133
- const out2 = [];
70683
+ const out3 = [];
70134
70684
  for (let r = 0; r < rows; r++) {
70135
- out2.push(
70685
+ out3.push(
70136
70686
  [...text2].map((ch) => GLYPHS[ch] ? GLYPHS[ch][r] : " ").join(" ")
70137
70687
  );
70138
70688
  }
70139
- return out2;
70689
+ return out3;
70140
70690
  }
70141
- function buildBanner(_systemPromptChars) {
70691
+ function buildBanner(_systemPromptChars, version3 = "1") {
70142
70692
  const user = (import_node_os4.default.userInfo().username || "hacker").toLowerCase();
70143
70693
  const host = (import_node_os4.default.hostname() || "localhost").split(".")[0].toLowerCase();
70144
70694
  const art = asciiTitle("CLAWFAST");
@@ -70162,7 +70712,7 @@ function buildBanner(_systemPromptChars) {
70162
70712
  { text: shortCwd() },
70163
70713
  { text: "" }
70164
70714
  ];
70165
- const title = `clawfast v1`;
70715
+ const title = `clawfast v${version3}`;
70166
70716
  const topFill = "\u2500".repeat(Math.max(0, BOX_W - vlen(title) - 5));
70167
70717
  const top = `${C3.green}\u256D\u2500 ${C3.greenB}${C3.bold}${title}${C3.reset}${C3.green} ${topFill}\u256E${C3.reset}`;
70168
70718
  const bottom = `${C3.green}\u2570${"\u2500".repeat(BOX_W - 2)}\u256F${C3.reset}`;
@@ -70208,7 +70758,8 @@ var init_ui = __esm({
70208
70758
  cyan: `${ESC}36m`,
70209
70759
  cyanB: `${ESC}96m`,
70210
70760
  magenta: `${ESC}95m`,
70211
- yellow: `${ESC}93m`
70761
+ yellow: `${ESC}93m`,
70762
+ red: `${ESC}91m`
70212
70763
  };
70213
70764
  INNER = 42;
70214
70765
  BOX_W = INNER + 4;
@@ -70232,42 +70783,500 @@ var init_ui = __esm({
70232
70783
  }
70233
70784
  });
70234
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
+
70235
71232
  // index.ts
70236
71233
  var index_exports = {};
70237
71234
  async function main() {
70238
71235
  const { createAgent: createAgent2 } = await Promise.resolve().then(() => (init_agent(), agent_exports));
70239
- 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;
70240
71239
  if (!bootQuiet) {
70241
- process.stdout.write(
70242
- `${ui2.C.dim} booting local sandbox + agent\u2026${ui2.C.reset}
70243
- `
70244
- );
71240
+ process.stdout.write(`${C5.dim} booting local sandbox + agent\u2026${C5.reset}
71241
+ `);
70245
71242
  }
70246
71243
  const agent = await createAgent2();
70247
71244
  const sys = agent.getSystemPrompt();
70248
71245
  stopBootSpinner();
70249
- process.stdout.write(buildBanner2(sys.length));
71246
+ const version3 = clawfastVersion();
71247
+ process.stdout.write(buildBanner2(sys.length, version3));
71248
+ const updateNotice = getUpdateNotice(version3);
71249
+ if (updateNotice) {
71250
+ process.stdout.write(`${C5.yellow}\u2191 ${updateNotice}${C5.reset}
71251
+ `);
71252
+ }
71253
+ refreshUpdateCacheInBackground(version3);
71254
+ if (consumePostUpdateLaunch(version3)) {
71255
+ process.stdout.write(
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}
71257
+ `
71258
+ );
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
+ ];
70250
71272
  const pasteInput = createPasteInput();
70251
- const rl = import_node_readline3.default.createInterface({
70252
- input: pasteInput.input,
70253
- output: process.stdout,
70254
- terminal: true
70255
- });
71273
+ const inputUI = new InteractiveInput2(pasteInput, COMMANDS);
70256
71274
  let closing = false;
70257
- let commandQueue = Promise.resolve();
70258
- let awaitingModelSelection = false;
70259
- let skillCreator = null;
70260
- const prompt = () => {
70261
- rl.setPrompt(
70262
- skillCreator ? skillPrompt(skillCreator.phase) : awaitingModelSelection ? modelPrompt() : shellPrompt2()
70263
- );
70264
- rl.prompt();
70265
- };
71275
+ let shuttingDown = false;
70266
71276
  let activeAbort = null;
70267
71277
  let turnActive = false;
70268
71278
  let exitArmed = false;
70269
71279
  let exitTimer = null;
70270
- let lastSigint = 0;
70271
71280
  const armExit = () => {
70272
71281
  exitArmed = true;
70273
71282
  if (exitTimer) clearTimeout(exitTimer);
@@ -70276,69 +71285,58 @@ async function main() {
70276
71285
  exitTimer = null;
70277
71286
  }, 2e3);
70278
71287
  };
70279
- const handleSigint = () => {
70280
- const now2 = Date.now();
70281
- if (now2 - lastSigint < 60) return;
70282
- lastSigint = now2;
70283
- if (closing) return;
70284
- if (exitArmed) {
70285
- if (exitTimer) clearTimeout(exitTimer);
70286
- exitTimer = null;
70287
- exitArmed = false;
70288
- closing = true;
70289
- activeAbort?.abort();
70290
- process.stdout.write(`
70291
- ${ui2.C.dim}fechando\u2026${ui2.C.reset}
70292
- `);
70293
- rl.close();
70294
- return;
70295
- }
70296
- if (activeAbort && !activeAbort.signal.aborted) {
70297
- activeAbort.abort();
70298
- process.stdout.write(
70299
- `
70300
- ${ui2.C.dim}interrompido \u2014 Ctrl+C de novo para fechar${ui2.C.reset}
70301
- `
70302
- );
70303
- } else {
70304
- process.stdout.write(
70305
- `
70306
- ${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)}
70307
71312
  `
70308
- );
70309
- if (!awaitingModelSelection) prompt();
70310
- }
70311
- armExit();
71313
+ );
70312
71314
  };
70313
- process.removeAllListeners("SIGINT");
70314
- process.on("SIGINT", handleSigint);
70315
- rl.on("SIGINT", handleSigint);
71315
+ let skillCreator = null;
70316
71316
  const printSkillList = () => {
70317
71317
  const skills = listSkills();
70318
71318
  if (skills.length === 0) {
70319
71319
  process.stdout.write(
70320
71320
  `
70321
- ${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}
70322
71322
  `
70323
71323
  );
70324
71324
  return;
70325
71325
  }
70326
71326
  process.stdout.write(
70327
71327
  `
70328
- ${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}
70329
71329
  `
70330
71330
  );
70331
71331
  for (const s of skills) {
70332
- const flags = s.always ? ` ${ui2.C.yellow}[sempre]${ui2.C.reset}` : "";
71332
+ const flags = s.always ? ` ${C5.yellow}[sempre]${C5.reset}` : "";
70333
71333
  process.stdout.write(
70334
- ` ${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}
70335
71335
  `
70336
71336
  );
70337
71337
  }
70338
- process.stdout.write(
70339
- `${ui2.C.dim}remover: /skill delete <nome>${ui2.C.reset}
70340
- `
70341
- );
71338
+ process.stdout.write(`${C5.dim}remover: /skill delete <nome>${C5.reset}
71339
+ `);
70342
71340
  };
70343
71341
  const handleSkillCommand = (input) => {
70344
71342
  if (input === "/skillcreator") {
@@ -70351,9 +71349,9 @@ ${ui2.C.cyan}skills instaladas${ui2.C.reset} ${ui2.C.dim}(${skillsDir()})${ui2.C
70351
71349
  };
70352
71350
  process.stdout.write(
70353
71351
  `
70354
- ${ui2.C.greenB}criar skill${ui2.C.reset} ${ui2.C.dim}(/cancelar para abortar)${ui2.C.reset}
70355
- ${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}
70356
- ${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}
70357
71355
  `
70358
71356
  );
70359
71357
  return;
@@ -70371,29 +71369,27 @@ ${ui2.C.cyan}nome da skill?${ui2.C.reset} ${ui2.C.dim}(ex: xss-recon)${ui2.C.res
70371
71369
  }
70372
71370
  if (sub === "delete" || sub === "rm" || sub === "remove") {
70373
71371
  if (!arg) {
70374
- process.stdout.write(
70375
- `${ui2.C.yellow}uso: /skill delete <nome>${ui2.C.reset}
70376
- `
70377
- );
71372
+ process.stdout.write(`${C5.yellow}uso: /skill delete <nome>${C5.reset}
71373
+ `);
70378
71374
  return;
70379
71375
  }
70380
71376
  if (deleteSkill(arg)) {
70381
71377
  await agent.refreshSkills();
70382
71378
  process.stdout.write(
70383
- `${ui2.C.green}\u2713 skill '${slugify(arg)}' removida${ui2.C.reset}
71379
+ `${C5.green}\u2713 skill '${slugify(arg)}' removida${C5.reset}
70384
71380
  `
70385
71381
  );
70386
71382
  } else {
70387
71383
  process.stdout.write(
70388
- `${ui2.C.yellow}skill '${arg}' nao encontrada${ui2.C.reset}
71384
+ `${C5.yellow}skill '${arg}' nao encontrada${C5.reset}
70389
71385
  `
70390
71386
  );
70391
71387
  }
70392
71388
  return;
70393
71389
  }
70394
71390
  process.stdout.write(
70395
- `${ui2.C.yellow}subcomando desconhecido: ${sub}${ui2.C.reset}
70396
- ${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}
70397
71393
  `
70398
71394
  );
70399
71395
  };
@@ -70401,7 +71397,7 @@ ${ui2.C.dim}use: /skillcreator | /skills | /skill delete <nome>${ui2.C.reset}
70401
71397
  const text2 = sc.bodyLines.join("\n");
70402
71398
  const lines = text2 ? text2.split("\n").length : 0;
70403
71399
  process.stdout.write(
70404
- `${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}
70405
71401
  `
70406
71402
  );
70407
71403
  };
@@ -70410,11 +71406,9 @@ ${ui2.C.dim}use: /skillcreator | /skills | /skill delete <nome>${ui2.C.reset}
70410
71406
  if (!sc) return;
70411
71407
  if (input === "/cancelar" || input === "/cancel") {
70412
71408
  skillCreator = null;
70413
- process.stdout.write(
70414
- `
70415
- ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70416
- `
70417
- );
71409
+ process.stdout.write(`
71410
+ ${C5.dim}criacao de skill cancelada${C5.reset}
71411
+ `);
70418
71412
  return;
70419
71413
  }
70420
71414
  switch (sc.phase) {
@@ -70422,7 +71416,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70422
71416
  const slug = slugify(input);
70423
71417
  if (!slug) {
70424
71418
  process.stdout.write(
70425
- `${ui2.C.yellow}nome invalido \u2014 tente de novo${ui2.C.reset}
71419
+ `${C5.yellow}nome invalido \u2014 tente de novo${C5.reset}
70426
71420
  `
70427
71421
  );
70428
71422
  return;
@@ -70430,22 +71424,20 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70430
71424
  sc.name = slug;
70431
71425
  if (listSkills().some((s) => s.name === slug)) {
70432
71426
  process.stdout.write(
70433
- `${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}
70434
71428
  `
70435
71429
  );
70436
71430
  }
70437
71431
  sc.phase = "desc";
70438
- process.stdout.write(
70439
- `${ui2.C.cyan}descricao curta (1 linha)?${ui2.C.reset}
70440
- `
70441
- );
71432
+ process.stdout.write(`${C5.cyan}descricao curta (1 linha)?${C5.reset}
71433
+ `);
70442
71434
  return;
70443
71435
  }
70444
71436
  case "desc": {
70445
71437
  sc.description = input;
70446
71438
  sc.phase = "triggers";
70447
71439
  process.stdout.write(
70448
- `${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}
70449
71441
  `
70450
71442
  );
70451
71443
  return;
@@ -70457,7 +71449,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70457
71449
  sc.phase = "body";
70458
71450
  sc.bodyLines.push(line.replace(/\r$/, ""));
70459
71451
  process.stdout.write(
70460
- `${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}
70461
71453
  `
70462
71454
  );
70463
71455
  printBodyTally(sc);
@@ -70466,7 +71458,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70466
71458
  sc.triggers = input ? input.split(",").map((t) => t.trim()).filter(Boolean) : [];
70467
71459
  sc.phase = "body";
70468
71460
  process.stdout.write(
70469
- `${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}
70470
71462
  `
70471
71463
  );
70472
71464
  return;
@@ -70476,7 +71468,7 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70476
71468
  const body = sc.bodyLines.join("\n").trim();
70477
71469
  if (!body) {
70478
71470
  process.stdout.write(
70479
- `${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}
70480
71472
  `
70481
71473
  );
70482
71474
  return;
@@ -70491,22 +71483,20 @@ ${ui2.C.dim}criacao de skill cancelada${ui2.C.reset}
70491
71483
  await agent.refreshSkills();
70492
71484
  process.stdout.write(
70493
71485
  `
70494
- ${ui2.C.green}\u2713 skill '${res.skill.name}' ${res.overwritten ? "atualizada" : "criada"}${ui2.C.reset} ${ui2.C.dim}(${res.file})${ui2.C.reset}
70495
- ${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}
70496
71488
  `
70497
71489
  );
70498
71490
  return;
70499
71491
  }
70500
71492
  if (input === "/desfazer" || input === "/undo") {
70501
71493
  if (sc.bodyLines.length === 0) {
70502
- process.stdout.write(
70503
- `${ui2.C.dim}nada para desfazer${ui2.C.reset}
70504
- `
70505
- );
71494
+ process.stdout.write(`${C5.dim}nada para desfazer${C5.reset}
71495
+ `);
70506
71496
  } else {
70507
71497
  sc.bodyLines.pop();
70508
71498
  process.stdout.write(
70509
- `${ui2.C.yellow}ultimo trecho removido.${ui2.C.reset}
71499
+ `${C5.yellow}ultimo trecho removido.${C5.reset}
70510
71500
  `
70511
71501
  );
70512
71502
  printBodyTally(sc);
@@ -70519,203 +71509,204 @@ ${ui2.C.dim}ja disponivel para todos os modelos nesta sessao.${ui2.C.reset}
70519
71509
  }
70520
71510
  }
70521
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
+ };
70522
71544
  const handleLine = async (line) => {
70523
71545
  if (closing) return;
70524
71546
  const input = line.trim();
70525
71547
  if (skillCreator) {
70526
71548
  await handleSkillCreatorLine(line, input);
70527
- if (!closing) prompt();
70528
71549
  return;
70529
71550
  }
70530
71551
  if (input === "/exit" || input === "/quit") {
70531
71552
  closing = true;
70532
- rl.close();
70533
71553
  return;
70534
71554
  }
70535
71555
  if (input === "/skillcreator" || input === "/skill" || input === "/skills") {
70536
71556
  handleSkillCommand(input);
70537
- if (!closing) prompt();
70538
71557
  return;
70539
71558
  }
70540
71559
  if (input.startsWith("/skill ") || input.startsWith("/skills ")) {
70541
71560
  await handleSkillSubcommand(input);
70542
- if (!closing) prompt();
70543
71561
  return;
70544
71562
  }
70545
- if (awaitingModelSelection) {
70546
- if (!input || input === "cancelar" || input === "cancel" || input === "sair" || input === "q") {
70547
- awaitingModelSelection = false;
70548
- process.stdout.write(
70549
- `
70550
- ${ui2.C.dim}selecao de modelo cancelada${ui2.C.reset}
70551
- `
70552
- );
70553
- if (!closing) prompt();
70554
- return;
70555
- }
71563
+ if (input === "/model" || input === "/models") {
71564
+ await openModelSelector();
71565
+ return;
71566
+ }
71567
+ if (input.startsWith("/model ") || input.startsWith("/models ")) {
70556
71568
  const arg = input.replace(/^\/models?\s*/, "");
70557
71569
  try {
70558
- const result = await agent.setModelSelection(arg);
70559
- process.stdout.write(formatModelSelection(result));
70560
- awaitingModelSelection = !result.ok;
71570
+ printModelResult(await agent.setModelSelection(arg));
70561
71571
  } catch (err) {
70562
- process.stderr.write(
70563
- `
70564
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70565
- `
70566
- );
70567
- awaitingModelSelection = false;
71572
+ printFatal(err);
70568
71573
  }
70569
- if (!closing) prompt();
70570
71574
  return;
70571
71575
  }
70572
- if (!input) {
70573
- prompt();
70574
- return;
70575
- }
70576
- if (input === "/model" || input === "/models" || input.startsWith("/model ") || input.startsWith("/models ")) {
70577
- 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>`;
70578
71587
  try {
70579
- const result = await agent.setModelSelection(arg || "list");
70580
- awaitingModelSelection = !arg && result.ok;
71588
+ await (0, import_promises2.writeFile)(filePath, html, "utf8");
70581
71589
  process.stdout.write(
70582
- 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
+ `
70583
71593
  );
70584
71594
  } catch (err) {
70585
- process.stderr.write(
70586
- `
70587
- [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)}
70588
71597
  `
70589
71598
  );
70590
- awaitingModelSelection = false;
70591
71599
  }
70592
- if (!closing) prompt();
70593
71600
  return;
70594
71601
  }
70595
- if (input === "/system") {
70596
- const sys2 = agent.getSystemPrompt();
70597
- const audit = agent.getSystemPromptAudit();
71602
+ if (input === "/nov" || input === "/novidades") {
70598
71603
  process.stdout.write(
70599
- `\x1B[90m\u2500\u2500\u2500\u2500 system prompt (${sys2.length.toLocaleString()} caracteres) \u2500\u2500\u2500\u2500\x1B[0m
70600
- `
70601
- );
70602
- process.stdout.write(
70603
- `\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}
70604
71606
  `
70605
71607
  );
70606
- process.stdout.write(sys2 + "\n");
70607
- process.stdout.write(`\x1B[90m\u2500\u2500\u2500\u2500 fim do system prompt \u2500\u2500\u2500\u2500\x1B[0m
70608
- `);
70609
- if (!closing) prompt();
70610
71608
  return;
70611
71609
  }
71610
+ if (!input) return;
70612
71611
  process.stdout.write("\n" + agentHeader2());
70613
71612
  activeAbort = new AbortController();
70614
71613
  turnActive = true;
70615
- 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
+ );
70616
71635
  try {
70617
71636
  await agent.send(input, activeAbort.signal);
70618
71637
  } catch (err) {
70619
- process.stderr.write(
70620
- `
70621
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70622
- `
70623
- );
71638
+ printFatal(err);
70624
71639
  } finally {
71640
+ inputUI.endTurn();
70625
71641
  activeAbort = null;
70626
71642
  turnActive = false;
70627
71643
  }
70628
- if (!closing) prompt();
70629
71644
  };
70630
- prompt();
70631
- rl.on("line", (rawLine) => {
70632
- const line = pasteInput.expand(rawLine);
71645
+ process.removeAllListeners("SIGINT");
71646
+ process.on("SIGINT", () => {
70633
71647
  if (turnActive) {
70634
- if (agent.isRunningCommand()) {
70635
- agent.sendStdin(line);
70636
- }
71648
+ activeAbort?.abort();
70637
71649
  return;
70638
71650
  }
70639
- rl.pause();
70640
- commandQueue = commandQueue.then(() => handleLine(line)).catch((err) => {
70641
- process.stderr.write(
70642
- `
70643
- [fatal] ${err instanceof Error ? err.stack || err.message : String(err)}
70644
- `
70645
- );
70646
- }).finally(() => {
70647
- if (!closing) rl.resume();
70648
- });
70649
- });
70650
- rl.on("close", async () => {
70651
- closing = true;
70652
- pasteInput.dispose();
70653
- await commandQueue.catch(() => void 0);
70654
- process.stdout.write("\nClosing sandbox...\n");
70655
- await agent.close();
70656
- process.exit(0);
71651
+ void shutdown();
70657
71652
  });
70658
71653
  process.on("exit", () => pasteInput.dispose());
70659
- }
70660
- function modelPrompt() {
70661
- return "\n\x1B[96m\x1B[1mmodelo\x1B[0m\x1B[92m\x1B[1m>\x1B[0m ";
70662
- }
70663
- function skillPrompt(phase) {
70664
- const label = phase === "name" ? "nome" : phase === "desc" ? "descricao" : phase === "triggers" ? "gatilhos" : "skill";
70665
- return `\x1B[96m\x1B[1m${label}\x1B[0m\x1B[92m\x1B[1m>\x1B[0m `;
70666
- }
70667
- function formatModelSelection(result, options = {}) {
70668
- const { C: C4 } = {
70669
- C: {
70670
- reset: "\x1B[0m",
70671
- bold: "\x1B[1m",
70672
- dim: "\x1B[90m",
70673
- green: "\x1B[32m",
70674
- cyan: "\x1B[36m",
70675
- yellow: "\x1B[33m",
70676
- 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";
70677
71665
  }
70678
71666
  };
70679
- const statusColor = result.ok ? C4.green : C4.red;
70680
- const lines = [
70681
- `${statusColor}${result.ok ? "ok" : "erro"}${C4.reset} ${result.message}`,
70682
- `${C4.dim}modo atual:${C4.reset} ${result.selection.mode === "auto" ? `${C4.yellow}auto / fallback${C4.reset}` : `${C4.green}fixo${C4.reset}`}`,
70683
- "",
70684
- `${C4.cyan}${C4.bold}Modelos disponiveis${C4.reset}`
70685
- ];
70686
- for (const choice2 of result.selection.chain) {
70687
- const isActive = choice2.key === result.selection.activeModelKey;
70688
- const marker25 = isActive ? result.selection.mode === "fixed" ? "*" : ">" : " ";
70689
- lines.push(
70690
- `${marker25} ${choice2.index}. ${choice2.label} ${C4.dim}(${choice2.key})${C4.reset}`
70691
- );
70692
- }
70693
- if (result.selection.unavailable.length > 0) {
70694
- lines.push("", `${C4.yellow}${C4.bold}Indisponiveis${C4.reset}`);
70695
- for (const group of result.selection.unavailable) {
70696
- lines.push(`${group.provider}: ${C4.dim}${group.reason}${C4.reset}`);
70697
- for (const model of group.models) {
70698
- 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;
70699
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);
70700
71691
  }
70701
71692
  }
70702
- lines.push(
70703
- "",
70704
- 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}`
70705
- );
70706
- return `
70707
- ${lines.join("\n")}
70708
- `;
71693
+ await shutdown();
70709
71694
  }
70710
- var import_node_readline3, deepseekEnabled, configuredModelProviders;
71695
+ var import_node_os6, import_node_path9, import_node_fs8, import_promises2, deepseekEnabled, configuredModelProviders;
70711
71696
  var init_index = __esm({
70712
71697
  "index.ts"() {
70713
71698
  "use strict";
70714
- 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");
70715
71703
  init_paste_input();
70716
71704
  init_boot_ui();
70717
71705
  init_config();
70718
71706
  init_skills();
71707
+ init_version();
71708
+ init_update();
71709
+ init_news();
70719
71710
  loadClawfastEnv();
70720
71711
  deepseekEnabled = /^(1|true|yes)$/i.test(process.env.DEEPSEEK_ENABLED?.trim() ?? "") || Boolean(process.env.DEEPSEEK_BASE_URL?.trim()) || Boolean(process.env.DEEPSEEK_API_KEY?.trim());
70721
71712
  configuredModelProviders = [
@@ -70740,8 +71731,38 @@ var init_index = __esm({
70740
71731
  // boot.ts
70741
71732
  init_boot_ui();
70742
71733
  init_config();
71734
+ init_version();
71735
+ init_update();
70743
71736
  loadClawfastEnv();
71737
+ async function handleSubcommand() {
71738
+ const arg = process.argv[2];
71739
+ if (arg === "--version" || arg === "-v" || arg === "version") {
71740
+ process.stdout.write(`clawfast ${clawfastVersion()}
71741
+ `);
71742
+ process.exit(0);
71743
+ }
71744
+ if (arg === "update" || arg === "upgrade") {
71745
+ process.stdout.write(`\x1B[92mAtualizando o clawfast\u2026\x1B[0m
71746
+ `);
71747
+ const code = await runSelfUpdate();
71748
+ if (code === 0) {
71749
+ process.stdout.write(
71750
+ `
71751
+ \x1B[92m\x1B[1mSeja bem vindo ao submundo.\x1B[0m
71752
+ `
71753
+ );
71754
+ } else {
71755
+ process.stdout.write(
71756
+ `
71757
+ \x1B[91mFalha ao atualizar (codigo ${code}).\x1B[0m Tente manualmente: \x1B[1mnpm install -g clawfast@latest\x1B[0m
71758
+ `
71759
+ );
71760
+ }
71761
+ process.exit(code === 0 ? 0 : 1);
71762
+ }
71763
+ }
70744
71764
  async function boot() {
71765
+ await handleSubcommand();
70745
71766
  const hasKey = await ensureProviderKey();
70746
71767
  if (!hasKey) process.exit(1);
70747
71768
  startBootSpinner();