clawfast 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -136,7 +136,7 @@ NVIDIA_BASE_URL=https://integrate.api.nvidia.com/v1
136
136
  Modelos usados pelo CLI (wiring via `.chat(...)`, chat-completions):
137
137
 
138
138
  - `mistralai/mistral-medium-3.5-128b`
139
- - `moonshotai/kimi-k2.6`
139
+ - `openai/gpt-oss-120b`
140
140
  - `z-ai/glm-5.1`
141
141
  - `qwen/qwen3.5-397b-a17b`
142
142
 
@@ -172,7 +172,7 @@ A ordem de fallback do CLI e `CLI_MODEL_CHAIN` em
172
172
  [`../lib/ai/providers.ts`](../lib/ai/providers.ts):
173
173
 
174
174
  1. NVIDIA `mistralai/mistral-medium-3.5-128b`, se `NVIDIA_API_KEY` estiver configurada
175
- 2. NVIDIA `moonshotai/kimi-k2.6`
175
+ 2. NVIDIA `openai/gpt-oss-120b`
176
176
  3. NVIDIA `z-ai/glm-5.1`
177
177
  4. NVIDIA `qwen/qwen3.5-397b-a17b`
178
178
  5. Kimi / DeepSeek por sessao web logada (proxies), se habilitados
package/dist/clawfast.cjs CHANGED
@@ -426,6 +426,52 @@ ${line}
426
426
  }
427
427
  import_node_fs.default.writeFileSync(filePath, content, { encoding: "utf8", mode: 384 });
428
428
  }
429
+ function fileDefines(filePath, key) {
430
+ try {
431
+ const content = import_node_fs.default.readFileSync(filePath, "utf8");
432
+ return new RegExp(`^${key}=`, "m").test(content);
433
+ } catch {
434
+ return false;
435
+ }
436
+ }
437
+ function swapNvidiaKey(key) {
438
+ const local = import_node_path.default.resolve(process.cwd(), ".env.local");
439
+ const target = fileDefines(local, "NVIDIA_API_KEY") ? local : clawfastEnvPath();
440
+ setEnvVar(target, "NVIDIA_API_KEY", key);
441
+ process.env.NVIDIA_API_KEY = key;
442
+ return target;
443
+ }
444
+ async function testNvidiaKey(key) {
445
+ const baseURL = process.env.NVIDIA_BASE_URL || "https://integrate.api.nvidia.com/v1";
446
+ try {
447
+ const res = await fetch(`${baseURL.replace(/\/$/, "")}/chat/completions`, {
448
+ method: "POST",
449
+ headers: {
450
+ Authorization: `Bearer ${key}`,
451
+ "Content-Type": "application/json"
452
+ },
453
+ body: JSON.stringify({
454
+ model: "openai/gpt-oss-120b",
455
+ messages: [{ role: "user", content: "hi" }],
456
+ max_tokens: 1
457
+ })
458
+ });
459
+ if (res.ok) return { ok: true, status: res.status, detail: "OK" };
460
+ let detail = res.statusText || `HTTP ${res.status}`;
461
+ try {
462
+ const body = await res.json();
463
+ detail = body.detail || body.error?.message || body.title || detail;
464
+ } catch {
465
+ }
466
+ return { ok: false, status: res.status, detail };
467
+ } catch (err) {
468
+ return {
469
+ ok: false,
470
+ status: 0,
471
+ detail: err instanceof Error ? err.message : String(err)
472
+ };
473
+ }
474
+ }
429
475
  function promptLine(question) {
430
476
  const rl = import_node_readline.default.createInterface({
431
477
  input: process.stdin,
@@ -502,7 +548,7 @@ var clawfastVersion, isDevVersion, isNewerVersion;
502
548
  var init_version = __esm({
503
549
  "src/version.ts"() {
504
550
  "use strict";
505
- clawfastVersion = () => true ? "2.0.0" : "0.0.0-dev";
551
+ clawfastVersion = () => true ? "2.0.1" : "0.0.0-dev";
506
552
  isDevVersion = () => clawfastVersion().includes("-dev");
507
553
  isNewerVersion = (a, b) => {
508
554
  const parse3 = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
@@ -869,14 +915,140 @@ var init_skills = __esm({
869
915
  }
870
916
  });
871
917
 
918
+ // src/ui.ts
919
+ var ui_exports = {};
920
+ __export(ui_exports, {
921
+ C: () => C2,
922
+ agentHeader: () => agentHeader,
923
+ buildBanner: () => buildBanner,
924
+ shellPrompt: () => shellPrompt,
925
+ shortCwd: () => shortCwd,
926
+ ui: () => ui,
927
+ vlen: () => vlen
928
+ });
929
+ function shortCwd() {
930
+ const cwd = process.cwd();
931
+ const home = import_node_os2.default.homedir();
932
+ const rel = cwd.startsWith(home) ? "~" + cwd.slice(home.length) : cwd;
933
+ const norm = rel.replace(/\\/g, "/");
934
+ if (norm.length <= 30) return norm;
935
+ const parts = norm.split("/");
936
+ return parts.length > 3 ? `${parts[0]}/\u2026/${parts[parts.length - 1]}` : norm.slice(-30);
937
+ }
938
+ function asciiTitle(text2) {
939
+ const rows = 6;
940
+ const out3 = [];
941
+ for (let r = 0; r < rows; r++) {
942
+ out3.push(
943
+ [...text2].map((ch) => GLYPHS[ch] ? GLYPHS[ch][r] : " ").join(" ")
944
+ );
945
+ }
946
+ return out3;
947
+ }
948
+ function buildBanner(_systemPromptChars, version3 = "1") {
949
+ const user = (import_node_os2.default.userInfo().username || "hacker").toLowerCase();
950
+ const host = (import_node_os2.default.hostname() || "localhost").split(".")[0].toLowerCase();
951
+ const art = asciiTitle("CLAWFAST");
952
+ const artW = vlen(art[0]);
953
+ const slogan = "Com o clawfast voc\xEA faz tudo";
954
+ const header = [
955
+ "",
956
+ ...art.map((line) => `${C2.greenB}${C2.bold}${line}${C2.reset}`),
957
+ "",
958
+ `${C2.cyanB}${C2.bold}${center(slogan, artW)}${C2.reset}`,
959
+ ""
960
+ ];
961
+ const info = [
962
+ { text: "" },
963
+ { text: `Bem-vindo de volta, ${user}!`, accent: true },
964
+ { text: "" },
965
+ { text: "clawfast usa a pasta SPRIT/ para criar" },
966
+ { text: "arquivos, scripts e tudo mais." },
967
+ { text: "" },
968
+ { text: `${user}@${host} \xB7 sem limites` },
969
+ { text: shortCwd() },
970
+ { text: "" }
971
+ ];
972
+ const title = `clawfast v${version3}`;
973
+ const topFill = "\u2500".repeat(Math.max(0, BOX_W - vlen(title) - 5));
974
+ const top = `${C2.green}\u256D\u2500 ${C2.greenB}${C2.bold}${title}${C2.reset}${C2.green} ${topFill}\u256E${C2.reset}`;
975
+ const bottom = `${C2.green}\u2570${"\u2500".repeat(BOX_W - 2)}\u256F${C2.reset}`;
976
+ const cardLines = info.map(({ text: text2, accent }) => {
977
+ const color = accent ? `${C2.greenB}${C2.bold}` : C2.green;
978
+ const body = `${color}${padEndV(text2, INNER)}${C2.reset}`;
979
+ return `${C2.green}\u2502 ${C2.reset}${body}${C2.green} \u2502${C2.reset}`;
980
+ });
981
+ const card = [top, ...cardLines, bottom];
982
+ return "\n" + [...header, ...card].join("\n") + "\n";
983
+ }
984
+ function shellPrompt() {
985
+ const user = (import_node_os2.default.userInfo().username || "hacker").toLowerCase();
986
+ const host = (import_node_os2.default.hostname() || "localhost").split(".")[0].toLowerCase();
987
+ const W = 52;
988
+ const label = " \u2709 mensagem ";
989
+ const topFill = "\u2500".repeat(Math.max(0, W - vlen(label) - 3));
990
+ const top = `${C2.green}\u256D\u2500${C2.greenB}${C2.bold}${label}${C2.reset}${C2.green}${topFill}\u256E${C2.reset}`;
991
+ const id = `${user}\u327F${host} \xB7 ${shortCwd()}`;
992
+ const mid = `${C2.green}\u2502 ${C2.dim}${id}${C2.reset}`;
993
+ const bottom = `${C2.green}\u2570\u2500${C2.greenB}${C2.bold}\u276F${C2.reset} `;
994
+ return `
995
+ ${top}
996
+ ${mid}
997
+ ${bottom}`;
998
+ }
999
+ function agentHeader() {
1000
+ return `${C2.magenta}\u256D\u2500 clawfast ${"\u2500".repeat(20)}${C2.reset}
1001
+ `;
1002
+ }
1003
+ var import_node_os2, ESC, C2, INNER, BOX_W, vlen, padEndV, center, GLYPHS, ui;
1004
+ var init_ui = __esm({
1005
+ "src/ui.ts"() {
1006
+ "use strict";
1007
+ import_node_os2 = __toESM(require("node:os"));
1008
+ ESC = "\x1B[";
1009
+ C2 = {
1010
+ reset: `${ESC}0m`,
1011
+ bold: `${ESC}1m`,
1012
+ dim: `${ESC}90m`,
1013
+ green: `${ESC}32m`,
1014
+ greenB: `${ESC}92m`,
1015
+ cyan: `${ESC}36m`,
1016
+ cyanB: `${ESC}96m`,
1017
+ magenta: `${ESC}95m`,
1018
+ yellow: `${ESC}93m`,
1019
+ red: `${ESC}91m`
1020
+ };
1021
+ INNER = 42;
1022
+ BOX_W = INNER + 4;
1023
+ vlen = (s) => [...s.replace(/\x1b\[[0-9;]*m/g, "")].length;
1024
+ padEndV = (s, w) => s + " ".repeat(Math.max(0, w - vlen(s)));
1025
+ center = (s, w) => {
1026
+ const pad = Math.max(0, w - vlen(s));
1027
+ const left = Math.floor(pad / 2);
1028
+ return " ".repeat(left) + s + " ".repeat(pad - left);
1029
+ };
1030
+ GLYPHS = {
1031
+ C: [" \u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588\u2588"],
1032
+ L: ["\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588\u2588"],
1033
+ A: [" \u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588"],
1034
+ W: ["\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588 \u2588\u2588", "\u2588\u2588 \u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 \u2588\u2588 "],
1035
+ F: ["\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 "],
1036
+ S: [" \u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588 ", " \u2588\u2588", " \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588 "],
1037
+ T: ["\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 "]
1038
+ };
1039
+ ui = { C: C2, buildBanner, shellPrompt, agentHeader };
1040
+ }
1041
+ });
1042
+
872
1043
  // src/news.ts
873
- var import_node_fs4, import_node_path4, NEWS, latestNewsVersion, renderNews, stateFile, readState, writeState, consumePostUpdateLaunch;
1044
+ var import_node_fs4, import_node_path4, NEWS, latestNewsVersion, wrapText, renderNews, stateFile, readState, writeState, consumePostUpdateLaunch;
874
1045
  var init_news = __esm({
875
1046
  "src/news.ts"() {
876
1047
  "use strict";
877
1048
  import_node_fs4 = __toESM(require("node:fs"));
878
1049
  import_node_path4 = __toESM(require("node:path"));
879
1050
  init_config();
1051
+ init_ui();
880
1052
  NEWS = {
881
1053
  "2.0.0": [
882
1054
  'Modo ANALISE DE PROJETO (somente leitura): peca "analise/varredura/auditoria do meu projeto" e o clawfast troca sozinho para um auditor dedicado \u2014 sem /comando. Diga "modo normal" para sair.',
@@ -889,7 +1061,7 @@ var init_news = __esm({
889
1061
  "1.0.3": [
890
1062
  "Atualizacao: `clawfast update` atualiza o CLI e mostra as boas-vindas; aparece um aviso quando ha versao nova; /nov lista as novidades.",
891
1063
  "Skills: /skillcreator cria ou cola uma skill (de qualquer tamanho), /skills lista e /skill delete remove. As skills viram conhecimento disponivel para TODOS os modelos.",
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).",
1064
+ "Modelos na NVIDIA build: mistral-medium-3.5, gpt-oss-120b, glm-5.1 e qwen3.5-397b \u2014 todos com function calling de verdade (as ferramentas disparam).",
893
1065
  "Resiliencia a rate limit (429): cai para os outros modelos como contingencia e espera/retenta a cadeia automaticamente."
894
1066
  ]
895
1067
  };
@@ -905,14 +1077,50 @@ var init_news = __esm({
905
1077
  return 0;
906
1078
  })[0];
907
1079
  };
1080
+ wrapText = (text2, width) => {
1081
+ const words = text2.split(/\s+/).filter(Boolean);
1082
+ const lines = [];
1083
+ let line = "";
1084
+ for (const word of words) {
1085
+ if (line && vlen(line) + 1 + vlen(word) > width) {
1086
+ lines.push(line);
1087
+ line = word;
1088
+ } else {
1089
+ line = line ? `${line} ${word}` : word;
1090
+ }
1091
+ }
1092
+ if (line) lines.push(line);
1093
+ return lines.length ? lines : [""];
1094
+ };
908
1095
  renderNews = (version3) => {
909
1096
  const key = NEWS[version3] ? version3 : latestNewsVersion();
910
1097
  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}`;
1098
+ return `${C2.dim}Sem novidades registradas para esta versao.${C2.reset}`;
1099
+ }
1100
+ const cols2 = process.stdout.columns || 80;
1101
+ const BOX = Math.min(Math.max(cols2 - 2, 48), 80);
1102
+ const INNER2 = BOX - 4;
1103
+ const BULLET = "\u2022 ";
1104
+ const INDENT = " ".repeat(BULLET.length);
1105
+ const title = `Novidades \xB7 v${key}`;
1106
+ const topFill = "\u2500".repeat(Math.max(0, BOX - vlen(title) - 5));
1107
+ const top = `${C2.green}\u256D\u2500 ${C2.greenB}${C2.bold}${title}${C2.reset}${C2.green} ${topFill}\u256E${C2.reset}`;
1108
+ const bottom = `${C2.green}\u2570${"\u2500".repeat(BOX - 2)}\u256F${C2.reset}`;
1109
+ const row = (content) => {
1110
+ const pad = " ".repeat(Math.max(0, INNER2 - vlen(content)));
1111
+ return `${C2.green}\u2502 ${C2.reset}${content}${pad}${C2.green} \u2502${C2.reset}`;
1112
+ };
1113
+ const body = [row("")];
1114
+ NEWS[key].forEach((item, idx) => {
1115
+ if (idx > 0) body.push(row(""));
1116
+ const wrapped = wrapText(item, INNER2 - BULLET.length);
1117
+ wrapped.forEach((line, i) => {
1118
+ const prefix = i === 0 ? `${C2.cyanB}${BULLET}${C2.reset}` : INDENT;
1119
+ body.push(row(`${prefix}${line}`));
1120
+ });
1121
+ });
1122
+ body.push(row(""));
1123
+ return [top, ...body, bottom].join("\n");
916
1124
  };
917
1125
  stateFile = () => import_node_path4.default.join(clawfastHome(), "state.json");
918
1126
  readState = () => {
@@ -45557,25 +45765,29 @@ var init_providers = __esm({
45557
45765
  };
45558
45766
  };
45559
45767
  nvidiaPatchFetch = async (url2, init) => {
45560
- if (init?.body && typeof init.body === "string") {
45768
+ const key = process.env.NVIDIA_API_KEY?.trim();
45769
+ const headers = new Headers(init?.headers);
45770
+ if (key) headers.set("Authorization", `Bearer ${key}`);
45771
+ let nextInit = { ...init, headers };
45772
+ if (typeof nextInit.body === "string") {
45561
45773
  try {
45562
- const parsed = JSON.parse(init.body);
45774
+ const parsed = JSON.parse(nextInit.body);
45563
45775
  const patched = applyNvidiaMistralConfig(parsed);
45564
45776
  if (patched.changed) {
45565
- return globalThis.fetch(url2, {
45566
- ...init,
45567
- body: JSON.stringify(patched.body)
45568
- });
45777
+ nextInit = { ...nextInit, body: JSON.stringify(patched.body) };
45569
45778
  }
45570
45779
  } catch {
45571
45780
  }
45572
45781
  }
45573
- return globalThis.fetch(url2, init);
45782
+ return globalThis.fetch(url2, nextInit);
45574
45783
  };
45575
45784
  nvidia = createOpenAI({
45576
45785
  name: "nvidia",
45577
45786
  baseURL: process.env.NVIDIA_BASE_URL || "https://integrate.api.nvidia.com/v1",
45578
- apiKey: process.env.NVIDIA_API_KEY,
45787
+ // Placeholder so the SDK never throws "missing API key" at request build time
45788
+ // when the env is empty at load — nvidiaPatchFetch sets the real Authorization
45789
+ // header from process.env on every request (see above).
45790
+ apiKey: process.env.NVIDIA_API_KEY || "nvapi-clawfast-runtime",
45579
45791
  fetch: nvidiaPatchFetch
45580
45792
  });
45581
45793
  deepseek = createOpenAI({
@@ -45607,7 +45819,7 @@ var init_providers = __esm({
45607
45819
  "model-nvidia-mistral-medium-3.5": nvidia.chat(
45608
45820
  "mistralai/mistral-medium-3.5-128b"
45609
45821
  ),
45610
- "model-nvidia-kimi-k2.6": nvidia.chat("moonshotai/kimi-k2.6"),
45822
+ "model-nvidia-gpt-oss-120b": nvidia.chat("openai/gpt-oss-120b"),
45611
45823
  "model-nvidia-glm-5.1": nvidia.chat("z-ai/glm-5.1"),
45612
45824
  "model-nvidia-qwen3.5-397b": nvidia.chat("qwen/qwen3.5-397b-a17b"),
45613
45825
  // Extra explicit keys for the CLI.
@@ -45645,8 +45857,8 @@ var init_providers = __esm({
45645
45857
  ...hasEnvValue("NVIDIA_API_KEY") ? [
45646
45858
  "model-nvidia-mistral-medium-3.5",
45647
45859
  // NVIDIA mistralai/mistral-medium-3.5-128b
45648
- "model-nvidia-kimi-k2.6",
45649
- // NVIDIA moonshotai/kimi-k2.6
45860
+ "model-nvidia-gpt-oss-120b",
45861
+ // NVIDIA openai/gpt-oss-120b
45650
45862
  "model-nvidia-glm-5.1",
45651
45863
  // NVIDIA z-ai/glm-5.1
45652
45864
  "model-nvidia-qwen3.5-397b"
@@ -45672,7 +45884,7 @@ var init_providers = __esm({
45672
45884
  "model-opus-4.6": "May 2025",
45673
45885
  "model-kimi-k2.6": "April 2024",
45674
45886
  "model-nvidia-mistral-medium-3.5": "Unknown",
45675
- "model-nvidia-kimi-k2.6": "April 2024",
45887
+ "model-nvidia-gpt-oss-120b": "June 2024",
45676
45888
  "model-nvidia-glm-5.1": "Unknown",
45677
45889
  "model-nvidia-qwen3.5-397b": "Unknown",
45678
45890
  "model-deepseek-proxy": "July 2024",
@@ -45696,7 +45908,7 @@ var init_providers = __esm({
45696
45908
  "model-opus-4.6": "Anthropic Claude Opus 4.6",
45697
45909
  "model-kimi-k2.6": "Moonshot Kimi K2.6",
45698
45910
  "model-nvidia-mistral-medium-3.5": "NVIDIA - Mistral Medium 3.5",
45699
- "model-nvidia-kimi-k2.6": "NVIDIA - Moonshot Kimi K2.6",
45911
+ "model-nvidia-gpt-oss-120b": "NVIDIA - OpenAI GPT-OSS 120B",
45700
45912
  "model-nvidia-glm-5.1": "NVIDIA - Z.ai GLM 5.1",
45701
45913
  "model-nvidia-qwen3.5-397b": "NVIDIA - Qwen3.5 397B A17B",
45702
45914
  "model-deepseek-proxy": "DeepSeek (sessao web logada / deepsproxy)",
@@ -68695,14 +68907,14 @@ function inferShellFlag(shell2) {
68695
68907
  }
68696
68908
  return "-c";
68697
68909
  }
68698
- var import_node_child_process2, import_node_fs6, import_node_path5, import_node_os2, import_node_url, import_meta, LocalSandbox;
68910
+ var import_node_child_process2, import_node_fs6, import_node_path5, import_node_os3, import_node_url, import_meta, LocalSandbox;
68699
68911
  var init_local_sandbox = __esm({
68700
68912
  "src/local-sandbox.ts"() {
68701
68913
  "use strict";
68702
68914
  import_node_child_process2 = require("node:child_process");
68703
68915
  import_node_fs6 = require("node:fs");
68704
68916
  import_node_path5 = __toESM(require("node:path"));
68705
- import_node_os2 = __toESM(require("node:os"));
68917
+ import_node_os3 = __toESM(require("node:os"));
68706
68918
  import_node_url = require("node:url");
68707
68919
  init_utils4();
68708
68920
  import_meta = {};
@@ -68827,7 +69039,7 @@ var init_local_sandbox = __esm({
68827
69039
  this.shellBin = shellOverride;
68828
69040
  this.shellFlag = process.env.CLI_SHELL_FLAG || inferShellFlag(shellOverride);
68829
69041
  } else {
68830
- const shell2 = getDefaultShell(import_node_os2.default.platform());
69042
+ const shell2 = getDefaultShell(import_node_os3.default.platform());
68831
69043
  this.shellBin = shell2.shell;
68832
69044
  this.shellFlag = shell2.shellFlag;
68833
69045
  }
@@ -68905,23 +69117,23 @@ var init_local_sandbox = __esm({
68905
69117
  return "local";
68906
69118
  }
68907
69119
  getConnectionName() {
68908
- return `local:${import_node_os2.default.hostname()}`;
69120
+ return `local:${import_node_os3.default.hostname()}`;
68909
69121
  }
68910
69122
  getUserId() {
68911
69123
  return "local";
68912
69124
  }
68913
69125
  isWindows() {
68914
- return import_node_os2.default.platform() === "win32" && !this.isBashLikeShell();
69126
+ return import_node_os3.default.platform() === "win32" && !this.isBashLikeShell();
68915
69127
  }
68916
69128
  supportsPty() {
68917
69129
  return false;
68918
69130
  }
68919
69131
  getSandboxContext() {
68920
- const platform = `${import_node_os2.default.type()} ${import_node_os2.default.release()} (${import_node_os2.default.arch()})`;
69132
+ const platform = `${import_node_os3.default.type()} ${import_node_os3.default.release()} (${import_node_os3.default.arch()})`;
68921
69133
  const shellInvocation = `${this.shellBin} ${this.shellFlag}`;
68922
- const windowsNotes = import_node_os2.default.platform() === "win32" ? this.getWindowsShellNotes() : "";
69134
+ const windowsNotes = import_node_os3.default.platform() === "win32" ? this.getWindowsShellNotes() : "";
68923
69135
  const pentestToolingNotes = this.getLocalPentestToolingNotes();
68924
- return `You are executing commands directly on the user's local host (${platform}, hostname "${import_node_os2.default.hostname()}") in DANGEROUS MODE: there is NO sandbox isolation.
69136
+ return `You are executing commands directly on the user's local host (${platform}, hostname "${import_node_os3.default.hostname()}") in DANGEROUS MODE: there is NO sandbox isolation.
68925
69137
  Commands are invoked via \`${shellInvocation}\`. The working directory is "${this.workdir}".
68926
69138
  Be careful: file system, network and process operations all affect the real host system.
68927
69139
  A real human user is present at this terminal. When a command prompts for input \u2014 a password, a y/n confirmation, an interactive installer, a REPL prompt (python, mysql, ftp), an ssh/sudo prompt, etc. \u2014 the user types the answer and it is forwarded to the command's stdin. So you MAY run commands that prompt for input; just run the command and the user will respond when asked. Prefer non-interactive flags (like --yes) when they exist and are convenient, but interactive prompts are fully supported. Only full-screen / raw-mode TUI programs (vim, top, htop, less without \`| cat\`) are unsupported, since there is no PTY \u2014 avoid those and use line-oriented alternatives.
@@ -69010,7 +69222,7 @@ EDITING SCRIPTS:
69010
69222
  // alive — `taskkill /T` tears down the whole tree so Ctrl+C truly stops it.
69011
69223
  killChildTree(child) {
69012
69224
  const pid = child.pid;
69013
- if (pid && import_node_os2.default.platform() === "win32") {
69225
+ if (pid && import_node_os3.default.platform() === "win32") {
69014
69226
  try {
69015
69227
  (0, import_node_child_process2.spawn)("taskkill", ["/PID", String(pid), "/T", "/F"], {
69016
69228
  windowsHide: true
@@ -69065,7 +69277,7 @@ WINDOWS SHELL NOTES:
69065
69277
  - For HTTP, prefer \`curl.exe\` if available; for DNS use \`nslookup\`.`;
69066
69278
  }
69067
69279
  getLocalPentestToolingNotes() {
69068
- if (import_node_os2.default.platform() === "win32") {
69280
+ if (import_node_os3.default.platform() === "win32") {
69069
69281
  return `
69070
69282
 
69071
69283
  LOCAL PENTEST TOOLING:
@@ -69184,10 +69396,10 @@ function createRenderer() {
69184
69396
  reasoning(delta) {
69185
69397
  sep3("reasoning");
69186
69398
  if (!reasoningHeaderShown) {
69187
- out(`${C2.dim}pensando: `);
69399
+ out(`${C3.dim}pensando: `);
69188
69400
  reasoningHeaderShown = true;
69189
69401
  }
69190
- out(`${C2.dim}${delta}${C2.reset}`);
69402
+ out(`${C3.dim}${delta}${C3.reset}`);
69191
69403
  },
69192
69404
  toolCall(toolName, input) {
69193
69405
  sep3("tool");
@@ -69199,23 +69411,23 @@ function createRenderer() {
69199
69411
  const note = summarizeResult(toolName, output);
69200
69412
  if (note) {
69201
69413
  sep3("tool");
69202
- out(`${C2.dim} ok ${note}${C2.reset}
69414
+ out(`${C3.dim} ok ${note}${C3.reset}
69203
69415
  `);
69204
69416
  }
69205
69417
  },
69206
69418
  info(msg) {
69207
69419
  sep3("info");
69208
- out(`${C2.dim}${msg}${C2.reset}
69420
+ out(`${C3.dim}${msg}${C3.reset}
69209
69421
  `);
69210
69422
  },
69211
69423
  fallback(msg) {
69212
69424
  sep3("info");
69213
- out(`${C2.yellow}-> ${msg}${C2.reset}
69425
+ out(`${C3.yellow}-> ${msg}${C3.reset}
69214
69426
  `);
69215
69427
  },
69216
69428
  error(msg) {
69217
69429
  sep3("info");
69218
- out(`${C2.red}x ${msg}${C2.reset}
69430
+ out(`${C3.red}x ${msg}${C3.reset}
69219
69431
  `);
69220
69432
  },
69221
69433
  endTurn() {
@@ -69233,31 +69445,31 @@ function formatToolCall(toolName, input) {
69233
69445
  switch (toolName) {
69234
69446
  case "run_terminal_cmd": {
69235
69447
  const cmd = String(i.command ?? "").trim();
69236
- const bg = i.is_background ? `${C2.dim} (background)${C2.reset}` : "";
69237
- return `${C2.cyan}executando${C2.reset} ${C2.bold}$ ${truncate3(cmd, 400)}${C2.reset}${bg}`;
69448
+ const bg = i.is_background ? `${C3.dim} (background)${C3.reset}` : "";
69449
+ return `${C3.cyan}executando${C3.reset} ${C3.bold}$ ${truncate3(cmd, 400)}${C3.reset}${bg}`;
69238
69450
  }
69239
69451
  case "file": {
69240
69452
  const path10 = String(i.path ?? "");
69241
- const brief = i.brief ? `${C2.dim} - ${truncate3(String(i.brief))}${C2.reset}` : "";
69453
+ const brief = i.brief ? `${C3.dim} - ${truncate3(String(i.brief))}${C3.reset}` : "";
69242
69454
  const map2 = {
69243
- write: `${C2.green}criando arquivo${C2.reset}`,
69244
- edit: `${C2.yellow}editando arquivo${C2.reset}`,
69245
- append: `${C2.green}anexando arquivo${C2.reset}`,
69246
- read: `${C2.blue}lendo arquivo${C2.reset}`,
69247
- view: `${C2.blue}visualizando arquivo${C2.reset}`
69455
+ write: `${C3.green}criando arquivo${C3.reset}`,
69456
+ edit: `${C3.yellow}editando arquivo${C3.reset}`,
69457
+ append: `${C3.green}anexando arquivo${C3.reset}`,
69458
+ read: `${C3.blue}lendo arquivo${C3.reset}`,
69459
+ view: `${C3.blue}visualizando arquivo${C3.reset}`
69248
69460
  };
69249
69461
  const action = typeof i.action === "string" ? i.action : "";
69250
- const label = map2[action] ?? (action ? `${C2.blue}arquivo (${action})${C2.reset}` : `${C2.blue}preparando operacao de arquivo${C2.reset}`);
69251
- const target = path10 ? ` ${C2.bold}${path10}${C2.reset}` : "";
69462
+ const label = map2[action] ?? (action ? `${C3.blue}arquivo (${action})${C3.reset}` : `${C3.blue}preparando operacao de arquivo${C3.reset}`);
69463
+ const target = path10 ? ` ${C3.bold}${path10}${C3.reset}` : "";
69252
69464
  return `${label}${target}${brief}`;
69253
69465
  }
69254
69466
  case "todo_write":
69255
- return `${C2.magenta}atualizando lista de tarefas${C2.reset}`;
69467
+ return `${C3.magenta}atualizando lista de tarefas${C3.reset}`;
69256
69468
  default:
69257
- return `${C2.cyan}${toolName}${C2.reset} ${C2.dim}${truncate3(
69469
+ return `${C3.cyan}${toolName}${C3.reset} ${C3.dim}${truncate3(
69258
69470
  JSON.stringify(i),
69259
69471
  200
69260
- )}${C2.reset}`;
69472
+ )}${C3.reset}`;
69261
69473
  }
69262
69474
  }
69263
69475
  function summarizeResult(toolName, output) {
@@ -69271,11 +69483,11 @@ function summarizeResult(toolName, output) {
69271
69483
  if (toolName === "todo_write") return "tarefas salvas";
69272
69484
  return null;
69273
69485
  }
69274
- var C2, out, truncate3;
69486
+ var C3, out, truncate3;
69275
69487
  var init_render = __esm({
69276
69488
  "src/render.ts"() {
69277
69489
  "use strict";
69278
- C2 = {
69490
+ C3 = {
69279
69491
  reset: "\x1B[0m",
69280
69492
  dim: "\x1B[90m",
69281
69493
  red: "\x1B[31m",
@@ -69413,11 +69625,11 @@ async function ensureProxyReady(id, log2) {
69413
69625
  message: `${def.label}: o proxy n\xE3o respondeu em 90s. Tente de novo, ou rode 'npm run login' em ${dir}.`
69414
69626
  };
69415
69627
  }
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;
69628
+ var import_node_os4, import_node_path6, import_node_fs7, import_node_child_process3, DEFS, PROXY_MODEL_KEYS, proxyIdForModelKey, proxiesRoot, dirFor, healthUrl, baseUrl, wait, started, exitHooksInstalled, quoteArg, asShellCommand, run, hasCommand;
69417
69629
  var init_proxy_manager2 = __esm({
69418
69630
  "src/proxy-manager.ts"() {
69419
69631
  "use strict";
69420
- import_node_os3 = __toESM(require("node:os"));
69632
+ import_node_os4 = __toESM(require("node:os"));
69421
69633
  import_node_path6 = __toESM(require("node:path"));
69422
69634
  import_node_fs7 = require("node:fs");
69423
69635
  import_node_child_process3 = require("node:child_process");
@@ -69453,7 +69665,7 @@ var init_proxy_manager2 = __esm({
69453
69665
  return null;
69454
69666
  };
69455
69667
  proxiesRoot = () => import_node_path6.default.join(
69456
- process.env.CLAWFAST_HOME?.trim() || import_node_path6.default.join(import_node_os3.default.homedir(), ".clawfast"),
69668
+ process.env.CLAWFAST_HOME?.trim() || import_node_path6.default.join(import_node_os4.default.homedir(), ".clawfast"),
69457
69669
  "proxies"
69458
69670
  );
69459
69671
  dirFor = (def) => process.env[def.dirEnv]?.trim() || import_node_path6.default.join(proxiesRoot(), def.folder);
@@ -69915,7 +70127,7 @@ async function createAgent() {
69915
70127
  reason: "faltando NVIDIA_API_KEY em .env.local (https://build.nvidia.com/)",
69916
70128
  models: [
69917
70129
  "model-nvidia-mistral-medium-3.5",
69918
- "model-nvidia-kimi-k2.6",
70130
+ "model-nvidia-gpt-oss-120b",
69919
70131
  "model-nvidia-glm-5.1",
69920
70132
  "model-nvidia-qwen3.5-397b"
69921
70133
  ].map((key) => ({ key, label: labelFor(key) }))
@@ -70490,7 +70702,7 @@ Regras:
70490
70702
  ];
70491
70703
  MODEL_LABELS = {
70492
70704
  "model-nvidia-mistral-medium-3.5": "NVIDIA - mistralai/mistral-medium-3.5-128b",
70493
- "model-nvidia-kimi-k2.6": "NVIDIA - moonshotai/kimi-k2.6",
70705
+ "model-nvidia-gpt-oss-120b": "NVIDIA - openai/gpt-oss-120b",
70494
70706
  "model-nvidia-glm-5.1": "NVIDIA - z-ai/glm-5.1",
70495
70707
  "model-nvidia-qwen3.5-397b": "NVIDIA - qwen/qwen3.5-397b-a17b",
70496
70708
  "model-openai-chat-latest": "OpenAI - chat-latest",
@@ -70659,130 +70871,6 @@ ${section}` : "";
70659
70871
  }
70660
70872
  });
70661
70873
 
70662
- // src/ui.ts
70663
- var ui_exports = {};
70664
- __export(ui_exports, {
70665
- agentHeader: () => agentHeader,
70666
- buildBanner: () => buildBanner,
70667
- shellPrompt: () => shellPrompt,
70668
- shortCwd: () => shortCwd,
70669
- ui: () => ui,
70670
- vlen: () => vlen
70671
- });
70672
- function shortCwd() {
70673
- const cwd = process.cwd();
70674
- const home = import_node_os4.default.homedir();
70675
- const rel = cwd.startsWith(home) ? "~" + cwd.slice(home.length) : cwd;
70676
- const norm = rel.replace(/\\/g, "/");
70677
- if (norm.length <= 30) return norm;
70678
- const parts = norm.split("/");
70679
- return parts.length > 3 ? `${parts[0]}/\u2026/${parts[parts.length - 1]}` : norm.slice(-30);
70680
- }
70681
- function asciiTitle(text2) {
70682
- const rows = 6;
70683
- const out3 = [];
70684
- for (let r = 0; r < rows; r++) {
70685
- out3.push(
70686
- [...text2].map((ch) => GLYPHS[ch] ? GLYPHS[ch][r] : " ").join(" ")
70687
- );
70688
- }
70689
- return out3;
70690
- }
70691
- function buildBanner(_systemPromptChars, version3 = "1") {
70692
- const user = (import_node_os4.default.userInfo().username || "hacker").toLowerCase();
70693
- const host = (import_node_os4.default.hostname() || "localhost").split(".")[0].toLowerCase();
70694
- const art = asciiTitle("CLAWFAST");
70695
- const artW = vlen(art[0]);
70696
- const slogan = "Com o clawfast voc\xEA faz tudo";
70697
- const header = [
70698
- "",
70699
- ...art.map((line) => `${C3.greenB}${C3.bold}${line}${C3.reset}`),
70700
- "",
70701
- `${C3.cyanB}${C3.bold}${center(slogan, artW)}${C3.reset}`,
70702
- ""
70703
- ];
70704
- const info = [
70705
- { text: "" },
70706
- { text: `Bem-vindo de volta, ${user}!`, accent: true },
70707
- { text: "" },
70708
- { text: "clawfast usa a pasta SPRIT/ para criar" },
70709
- { text: "arquivos, scripts e tudo mais." },
70710
- { text: "" },
70711
- { text: `${user}@${host} \xB7 sem limites` },
70712
- { text: shortCwd() },
70713
- { text: "" }
70714
- ];
70715
- const title = `clawfast v${version3}`;
70716
- const topFill = "\u2500".repeat(Math.max(0, BOX_W - vlen(title) - 5));
70717
- const top = `${C3.green}\u256D\u2500 ${C3.greenB}${C3.bold}${title}${C3.reset}${C3.green} ${topFill}\u256E${C3.reset}`;
70718
- const bottom = `${C3.green}\u2570${"\u2500".repeat(BOX_W - 2)}\u256F${C3.reset}`;
70719
- const cardLines = info.map(({ text: text2, accent }) => {
70720
- const color = accent ? `${C3.greenB}${C3.bold}` : C3.green;
70721
- const body = `${color}${padEndV(text2, INNER)}${C3.reset}`;
70722
- return `${C3.green}\u2502 ${C3.reset}${body}${C3.green} \u2502${C3.reset}`;
70723
- });
70724
- const card = [top, ...cardLines, bottom];
70725
- return "\n" + [...header, ...card].join("\n") + "\n";
70726
- }
70727
- function shellPrompt() {
70728
- const user = (import_node_os4.default.userInfo().username || "hacker").toLowerCase();
70729
- const host = (import_node_os4.default.hostname() || "localhost").split(".")[0].toLowerCase();
70730
- const W = 52;
70731
- const label = " \u2709 mensagem ";
70732
- const topFill = "\u2500".repeat(Math.max(0, W - vlen(label) - 3));
70733
- const top = `${C3.green}\u256D\u2500${C3.greenB}${C3.bold}${label}${C3.reset}${C3.green}${topFill}\u256E${C3.reset}`;
70734
- const id = `${user}\u327F${host} \xB7 ${shortCwd()}`;
70735
- const mid = `${C3.green}\u2502 ${C3.dim}${id}${C3.reset}`;
70736
- const bottom = `${C3.green}\u2570\u2500${C3.greenB}${C3.bold}\u276F${C3.reset} `;
70737
- return `
70738
- ${top}
70739
- ${mid}
70740
- ${bottom}`;
70741
- }
70742
- function agentHeader() {
70743
- return `${C3.magenta}\u256D\u2500 clawfast ${"\u2500".repeat(20)}${C3.reset}
70744
- `;
70745
- }
70746
- var import_node_os4, ESC, C3, INNER, BOX_W, vlen, padEndV, center, GLYPHS, ui;
70747
- var init_ui = __esm({
70748
- "src/ui.ts"() {
70749
- "use strict";
70750
- import_node_os4 = __toESM(require("node:os"));
70751
- ESC = "\x1B[";
70752
- C3 = {
70753
- reset: `${ESC}0m`,
70754
- bold: `${ESC}1m`,
70755
- dim: `${ESC}90m`,
70756
- green: `${ESC}32m`,
70757
- greenB: `${ESC}92m`,
70758
- cyan: `${ESC}36m`,
70759
- cyanB: `${ESC}96m`,
70760
- magenta: `${ESC}95m`,
70761
- yellow: `${ESC}93m`,
70762
- red: `${ESC}91m`
70763
- };
70764
- INNER = 42;
70765
- BOX_W = INNER + 4;
70766
- vlen = (s) => [...s.replace(/\x1b\[[0-9;]*m/g, "")].length;
70767
- padEndV = (s, w) => s + " ".repeat(Math.max(0, w - vlen(s)));
70768
- center = (s, w) => {
70769
- const pad = Math.max(0, w - vlen(s));
70770
- const left = Math.floor(pad / 2);
70771
- return " ".repeat(left) + s + " ".repeat(pad - left);
70772
- };
70773
- GLYPHS = {
70774
- C: [" \u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588\u2588"],
70775
- L: ["\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588\u2588"],
70776
- A: [" \u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588"],
70777
- W: ["\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588\u2588", "\u2588\u2588 \u2588 \u2588\u2588", "\u2588\u2588 \u2588 \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 \u2588\u2588 "],
70778
- F: ["\u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 ", "\u2588\u2588 "],
70779
- S: [" \u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588 ", " \u2588\u2588", " \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588 "],
70780
- T: ["\u2588\u2588\u2588\u2588\u2588\u2588", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 ", " \u2588\u2588 "]
70781
- };
70782
- ui = { C: C3, buildBanner, shellPrompt, agentHeader };
70783
- }
70784
- });
70785
-
70786
70874
  // src/interactive-input.ts
70787
70875
  var interactive_input_exports = {};
70788
70876
  __export(interactive_input_exports, {
@@ -70822,6 +70910,9 @@ var init_interactive_input = __esm({
70822
70910
  // instead of the full message box + dropdown — used for the /skillcreator
70823
70911
  // step-by-step capture so each phase shows what it's asking for.
70824
70912
  this.promptLabel = null;
70913
+ // When true, the submitted value is NOT recorded in ↑ history (used for the
70914
+ // /api key prompt so a pasted secret can't be recalled with the up arrow).
70915
+ this.promptSecret = false;
70825
70916
  this.inputLineIndex = 2;
70826
70917
  import_node_readline3.default.emitKeypressEvents(paste.input);
70827
70918
  paste.input.on("keypress", (str, key) => {
@@ -70835,6 +70926,7 @@ var init_interactive_input = __esm({
70835
70926
  */
70836
70927
  prompt(opts = {}) {
70837
70928
  this.promptLabel = opts.label ?? null;
70929
+ this.promptSecret = opts.secret ?? false;
70838
70930
  const initial = this.promptLabel === null && this.pendingInitial ? this.pendingInitial : "";
70839
70931
  this.pendingInitial = null;
70840
70932
  this.buffer = initial;
@@ -70961,7 +71053,7 @@ var init_interactive_input = __esm({
70961
71053
  this.cursor = name25.length;
70962
71054
  }
70963
71055
  const value = this.paste.expand(this.buffer);
70964
- if (value.trim()) this.history.push(value);
71056
+ if (value.trim() && !this.promptSecret) this.history.push(value);
70965
71057
  this.finishLine();
70966
71058
  return { result: { type: "line", value } };
70967
71059
  }
@@ -71263,6 +71355,7 @@ async function main() {
71263
71355
  );
71264
71356
  const COMMANDS = [
71265
71357
  { name: "/model", desc: "trocar o modelo (seletor com setas)" },
71358
+ { name: "/api", desc: "trocar a chave NVIDIA (testa e ativa na hora)" },
71266
71359
  { name: "/skills", desc: "listar as skills instaladas" },
71267
71360
  { name: "/skillcreator", desc: "criar uma nova skill" },
71268
71361
  { name: "/system", desc: "salvar o system prompt (HTML) na \xC1rea de Trabalho" },
@@ -71541,6 +71634,58 @@ ${C5.dim}ja disponivel para todos os modelos nesta sessao.${C5.reset}
71541
71634
  printFatal(err);
71542
71635
  }
71543
71636
  };
71637
+ const handleApiSwap = async (inlineKey) => {
71638
+ let raw = inlineKey;
71639
+ if (!raw) {
71640
+ process.stdout.write(
71641
+ `${C5.dim}Cole a nova chave NVIDIA (cria em ${C5.reset}${C5.cyan}https://build.nvidia.com/${C5.reset}${C5.dim}). Enter vazio ou Ctrl+C cancela.${C5.reset}
71642
+ `
71643
+ );
71644
+ const res = await inputUI.prompt({
71645
+ label: "nova NVIDIA API key",
71646
+ secret: true
71647
+ });
71648
+ if (res.type !== "line" || !res.value.trim()) {
71649
+ process.stdout.write(`${C5.dim}troca de chave cancelada${C5.reset}
71650
+ `);
71651
+ return;
71652
+ }
71653
+ raw = res.value;
71654
+ }
71655
+ const key = raw.replace(/\s+/g, "").match(/nvapi-[A-Za-z0-9_-]+/)?.[0] ?? "";
71656
+ if (!key) {
71657
+ process.stdout.write(
71658
+ `${C5.red}\u2717 n\xE3o encontrei uma chave NVIDIA no que foi colado${C5.reset} ${C5.dim}(esperado um token "nvapi-\u2026"; cole a chave completa).${C5.reset}
71659
+ `
71660
+ );
71661
+ return;
71662
+ }
71663
+ process.stdout.write(`${C5.dim}testando a chave na NVIDIA\u2026${C5.reset}
71664
+ `);
71665
+ const test = await testNvidiaKey(key);
71666
+ if (!test.ok) {
71667
+ if (test.status === 401 || test.status === 403) {
71668
+ process.stdout.write(
71669
+ `${C5.red}\u2717 a NVIDIA recusou a chave (${test.status}): ${test.detail}${C5.reset}
71670
+ ${C5.dim}chave N\xC3O salva \u2014 confira se copiou inteira e se a conta tem acesso de infer\xEAncia.${C5.reset}
71671
+ `
71672
+ );
71673
+ return;
71674
+ }
71675
+ process.stdout.write(
71676
+ `${C5.yellow}\u26A0 n\xE3o consegui validar (${test.status || "rede"}): ${test.detail}${C5.reset}
71677
+ ${C5.dim}salvando mesmo assim \u2014 o pr\xF3ximo pedido vai usar a chave nova.${C5.reset}
71678
+ `
71679
+ );
71680
+ }
71681
+ const file2 = swapNvidiaKey(key);
71682
+ const masked = `${key.slice(0, 9)}\u2026${key.slice(-4)} (${key.length} chars)`;
71683
+ process.stdout.write(
71684
+ `${C5.green}\u2713 chave NVIDIA trocada e ativa${C5.reset} ${C5.dim}${masked}${C5.reset}
71685
+ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
71686
+ `
71687
+ );
71688
+ };
71544
71689
  const handleLine = async (line) => {
71545
71690
  if (closing) return;
71546
71691
  const input = line.trim();
@@ -71599,12 +71744,15 @@ ${C5.cyan}${filePath}${C5.reset}
71599
71744
  }
71600
71745
  return;
71601
71746
  }
71747
+ if (input === "/api" || input.startsWith("/api ")) {
71748
+ await handleApiSwap(input.replace(/^\/api\s*/, "").trim());
71749
+ return;
71750
+ }
71602
71751
  if (input === "/nov" || input === "/novidades") {
71603
- process.stdout.write(
71604
- `
71605
- ${C5.cyan}${renderNews(clawfastVersion())}${C5.reset}
71606
- `
71607
- );
71752
+ process.stdout.write(`
71753
+ ${renderNews(clawfastVersion())}
71754
+
71755
+ `);
71608
71756
  return;
71609
71757
  }
71610
71758
  if (!input) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawfast",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "CLAWFAST — agente de pentest no terminal. Com o clawfast você faz tudo.",
5
5
  "bin": {
6
6
  "clawfast": "dist/clawfast.cjs"