clawfast 2.2.1 → 2.4.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.
- package/README.md +4 -6
- package/dist/clawfast.cjs +1069 -684
- package/package.json +1 -1
package/dist/clawfast.cjs
CHANGED
|
@@ -199,8 +199,8 @@ var init_boot_ui = __esm({
|
|
|
199
199
|
var require_main = __commonJS({
|
|
200
200
|
"../node_modules/.pnpm/dotenv@17.4.2/node_modules/dotenv/lib/main.js"(exports2, module2) {
|
|
201
201
|
"use strict";
|
|
202
|
-
var
|
|
203
|
-
var
|
|
202
|
+
var fs9 = require("fs");
|
|
203
|
+
var path13 = require("path");
|
|
204
204
|
var os7 = require("os");
|
|
205
205
|
var crypto2 = require("crypto");
|
|
206
206
|
var TIPS = [
|
|
@@ -331,7 +331,7 @@ var require_main = __commonJS({
|
|
|
331
331
|
if (options && options.path && options.path.length > 0) {
|
|
332
332
|
if (Array.isArray(options.path)) {
|
|
333
333
|
for (const filepath of options.path) {
|
|
334
|
-
if (
|
|
334
|
+
if (fs9.existsSync(filepath)) {
|
|
335
335
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
336
336
|
}
|
|
337
337
|
}
|
|
@@ -339,15 +339,15 @@ var require_main = __commonJS({
|
|
|
339
339
|
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
340
340
|
}
|
|
341
341
|
} else {
|
|
342
|
-
possibleVaultPath =
|
|
342
|
+
possibleVaultPath = path13.resolve(process.cwd(), ".env.vault");
|
|
343
343
|
}
|
|
344
|
-
if (
|
|
344
|
+
if (fs9.existsSync(possibleVaultPath)) {
|
|
345
345
|
return possibleVaultPath;
|
|
346
346
|
}
|
|
347
347
|
return null;
|
|
348
348
|
}
|
|
349
349
|
function _resolveHome(envPath) {
|
|
350
|
-
return envPath[0] === "~" ?
|
|
350
|
+
return envPath[0] === "~" ? path13.join(os7.homedir(), envPath.slice(1)) : envPath;
|
|
351
351
|
}
|
|
352
352
|
function _configVault(options) {
|
|
353
353
|
const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
|
|
@@ -364,7 +364,7 @@ var require_main = __commonJS({
|
|
|
364
364
|
return { parsed };
|
|
365
365
|
}
|
|
366
366
|
function configDotenv(options) {
|
|
367
|
-
const dotenvPath =
|
|
367
|
+
const dotenvPath = path13.resolve(process.cwd(), ".env");
|
|
368
368
|
let encoding = "utf8";
|
|
369
369
|
let processEnv = process.env;
|
|
370
370
|
if (options && options.processEnv != null) {
|
|
@@ -392,13 +392,13 @@ var require_main = __commonJS({
|
|
|
392
392
|
}
|
|
393
393
|
let lastError;
|
|
394
394
|
const parsedAll = {};
|
|
395
|
-
for (const
|
|
395
|
+
for (const path14 of optionPaths) {
|
|
396
396
|
try {
|
|
397
|
-
const parsed = DotenvModule.parse(
|
|
397
|
+
const parsed = DotenvModule.parse(fs9.readFileSync(path14, { encoding }));
|
|
398
398
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
399
399
|
} catch (e) {
|
|
400
400
|
if (debug) {
|
|
401
|
-
_debug(`failed to load ${
|
|
401
|
+
_debug(`failed to load ${path14} ${e.message}`);
|
|
402
402
|
}
|
|
403
403
|
lastError = e;
|
|
404
404
|
}
|
|
@@ -411,7 +411,7 @@ var require_main = __commonJS({
|
|
|
411
411
|
const shortPaths = [];
|
|
412
412
|
for (const filePath of optionPaths) {
|
|
413
413
|
try {
|
|
414
|
-
const relative2 =
|
|
414
|
+
const relative2 = path13.relative(process.cwd(), filePath);
|
|
415
415
|
shortPaths.push(relative2);
|
|
416
416
|
} catch (e) {
|
|
417
417
|
if (debug) {
|
|
@@ -565,7 +565,7 @@ async function testNvidiaKey(key) {
|
|
|
565
565
|
"Content-Type": "application/json"
|
|
566
566
|
},
|
|
567
567
|
body: JSON.stringify({
|
|
568
|
-
model: "
|
|
568
|
+
model: "mistralai/mistral-medium-3.5-128b",
|
|
569
569
|
messages: [{ role: "user", content: "hi" }],
|
|
570
570
|
max_tokens: 1
|
|
571
571
|
})
|
|
@@ -689,7 +689,7 @@ var clawfastVersion, isDevVersion, isNewerVersion;
|
|
|
689
689
|
var init_version = __esm({
|
|
690
690
|
"src/version.ts"() {
|
|
691
691
|
"use strict";
|
|
692
|
-
clawfastVersion = () => true ? "2.
|
|
692
|
+
clawfastVersion = () => true ? "2.4.0" : devVersionFromPackageJson();
|
|
693
693
|
isDevVersion = () => clawfastVersion().includes("-dev");
|
|
694
694
|
isNewerVersion = (a, b) => {
|
|
695
695
|
const parse3 = (v) => v.split("-")[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
@@ -1138,7 +1138,9 @@ function bannerSections(opts) {
|
|
|
1138
1138
|
}
|
|
1139
1139
|
function buildBanner(_systemPromptChars, version3 = "1") {
|
|
1140
1140
|
const { artRows, slogan, panel } = bannerSections({ version: version3 });
|
|
1141
|
-
return "\n" + ["", ...artRows, "", center(slogan, vlen(panel[0])), "", ...panel].join(
|
|
1141
|
+
return "\n" + ["", ...artRows, "", center(slogan, vlen(panel[0])), "", ...panel].join(
|
|
1142
|
+
"\n"
|
|
1143
|
+
) + "\n";
|
|
1142
1144
|
}
|
|
1143
1145
|
async function playBanner(opts = {}) {
|
|
1144
1146
|
const { artRows, slogan, panel } = bannerSections(opts);
|
|
@@ -1146,7 +1148,9 @@ async function playBanner(opts = {}) {
|
|
|
1146
1148
|
process.stdout.write("\n");
|
|
1147
1149
|
await revealLines(artRows, 55);
|
|
1148
1150
|
process.stdout.write("\n");
|
|
1149
|
-
const padLeft = " ".repeat(
|
|
1151
|
+
const padLeft = " ".repeat(
|
|
1152
|
+
Math.max(0, Math.floor((width - vlen(slogan)) / 2))
|
|
1153
|
+
);
|
|
1150
1154
|
await typeOut(SLOGAN, {
|
|
1151
1155
|
perChar: 14,
|
|
1152
1156
|
render: (s) => padLeft + gradient(s, { bold: true })
|
|
@@ -1154,8 +1158,10 @@ async function playBanner(opts = {}) {
|
|
|
1154
1158
|
process.stdout.write("\n");
|
|
1155
1159
|
await sweepRule(width);
|
|
1156
1160
|
for (const check2 of BOOT_CHECKS) {
|
|
1157
|
-
process.stdout.write(
|
|
1158
|
-
`)
|
|
1161
|
+
process.stdout.write(
|
|
1162
|
+
` ${paint("[\u2713]", PAL.green, { bold: true })} ${dim(check2)}
|
|
1163
|
+
`
|
|
1164
|
+
);
|
|
1159
1165
|
await sleep(110);
|
|
1160
1166
|
}
|
|
1161
1167
|
process.stdout.write("\n");
|
|
@@ -1261,6 +1267,12 @@ var init_news = __esm({
|
|
|
1261
1267
|
init_ui();
|
|
1262
1268
|
init_theme();
|
|
1263
1269
|
NEWS = {
|
|
1270
|
+
"2.3.0": [
|
|
1271
|
+
"Linux liberado e turbinado: o clawfast detecta Kali/Linux (e se e root) e entra em modo FULL-POWER \u2014 shell real, sockets, apt/pip/pipx, systemctl e todo o arsenal Kali (nmap, masscan, sqlmap, metasploit, hydra, hashcat, nuclei, gobuster/ffuf...).",
|
|
1272
|
+
"Python 100% liberado e scan a vontade: portas, faixas de IP/CIDR, servicos/versoes e ate numeros (OSINT de telefone com phoneinfoga). Tudo o que o SO permite, ele faz.",
|
|
1273
|
+
'Prompt do Kali repassado pra voce: quando uma ferramenta/instalador/login para e pede algo (criar conta, y/n, senha do sudo, OTP), o clawfast avisa exatamente o que "o kali" esta pedindo; voce digita aqui e ele repassa pro programa pelo stdin e segue.',
|
|
1274
|
+
"Escopo liberado por padrao no Linux: http_request e o toolkit de recon nao exigem mais editar scope.txt. Volte ao restrito com CLAWFAST_STRICT_SCOPE=1; force liberado em qualquer SO com CLAWFAST_UNRESTRICTED=1."
|
|
1275
|
+
],
|
|
1264
1276
|
"2.1.0": [
|
|
1265
1277
|
'Novo visual "Verde Matrix Elite": gradiente verde\u2192teal\u2192ciano em todo o terminal. Banner cinematografico no boot \u2014 o wordmark desce em cortina, o slogan se datilografa e o painel "ACESSO CONCEDIDO" abaixa.',
|
|
1266
1278
|
"Header de cada turno animado, spinner de boot pulsando em gradiente e caixas (prompt, /model, /nov) com bordas pesadas realcadas.",
|
|
@@ -1937,10 +1949,10 @@ function mergeDefs(...defs) {
|
|
|
1937
1949
|
function cloneDef(schema) {
|
|
1938
1950
|
return mergeDefs(schema._zod.def);
|
|
1939
1951
|
}
|
|
1940
|
-
function getElementAtPath(obj,
|
|
1941
|
-
if (!
|
|
1952
|
+
function getElementAtPath(obj, path13) {
|
|
1953
|
+
if (!path13)
|
|
1942
1954
|
return obj;
|
|
1943
|
-
return
|
|
1955
|
+
return path13.reduce((acc, key) => acc?.[key], obj);
|
|
1944
1956
|
}
|
|
1945
1957
|
function promiseAllObject(promisesObj) {
|
|
1946
1958
|
const keys = Object.keys(promisesObj);
|
|
@@ -2268,11 +2280,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
2268
2280
|
}
|
|
2269
2281
|
return false;
|
|
2270
2282
|
}
|
|
2271
|
-
function prefixIssues(
|
|
2283
|
+
function prefixIssues(path13, issues) {
|
|
2272
2284
|
return issues.map((iss) => {
|
|
2273
2285
|
var _a25;
|
|
2274
2286
|
(_a25 = iss).path ?? (_a25.path = []);
|
|
2275
|
-
iss.path.unshift(
|
|
2287
|
+
iss.path.unshift(path13);
|
|
2276
2288
|
return iss;
|
|
2277
2289
|
});
|
|
2278
2290
|
}
|
|
@@ -2490,16 +2502,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2490
2502
|
}
|
|
2491
2503
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
2492
2504
|
const fieldErrors = { _errors: [] };
|
|
2493
|
-
const processError = (error52,
|
|
2505
|
+
const processError = (error52, path13 = []) => {
|
|
2494
2506
|
for (const issue2 of error52.issues) {
|
|
2495
2507
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2496
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2508
|
+
issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
|
|
2497
2509
|
} else if (issue2.code === "invalid_key") {
|
|
2498
|
-
processError({ issues: issue2.issues }, [...
|
|
2510
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
2499
2511
|
} else if (issue2.code === "invalid_element") {
|
|
2500
|
-
processError({ issues: issue2.issues }, [...
|
|
2512
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
2501
2513
|
} else {
|
|
2502
|
-
const fullpath = [...
|
|
2514
|
+
const fullpath = [...path13, ...issue2.path];
|
|
2503
2515
|
if (fullpath.length === 0) {
|
|
2504
2516
|
fieldErrors._errors.push(mapper(issue2));
|
|
2505
2517
|
} else {
|
|
@@ -2526,17 +2538,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2526
2538
|
}
|
|
2527
2539
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
2528
2540
|
const result = { errors: [] };
|
|
2529
|
-
const processError = (error52,
|
|
2541
|
+
const processError = (error52, path13 = []) => {
|
|
2530
2542
|
var _a25, _b18;
|
|
2531
2543
|
for (const issue2 of error52.issues) {
|
|
2532
2544
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2533
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2545
|
+
issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
|
|
2534
2546
|
} else if (issue2.code === "invalid_key") {
|
|
2535
|
-
processError({ issues: issue2.issues }, [...
|
|
2547
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
2536
2548
|
} else if (issue2.code === "invalid_element") {
|
|
2537
|
-
processError({ issues: issue2.issues }, [...
|
|
2549
|
+
processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
|
|
2538
2550
|
} else {
|
|
2539
|
-
const fullpath = [...
|
|
2551
|
+
const fullpath = [...path13, ...issue2.path];
|
|
2540
2552
|
if (fullpath.length === 0) {
|
|
2541
2553
|
result.errors.push(mapper(issue2));
|
|
2542
2554
|
continue;
|
|
@@ -2568,8 +2580,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2568
2580
|
}
|
|
2569
2581
|
function toDotPath(_path) {
|
|
2570
2582
|
const segs = [];
|
|
2571
|
-
const
|
|
2572
|
-
for (const seg of
|
|
2583
|
+
const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
2584
|
+
for (const seg of path13) {
|
|
2573
2585
|
if (typeof seg === "number")
|
|
2574
2586
|
segs.push(`[${seg}]`);
|
|
2575
2587
|
else if (typeof seg === "symbol")
|
|
@@ -16072,13 +16084,13 @@ function resolveRef(ref, ctx) {
|
|
|
16072
16084
|
if (!ref.startsWith("#")) {
|
|
16073
16085
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
16074
16086
|
}
|
|
16075
|
-
const
|
|
16076
|
-
if (
|
|
16087
|
+
const path13 = ref.slice(1).split("/").filter(Boolean);
|
|
16088
|
+
if (path13.length === 0) {
|
|
16077
16089
|
return ctx.rootSchema;
|
|
16078
16090
|
}
|
|
16079
16091
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
16080
|
-
if (
|
|
16081
|
-
const key =
|
|
16092
|
+
if (path13[0] === defsKey) {
|
|
16093
|
+
const key = path13[1];
|
|
16082
16094
|
if (!key || !ctx.defs[key]) {
|
|
16083
16095
|
throw new Error(`Reference not found: ${ref}`);
|
|
16084
16096
|
}
|
|
@@ -17267,8 +17279,8 @@ var init_parseUtil = __esm({
|
|
|
17267
17279
|
init_errors3();
|
|
17268
17280
|
init_en2();
|
|
17269
17281
|
makeIssue = (params) => {
|
|
17270
|
-
const { data, path:
|
|
17271
|
-
const fullPath = [...
|
|
17282
|
+
const { data, path: path13, errorMaps, issueData } = params;
|
|
17283
|
+
const fullPath = [...path13, ...issueData.path || []];
|
|
17272
17284
|
const fullIssue = {
|
|
17273
17285
|
...issueData,
|
|
17274
17286
|
path: fullPath
|
|
@@ -17551,11 +17563,11 @@ var init_types = __esm({
|
|
|
17551
17563
|
init_parseUtil();
|
|
17552
17564
|
init_util2();
|
|
17553
17565
|
ParseInputLazyPath = class {
|
|
17554
|
-
constructor(parent, value,
|
|
17566
|
+
constructor(parent, value, path13, key) {
|
|
17555
17567
|
this._cachedPath = [];
|
|
17556
17568
|
this.parent = parent;
|
|
17557
17569
|
this.data = value;
|
|
17558
|
-
this._path =
|
|
17570
|
+
this._path = path13;
|
|
17559
17571
|
this._key = key;
|
|
17560
17572
|
}
|
|
17561
17573
|
get path() {
|
|
@@ -23594,8 +23606,8 @@ var require_auth_config = __commonJS({
|
|
|
23594
23606
|
writeAuthConfig: () => writeAuthConfig
|
|
23595
23607
|
});
|
|
23596
23608
|
module2.exports = __toCommonJS(auth_config_exports);
|
|
23597
|
-
var
|
|
23598
|
-
var
|
|
23609
|
+
var fs9 = __toESM2(require("fs"));
|
|
23610
|
+
var path13 = __toESM2(require("path"));
|
|
23599
23611
|
var import_token_util = require_token_util();
|
|
23600
23612
|
function getAuthConfigPath() {
|
|
23601
23613
|
const dataDir = (0, import_token_util.getVercelDataDir)();
|
|
@@ -23604,15 +23616,15 @@ var require_auth_config = __commonJS({
|
|
|
23604
23616
|
`Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`
|
|
23605
23617
|
);
|
|
23606
23618
|
}
|
|
23607
|
-
return
|
|
23619
|
+
return path13.join(dataDir, "auth.json");
|
|
23608
23620
|
}
|
|
23609
23621
|
function readAuthConfig() {
|
|
23610
23622
|
try {
|
|
23611
23623
|
const authPath = getAuthConfigPath();
|
|
23612
|
-
if (!
|
|
23624
|
+
if (!fs9.existsSync(authPath)) {
|
|
23613
23625
|
return null;
|
|
23614
23626
|
}
|
|
23615
|
-
const content =
|
|
23627
|
+
const content = fs9.readFileSync(authPath, "utf8");
|
|
23616
23628
|
if (!content) {
|
|
23617
23629
|
return null;
|
|
23618
23630
|
}
|
|
@@ -23623,11 +23635,11 @@ var require_auth_config = __commonJS({
|
|
|
23623
23635
|
}
|
|
23624
23636
|
function writeAuthConfig(config3) {
|
|
23625
23637
|
const authPath = getAuthConfigPath();
|
|
23626
|
-
const authDir =
|
|
23627
|
-
if (!
|
|
23628
|
-
|
|
23638
|
+
const authDir = path13.dirname(authPath);
|
|
23639
|
+
if (!fs9.existsSync(authDir)) {
|
|
23640
|
+
fs9.mkdirSync(authDir, { mode: 504, recursive: true });
|
|
23629
23641
|
}
|
|
23630
|
-
|
|
23642
|
+
fs9.writeFileSync(authPath, JSON.stringify(config3, null, 2), { mode: 384 });
|
|
23631
23643
|
}
|
|
23632
23644
|
function isValidAccessToken(authConfig, expirationBufferMs = 0) {
|
|
23633
23645
|
if (!authConfig.token)
|
|
@@ -23818,8 +23830,8 @@ var require_token_util = __commonJS({
|
|
|
23818
23830
|
saveToken: () => saveToken
|
|
23819
23831
|
});
|
|
23820
23832
|
module2.exports = __toCommonJS(token_util_exports);
|
|
23821
|
-
var
|
|
23822
|
-
var
|
|
23833
|
+
var path13 = __toESM2(require("path"));
|
|
23834
|
+
var fs9 = __toESM2(require("fs"));
|
|
23823
23835
|
var import_token_error = require_token_error();
|
|
23824
23836
|
var import_token_io = require_token_io();
|
|
23825
23837
|
var import_auth_config = require_auth_config();
|
|
@@ -23831,7 +23843,7 @@ var require_token_util = __commonJS({
|
|
|
23831
23843
|
if (!dataDir) {
|
|
23832
23844
|
return null;
|
|
23833
23845
|
}
|
|
23834
|
-
return
|
|
23846
|
+
return path13.join(dataDir, vercelFolder);
|
|
23835
23847
|
}
|
|
23836
23848
|
async function getVercelToken2(options) {
|
|
23837
23849
|
const authConfig = (0, import_auth_config.readAuthConfig)();
|
|
@@ -23907,13 +23919,13 @@ var require_token_util = __commonJS({
|
|
|
23907
23919
|
"Unable to find project root directory. Have you linked your project with `vc link?`"
|
|
23908
23920
|
);
|
|
23909
23921
|
}
|
|
23910
|
-
const prjPath =
|
|
23911
|
-
if (!
|
|
23922
|
+
const prjPath = path13.join(dir, ".vercel", "project.json");
|
|
23923
|
+
if (!fs9.existsSync(prjPath)) {
|
|
23912
23924
|
throw new import_token_error.VercelOidcTokenError(
|
|
23913
23925
|
"project.json not found, have you linked your project with `vc link?`"
|
|
23914
23926
|
);
|
|
23915
23927
|
}
|
|
23916
|
-
const prj = JSON.parse(
|
|
23928
|
+
const prj = JSON.parse(fs9.readFileSync(prjPath, "utf8"));
|
|
23917
23929
|
if (typeof prj.projectId !== "string" && typeof prj.orgId !== "string") {
|
|
23918
23930
|
throw new TypeError(
|
|
23919
23931
|
"Expected a string-valued projectId property. Try running `vc link` to re-link your project."
|
|
@@ -23928,11 +23940,11 @@ var require_token_util = __commonJS({
|
|
|
23928
23940
|
"Unable to find user data directory. Please reach out to Vercel support."
|
|
23929
23941
|
);
|
|
23930
23942
|
}
|
|
23931
|
-
const tokenPath =
|
|
23943
|
+
const tokenPath = path13.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
23932
23944
|
const tokenJson = JSON.stringify(token);
|
|
23933
|
-
|
|
23934
|
-
|
|
23935
|
-
|
|
23945
|
+
fs9.mkdirSync(path13.dirname(tokenPath), { mode: 504, recursive: true });
|
|
23946
|
+
fs9.writeFileSync(tokenPath, tokenJson);
|
|
23947
|
+
fs9.chmodSync(tokenPath, 432);
|
|
23936
23948
|
return;
|
|
23937
23949
|
}
|
|
23938
23950
|
function loadToken(projectId) {
|
|
@@ -23942,11 +23954,11 @@ var require_token_util = __commonJS({
|
|
|
23942
23954
|
"Unable to find user data directory. Please reach out to Vercel support."
|
|
23943
23955
|
);
|
|
23944
23956
|
}
|
|
23945
|
-
const tokenPath =
|
|
23946
|
-
if (!
|
|
23957
|
+
const tokenPath = path13.join(dir, "com.vercel.token", `${projectId}.json`);
|
|
23958
|
+
if (!fs9.existsSync(tokenPath)) {
|
|
23947
23959
|
return null;
|
|
23948
23960
|
}
|
|
23949
|
-
const token = JSON.parse(
|
|
23961
|
+
const token = JSON.parse(fs9.readFileSync(tokenPath, "utf8"));
|
|
23950
23962
|
assertVercelOidcTokenResponse(token);
|
|
23951
23963
|
return token;
|
|
23952
23964
|
}
|
|
@@ -35972,7 +35984,7 @@ function createOpenRouter(options = {}) {
|
|
|
35972
35984
|
);
|
|
35973
35985
|
const createChatModel = (modelId, settings = {}) => new OpenRouterChatLanguageModel(modelId, settings, {
|
|
35974
35986
|
provider: "openrouter.chat",
|
|
35975
|
-
url: ({ path:
|
|
35987
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
35976
35988
|
headers: getHeaders,
|
|
35977
35989
|
compatibility,
|
|
35978
35990
|
fetch: options.fetch,
|
|
@@ -35980,7 +35992,7 @@ function createOpenRouter(options = {}) {
|
|
|
35980
35992
|
});
|
|
35981
35993
|
const createCompletionModel = (modelId, settings = {}) => new OpenRouterCompletionLanguageModel(modelId, settings, {
|
|
35982
35994
|
provider: "openrouter.completion",
|
|
35983
|
-
url: ({ path:
|
|
35995
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
35984
35996
|
headers: getHeaders,
|
|
35985
35997
|
compatibility,
|
|
35986
35998
|
fetch: options.fetch,
|
|
@@ -35988,21 +36000,21 @@ function createOpenRouter(options = {}) {
|
|
|
35988
36000
|
});
|
|
35989
36001
|
const createEmbeddingModel = (modelId, settings = {}) => new OpenRouterEmbeddingModel(modelId, settings, {
|
|
35990
36002
|
provider: "openrouter.embedding",
|
|
35991
|
-
url: ({ path:
|
|
36003
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
35992
36004
|
headers: getHeaders,
|
|
35993
36005
|
fetch: options.fetch,
|
|
35994
36006
|
extraBody: options.extraBody
|
|
35995
36007
|
});
|
|
35996
36008
|
const createImageModel = (modelId, settings = {}) => new OpenRouterImageModel(modelId, settings, {
|
|
35997
36009
|
provider: "openrouter.image",
|
|
35998
|
-
url: ({ path:
|
|
36010
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
35999
36011
|
headers: getHeaders,
|
|
36000
36012
|
fetch: options.fetch,
|
|
36001
36013
|
extraBody: options.extraBody
|
|
36002
36014
|
});
|
|
36003
36015
|
const createVideoModel = (modelId, settings = {}) => new OpenRouterVideoModel(modelId, settings, {
|
|
36004
36016
|
provider: "openrouter.video",
|
|
36005
|
-
url: ({ path:
|
|
36017
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
36006
36018
|
headers: getHeaders,
|
|
36007
36019
|
fetch: options.fetch,
|
|
36008
36020
|
extraBody: options.extraBody
|
|
@@ -40538,37 +40550,37 @@ function createOpenAI(options = {}) {
|
|
|
40538
40550
|
);
|
|
40539
40551
|
const createChatModel = (modelId) => new OpenAIChatLanguageModel(modelId, {
|
|
40540
40552
|
provider: `${providerName}.chat`,
|
|
40541
|
-
url: ({ path:
|
|
40553
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
40542
40554
|
headers: getHeaders,
|
|
40543
40555
|
fetch: options.fetch
|
|
40544
40556
|
});
|
|
40545
40557
|
const createCompletionModel = (modelId) => new OpenAICompletionLanguageModel(modelId, {
|
|
40546
40558
|
provider: `${providerName}.completion`,
|
|
40547
|
-
url: ({ path:
|
|
40559
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
40548
40560
|
headers: getHeaders,
|
|
40549
40561
|
fetch: options.fetch
|
|
40550
40562
|
});
|
|
40551
40563
|
const createEmbeddingModel = (modelId) => new OpenAIEmbeddingModel(modelId, {
|
|
40552
40564
|
provider: `${providerName}.embedding`,
|
|
40553
|
-
url: ({ path:
|
|
40565
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
40554
40566
|
headers: getHeaders,
|
|
40555
40567
|
fetch: options.fetch
|
|
40556
40568
|
});
|
|
40557
40569
|
const createImageModel = (modelId) => new OpenAIImageModel(modelId, {
|
|
40558
40570
|
provider: `${providerName}.image`,
|
|
40559
|
-
url: ({ path:
|
|
40571
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
40560
40572
|
headers: getHeaders,
|
|
40561
40573
|
fetch: options.fetch
|
|
40562
40574
|
});
|
|
40563
40575
|
const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
|
|
40564
40576
|
provider: `${providerName}.transcription`,
|
|
40565
|
-
url: ({ path:
|
|
40577
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
40566
40578
|
headers: getHeaders,
|
|
40567
40579
|
fetch: options.fetch
|
|
40568
40580
|
});
|
|
40569
40581
|
const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
|
|
40570
40582
|
provider: `${providerName}.speech`,
|
|
40571
|
-
url: ({ path:
|
|
40583
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
40572
40584
|
headers: getHeaders,
|
|
40573
40585
|
fetch: options.fetch
|
|
40574
40586
|
});
|
|
@@ -40583,7 +40595,7 @@ function createOpenAI(options = {}) {
|
|
|
40583
40595
|
const createResponsesModel = (modelId) => {
|
|
40584
40596
|
return new OpenAIResponsesLanguageModel(modelId, {
|
|
40585
40597
|
provider: `${providerName}.responses`,
|
|
40586
|
-
url: ({ path:
|
|
40598
|
+
url: ({ path: path13 }) => `${baseURL}${path13}`,
|
|
40587
40599
|
headers: getHeaders,
|
|
40588
40600
|
fetch: options.fetch,
|
|
40589
40601
|
fileIdPrefixes: ["file-"]
|
|
@@ -45808,6 +45820,9 @@ function resolveLanguageModel2(key) {
|
|
|
45808
45820
|
if (isOpenRouterDynamicKey(key)) {
|
|
45809
45821
|
return openrouter2(openRouterSlugFromKey(key));
|
|
45810
45822
|
}
|
|
45823
|
+
if (isNvidiaDynamicKey(key)) {
|
|
45824
|
+
return nvidia.chat(nvidiaSlugFromKey(key));
|
|
45825
|
+
}
|
|
45811
45826
|
return myProvider.languageModel(key);
|
|
45812
45827
|
}
|
|
45813
45828
|
async function listOpenRouterModels(signal) {
|
|
@@ -45833,7 +45848,25 @@ async function listOpenRouterModels(signal) {
|
|
|
45833
45848
|
};
|
|
45834
45849
|
}).filter((m) => m !== null).sort((a, b) => a.name.localeCompare(b.name));
|
|
45835
45850
|
}
|
|
45836
|
-
|
|
45851
|
+
async function listNvidiaModels(signal) {
|
|
45852
|
+
const key = process.env.NVIDIA_API_KEY?.trim();
|
|
45853
|
+
if (!key) throw new Error("NVIDIA_API_KEY n\xE3o configurada");
|
|
45854
|
+
const baseURL = process.env.NVIDIA_BASE_URL || "https://integrate.api.nvidia.com/v1";
|
|
45855
|
+
const res = await fetch(`${baseURL.replace(/\/$/, "")}/models`, {
|
|
45856
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
45857
|
+
signal
|
|
45858
|
+
});
|
|
45859
|
+
if (!res.ok) {
|
|
45860
|
+
throw new Error(`NVIDIA /models falhou: HTTP ${res.status}`);
|
|
45861
|
+
}
|
|
45862
|
+
const json3 = await res.json();
|
|
45863
|
+
const data = Array.isArray(json3.data) ? json3.data : [];
|
|
45864
|
+
return data.map((raw) => {
|
|
45865
|
+
if (!isRecord(raw) || typeof raw.id !== "string") return null;
|
|
45866
|
+
return { id: raw.id, name: raw.id };
|
|
45867
|
+
}).filter((m) => m !== null).sort((a, b) => a.id.localeCompare(b.id));
|
|
45868
|
+
}
|
|
45869
|
+
var isRecord, isXaiModelSlug, isGeminiModelSlug, requestCanRouteToXai, requestCanRouteToGemini, hasOwnEncryptedContent, stripEncryptedContent, sanitizeOpenRouterRequestForXai, hasJsonRefKey, wrapToolContentIfGeminiRefSensitive, sanitizeOpenRouterRequestForGeminiFunctionResponses, patchKimiReasoningToolCalls, OPENROUTER_METADATA_HEADER, withOpenRouterMetadataHeader, openrouterPatchFetch, openrouter2, openai2, isNvidiaMistralModel, applyNvidiaMistralConfig, nvidiaPatchFetch, nvidia, deepseek, kimi, buildProviderMap, hasEnvValue, isDeepSeekEnabled, isKimiEnabled, CLI_MODEL_CHAIN, baseProviders, modelCutoffDates, modelDisplayNames, getModelDisplayName, getModelCutoffDate, myProvider, OPENROUTER_KEY_PREFIX, hasOpenRouterKey, isOpenRouterDynamicKey, openRouterSlugFromKey, openRouterKeyForSlug, NVIDIA_KEY_PREFIX, hasNvidiaKey, isNvidiaDynamicKey, nvidiaSlugFromKey, nvidiaKeyForSlug;
|
|
45837
45870
|
var init_providers = __esm({
|
|
45838
45871
|
"../lib/ai/providers.ts"() {
|
|
45839
45872
|
"use strict";
|
|
@@ -46064,7 +46097,6 @@ var init_providers = __esm({
|
|
|
46064
46097
|
"model-nvidia-mistral-medium-3.5": nvidia.chat(
|
|
46065
46098
|
"mistralai/mistral-medium-3.5-128b"
|
|
46066
46099
|
),
|
|
46067
|
-
"model-nvidia-gpt-oss-120b": nvidia.chat("openai/gpt-oss-120b"),
|
|
46068
46100
|
"model-nvidia-glm-5.1": nvidia.chat("z-ai/glm-5.1"),
|
|
46069
46101
|
"model-nvidia-qwen3.5-397b": nvidia.chat("qwen/qwen3.5-397b-a17b"),
|
|
46070
46102
|
// Extra explicit keys for the CLI.
|
|
@@ -46102,8 +46134,6 @@ var init_providers = __esm({
|
|
|
46102
46134
|
...hasEnvValue("NVIDIA_API_KEY") ? [
|
|
46103
46135
|
"model-nvidia-mistral-medium-3.5",
|
|
46104
46136
|
// NVIDIA mistralai/mistral-medium-3.5-128b
|
|
46105
|
-
"model-nvidia-gpt-oss-120b",
|
|
46106
|
-
// NVIDIA openai/gpt-oss-120b
|
|
46107
46137
|
"model-nvidia-glm-5.1",
|
|
46108
46138
|
// NVIDIA z-ai/glm-5.1
|
|
46109
46139
|
"model-nvidia-qwen3.5-397b"
|
|
@@ -46129,7 +46159,6 @@ var init_providers = __esm({
|
|
|
46129
46159
|
"model-opus-4.6": "May 2025",
|
|
46130
46160
|
"model-kimi-k2.6": "April 2024",
|
|
46131
46161
|
"model-nvidia-mistral-medium-3.5": "Unknown",
|
|
46132
|
-
"model-nvidia-gpt-oss-120b": "June 2024",
|
|
46133
46162
|
"model-nvidia-glm-5.1": "Unknown",
|
|
46134
46163
|
"model-nvidia-qwen3.5-397b": "Unknown",
|
|
46135
46164
|
"model-deepseek-proxy": "July 2024",
|
|
@@ -46153,7 +46182,6 @@ var init_providers = __esm({
|
|
|
46153
46182
|
"model-opus-4.6": "Anthropic Claude Opus 4.6",
|
|
46154
46183
|
"model-kimi-k2.6": "Moonshot Kimi K2.6",
|
|
46155
46184
|
"model-nvidia-mistral-medium-3.5": "NVIDIA - Mistral Medium 3.5",
|
|
46156
|
-
"model-nvidia-gpt-oss-120b": "NVIDIA - OpenAI GPT-OSS 120B",
|
|
46157
46185
|
"model-nvidia-glm-5.1": "NVIDIA - Z.ai GLM 5.1",
|
|
46158
46186
|
"model-nvidia-qwen3.5-397b": "NVIDIA - Qwen3.5 397B A17B",
|
|
46159
46187
|
"model-deepseek-proxy": "DeepSeek (sessao web logada / deepsproxy)",
|
|
@@ -46180,6 +46208,11 @@ var init_providers = __esm({
|
|
|
46180
46208
|
isOpenRouterDynamicKey = (key) => key.startsWith(OPENROUTER_KEY_PREFIX);
|
|
46181
46209
|
openRouterSlugFromKey = (key) => key.slice(OPENROUTER_KEY_PREFIX.length);
|
|
46182
46210
|
openRouterKeyForSlug = (slug) => `${OPENROUTER_KEY_PREFIX}${slug}`;
|
|
46211
|
+
NVIDIA_KEY_PREFIX = "nvidia:";
|
|
46212
|
+
hasNvidiaKey = () => Boolean(process.env.NVIDIA_API_KEY?.trim());
|
|
46213
|
+
isNvidiaDynamicKey = (key) => key.startsWith(NVIDIA_KEY_PREFIX);
|
|
46214
|
+
nvidiaSlugFromKey = (key) => key.slice(NVIDIA_KEY_PREFIX.length);
|
|
46215
|
+
nvidiaKeyForSlug = (slug) => `${NVIDIA_KEY_PREFIX}${slug}`;
|
|
46183
46216
|
}
|
|
46184
46217
|
});
|
|
46185
46218
|
|
|
@@ -49192,8 +49225,8 @@ var init_background_process_tracker = __esm({
|
|
|
49192
49225
|
/**
|
|
49193
49226
|
* Normalize file path for comparison
|
|
49194
49227
|
*/
|
|
49195
|
-
normalizePath(
|
|
49196
|
-
let normalized =
|
|
49228
|
+
normalizePath(path13) {
|
|
49229
|
+
let normalized = path13.trim().replace(/\/+/g, "/");
|
|
49197
49230
|
if (normalized.startsWith("./")) {
|
|
49198
49231
|
normalized = normalized.slice(2);
|
|
49199
49232
|
}
|
|
@@ -49431,8 +49464,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
49431
49464
|
return decodedFile;
|
|
49432
49465
|
};
|
|
49433
49466
|
}
|
|
49434
|
-
function normalizeWindowsPath(
|
|
49435
|
-
return
|
|
49467
|
+
function normalizeWindowsPath(path13) {
|
|
49468
|
+
return path13.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
49436
49469
|
}
|
|
49437
49470
|
var import_path;
|
|
49438
49471
|
var init_module_node = __esm({
|
|
@@ -52321,9 +52354,9 @@ async function addSourceContext(frames) {
|
|
|
52321
52354
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
52322
52355
|
return frames;
|
|
52323
52356
|
}
|
|
52324
|
-
function getContextLinesFromFile(
|
|
52357
|
+
function getContextLinesFromFile(path13, ranges, output) {
|
|
52325
52358
|
return new Promise((resolve2) => {
|
|
52326
|
-
const stream = (0, import_node_fs5.createReadStream)(
|
|
52359
|
+
const stream = (0, import_node_fs5.createReadStream)(path13);
|
|
52327
52360
|
const lineReaded = (0, import_node_readline2.createInterface)({
|
|
52328
52361
|
input: stream
|
|
52329
52362
|
});
|
|
@@ -52338,7 +52371,7 @@ function getContextLinesFromFile(path12, ranges, output) {
|
|
|
52338
52371
|
let rangeStart = range[0];
|
|
52339
52372
|
let rangeEnd = range[1];
|
|
52340
52373
|
function onStreamError() {
|
|
52341
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
52374
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path13, 1);
|
|
52342
52375
|
lineReaded.close();
|
|
52343
52376
|
lineReaded.removeAllListeners();
|
|
52344
52377
|
destroyStreamAndResolve();
|
|
@@ -52399,8 +52432,8 @@ function clearLineContext(frame3) {
|
|
|
52399
52432
|
delete frame3.context_line;
|
|
52400
52433
|
delete frame3.post_context;
|
|
52401
52434
|
}
|
|
52402
|
-
function shouldSkipContextLinesForFile(
|
|
52403
|
-
return
|
|
52435
|
+
function shouldSkipContextLinesForFile(path13) {
|
|
52436
|
+
return path13.startsWith("node:") || path13.endsWith(".min.js") || path13.endsWith(".min.cjs") || path13.endsWith(".min.mjs") || path13.startsWith("data:");
|
|
52404
52437
|
}
|
|
52405
52438
|
function shouldSkipContextLinesForFrame(frame3) {
|
|
52406
52439
|
if (void 0 !== frame3.lineno && frame3.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -67810,8 +67843,8 @@ var init_logger2 = __esm({
|
|
|
67810
67843
|
});
|
|
67811
67844
|
|
|
67812
67845
|
// ../lib/ai/tools/file.ts
|
|
67813
|
-
function isSpritPath(
|
|
67814
|
-
return
|
|
67846
|
+
function isSpritPath(path13) {
|
|
67847
|
+
return path13.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
|
|
67815
67848
|
}
|
|
67816
67849
|
function getViewSandboxType(sandbox) {
|
|
67817
67850
|
return isCentrifugoSandbox(sandbox) ? "centrifugo" : "e2b";
|
|
@@ -67842,7 +67875,7 @@ function captureFileViewImageUsage(args) {
|
|
|
67842
67875
|
const {
|
|
67843
67876
|
context: context2,
|
|
67844
67877
|
sandbox,
|
|
67845
|
-
path:
|
|
67878
|
+
path: path13,
|
|
67846
67879
|
outcome,
|
|
67847
67880
|
durationMs,
|
|
67848
67881
|
mediaType,
|
|
@@ -67860,7 +67893,7 @@ function captureFileViewImageUsage(args) {
|
|
|
67860
67893
|
model: getActiveModelName(context2),
|
|
67861
67894
|
configured_model: context2.modelName,
|
|
67862
67895
|
sandbox_type: getViewSandboxType(sandbox),
|
|
67863
|
-
file_extension: getFileExtension(
|
|
67896
|
+
file_extension: getFileExtension(path13),
|
|
67864
67897
|
outcome,
|
|
67865
67898
|
success: outcome === "success",
|
|
67866
67899
|
duration_ms: durationMs,
|
|
@@ -67934,22 +67967,22 @@ async function runSandboxCommand(sandbox, command, envVars, timeoutMs = 6e4) {
|
|
|
67934
67967
|
function isWindowsSandbox(sandbox) {
|
|
67935
67968
|
return isCentrifugoSandbox(sandbox) && sandbox.isWindows();
|
|
67936
67969
|
}
|
|
67937
|
-
function getWindowsNativePath(
|
|
67938
|
-
if (/^[A-Za-z]:[\\/]/.test(
|
|
67939
|
-
if (
|
|
67940
|
-
return `C:\\temp${
|
|
67970
|
+
function getWindowsNativePath(path13) {
|
|
67971
|
+
if (/^[A-Za-z]:[\\/]/.test(path13)) return path13;
|
|
67972
|
+
if (path13.startsWith("/tmp/")) {
|
|
67973
|
+
return `C:\\temp${path13.slice(4).replace(/\//g, "\\")}`;
|
|
67941
67974
|
}
|
|
67942
|
-
return
|
|
67975
|
+
return path13.replace(/\//g, "\\");
|
|
67943
67976
|
}
|
|
67944
|
-
function getPythonPathForSandbox(sandbox,
|
|
67945
|
-
return isWindowsSandbox(sandbox) ? getWindowsNativePath(
|
|
67977
|
+
function getPythonPathForSandbox(sandbox, path13) {
|
|
67978
|
+
return isWindowsSandbox(sandbox) ? getWindowsNativePath(path13) : path13;
|
|
67946
67979
|
}
|
|
67947
|
-
function toWindowsBashPath(
|
|
67948
|
-
const drive =
|
|
67980
|
+
function toWindowsBashPath(path13) {
|
|
67981
|
+
const drive = path13.match(/^([A-Za-z]):[\\/](.*)$/);
|
|
67949
67982
|
if (drive) {
|
|
67950
67983
|
return `/${drive[1].toLowerCase()}/${drive[2].replace(/\\/g, "/")}`;
|
|
67951
67984
|
}
|
|
67952
|
-
return
|
|
67985
|
+
return path13.replace(/\\/g, "/");
|
|
67953
67986
|
}
|
|
67954
67987
|
async function detectSandboxShell(sandbox) {
|
|
67955
67988
|
if (!isWindowsSandbox(sandbox)) return "bash";
|
|
@@ -67988,8 +68021,8 @@ PY`;
|
|
|
67988
68021
|
}
|
|
67989
68022
|
}
|
|
67990
68023
|
}
|
|
67991
|
-
async function getSandboxFileState(sandbox,
|
|
67992
|
-
const pythonPath = getPythonPathForSandbox(sandbox,
|
|
68024
|
+
async function getSandboxFileState(sandbox, path13) {
|
|
68025
|
+
const pythonPath = getPythonPathForSandbox(sandbox, path13);
|
|
67993
68026
|
const result = await runPythonScript(
|
|
67994
68027
|
sandbox,
|
|
67995
68028
|
FILE_STATE_SCRIPT,
|
|
@@ -68006,23 +68039,23 @@ async function getSandboxFileState(sandbox, path12) {
|
|
|
68006
68039
|
if (result.exitCode !== 0) {
|
|
68007
68040
|
return {
|
|
68008
68041
|
kind: "unknown",
|
|
68009
|
-
path:
|
|
68042
|
+
path: path13,
|
|
68010
68043
|
error: result.stderr || result.stdout || "file state command failed"
|
|
68011
68044
|
};
|
|
68012
68045
|
}
|
|
68013
68046
|
try {
|
|
68014
68047
|
const payload = JSON.parse(result.stdout.trim());
|
|
68015
68048
|
if (payload.kind === "file" && typeof payload.sizeBytes === "number" && Number.isFinite(payload.sizeBytes)) {
|
|
68016
|
-
return { ...payload, path:
|
|
68049
|
+
return { ...payload, path: path13 };
|
|
68017
68050
|
}
|
|
68018
68051
|
if (payload.kind === "missing" || payload.kind === "not_file") {
|
|
68019
|
-
return { ...payload, path:
|
|
68052
|
+
return { ...payload, path: path13 };
|
|
68020
68053
|
}
|
|
68021
68054
|
} catch {
|
|
68022
68055
|
}
|
|
68023
68056
|
return {
|
|
68024
68057
|
kind: "unknown",
|
|
68025
|
-
path:
|
|
68058
|
+
path: path13,
|
|
68026
68059
|
error: result.stderr || result.stdout || "invalid file state response"
|
|
68027
68060
|
};
|
|
68028
68061
|
}
|
|
@@ -68054,8 +68087,8 @@ ${numberedContent}${truncatedNotice}${footerNotice}`;
|
|
|
68054
68087
|
})
|
|
68055
68088
|
};
|
|
68056
68089
|
}
|
|
68057
|
-
async function readSandboxTextFile(sandbox,
|
|
68058
|
-
const pythonPath = getPythonPathForSandbox(sandbox,
|
|
68090
|
+
async function readSandboxTextFile(sandbox, path13, range) {
|
|
68091
|
+
const pythonPath = getPythonPathForSandbox(sandbox, path13);
|
|
68059
68092
|
const envVars = {
|
|
68060
68093
|
clawfast_FILE_READ_PATH: pythonPath,
|
|
68061
68094
|
clawfast_FILE_READ_RANGE_START: String(range?.[0] ?? 0),
|
|
@@ -68083,40 +68116,40 @@ async function readSandboxTextFile(sandbox, path12, range) {
|
|
|
68083
68116
|
}
|
|
68084
68117
|
return payload;
|
|
68085
68118
|
}
|
|
68086
|
-
async function readSandboxTextFileWithFallback(sandbox,
|
|
68119
|
+
async function readSandboxTextFileWithFallback(sandbox, path13, range) {
|
|
68087
68120
|
try {
|
|
68088
|
-
return await readSandboxTextFile(sandbox,
|
|
68121
|
+
return await readSandboxTextFile(sandbox, path13, range);
|
|
68089
68122
|
} catch (error51) {
|
|
68090
68123
|
const errorMessage = error51 instanceof Error ? error51.message : String(error51);
|
|
68091
68124
|
if (errorMessage.startsWith("Invalid ") || errorMessage.includes("File not found")) {
|
|
68092
68125
|
throw error51;
|
|
68093
68126
|
}
|
|
68094
|
-
const state = await getSandboxFileState(sandbox,
|
|
68127
|
+
const state = await getSandboxFileState(sandbox, path13);
|
|
68095
68128
|
if (state.kind === "unknown") {
|
|
68096
68129
|
throw new Error(
|
|
68097
|
-
`Unable to determine file size for ${
|
|
68130
|
+
`Unable to determine file size for ${path13}; refusing to load the file into memory. ${state.error}`
|
|
68098
68131
|
);
|
|
68099
68132
|
}
|
|
68100
68133
|
if (state.kind === "missing") {
|
|
68101
|
-
throw new Error(`File not found or is not a regular file: ${
|
|
68134
|
+
throw new Error(`File not found or is not a regular file: ${path13}`);
|
|
68102
68135
|
}
|
|
68103
68136
|
if (state.kind === "not_file") {
|
|
68104
|
-
throw new Error(`File is not a regular file: ${
|
|
68137
|
+
throw new Error(`File is not a regular file: ${path13}`);
|
|
68105
68138
|
}
|
|
68106
68139
|
if (state.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
|
|
68107
68140
|
if (range) {
|
|
68108
68141
|
throw new Error(
|
|
68109
|
-
`Unable to perform a bounded range read for ${
|
|
68142
|
+
`Unable to perform a bounded range read for ${path13}, 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.`
|
|
68110
68143
|
);
|
|
68111
68144
|
}
|
|
68112
68145
|
return {
|
|
68113
|
-
path:
|
|
68146
|
+
path: path13,
|
|
68114
68147
|
sizeBytes: state.sizeBytes,
|
|
68115
68148
|
totalLines: 0,
|
|
68116
68149
|
tooLarge: true
|
|
68117
68150
|
};
|
|
68118
68151
|
}
|
|
68119
|
-
const fileContent = await sandbox.files.read(
|
|
68152
|
+
const fileContent = await sandbox.files.read(path13, {
|
|
68120
68153
|
user: "user"
|
|
68121
68154
|
});
|
|
68122
68155
|
const lines = fileContent.split("\n");
|
|
@@ -68140,7 +68173,7 @@ async function readSandboxTextFileWithFallback(sandbox, path12, range) {
|
|
|
68140
68173
|
const startIndex = start - 1;
|
|
68141
68174
|
const endIndex = end === -1 ? lines.length : end;
|
|
68142
68175
|
return {
|
|
68143
|
-
path:
|
|
68176
|
+
path: path13,
|
|
68144
68177
|
sizeBytes: Buffer.byteLength(fileContent),
|
|
68145
68178
|
totalLines: lines.length,
|
|
68146
68179
|
content: lines.slice(startIndex, endIndex).join("\n"),
|
|
@@ -68148,7 +68181,7 @@ async function readSandboxTextFileWithFallback(sandbox, path12, range) {
|
|
|
68148
68181
|
};
|
|
68149
68182
|
}
|
|
68150
68183
|
return {
|
|
68151
|
-
path:
|
|
68184
|
+
path: path13,
|
|
68152
68185
|
sizeBytes: Buffer.byteLength(fileContent),
|
|
68153
68186
|
totalLines: lines.length,
|
|
68154
68187
|
content: fileContent,
|
|
@@ -68156,7 +68189,7 @@ async function readSandboxTextFileWithFallback(sandbox, path12, range) {
|
|
|
68156
68189
|
};
|
|
68157
68190
|
}
|
|
68158
68191
|
}
|
|
68159
|
-
async function appendSandboxTextFile(sandbox,
|
|
68192
|
+
async function appendSandboxTextFile(sandbox, path13, text2) {
|
|
68160
68193
|
const tempPath = `/tmp/clawfast_append_${Date.now()}_${Math.random().toString(36).slice(2)}.tmp`;
|
|
68161
68194
|
await sandbox.files.write(tempPath, text2, {
|
|
68162
68195
|
user: "user"
|
|
@@ -68165,7 +68198,7 @@ async function appendSandboxTextFile(sandbox, path12, text2) {
|
|
|
68165
68198
|
sandbox,
|
|
68166
68199
|
APPEND_TEXT_FILE_SCRIPT,
|
|
68167
68200
|
{
|
|
68168
|
-
clawfast_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox,
|
|
68201
|
+
clawfast_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path13),
|
|
68169
68202
|
clawfast_FILE_APPEND_SOURCE_PATH: getPythonPathForSandbox(
|
|
68170
68203
|
sandbox,
|
|
68171
68204
|
tempPath
|
|
@@ -68177,13 +68210,13 @@ async function appendSandboxTextFile(sandbox, path12, text2) {
|
|
|
68177
68210
|
throw new Error(result.stderr || result.stdout || "Failed to append file");
|
|
68178
68211
|
}
|
|
68179
68212
|
}
|
|
68180
|
-
async function readSandboxFileForView(sandbox,
|
|
68213
|
+
async function readSandboxFileForView(sandbox, path13, includeData) {
|
|
68181
68214
|
if (isCentrifugoSandbox(sandbox) && sandbox.isWindows()) {
|
|
68182
68215
|
throw new Error(
|
|
68183
68216
|
"The view action is not available for Windows local sandboxes yet. Use a Linux/E2B sandbox or inspect the image manually."
|
|
68184
68217
|
);
|
|
68185
68218
|
}
|
|
68186
|
-
const sandboxPath = getSandboxViewPath(sandbox,
|
|
68219
|
+
const sandboxPath = getSandboxViewPath(sandbox, path13);
|
|
68187
68220
|
const viewEnvVars = {
|
|
68188
68221
|
clawfast_FILE_VIEW_PATH: sandboxPath,
|
|
68189
68222
|
clawfast_FILE_VIEW_INCLUDE_DATA: includeData ? "1" : "0",
|
|
@@ -68527,19 +68560,19 @@ try:
|
|
|
68527
68560
|
except OSError:
|
|
68528
68561
|
pass
|
|
68529
68562
|
`;
|
|
68530
|
-
getFilename = (
|
|
68531
|
-
getFileExtension = (
|
|
68532
|
-
const filename = getFilename(
|
|
68563
|
+
getFilename = (path13) => path13.split("/").pop() || path13;
|
|
68564
|
+
getFileExtension = (path13) => {
|
|
68565
|
+
const filename = getFilename(path13);
|
|
68533
68566
|
const dotIndex = filename.lastIndexOf(".");
|
|
68534
68567
|
if (dotIndex <= 0 || dotIndex === filename.length - 1) return void 0;
|
|
68535
68568
|
return filename.slice(dotIndex + 1).toLowerCase();
|
|
68536
68569
|
};
|
|
68537
|
-
getSandboxViewPath = (sandbox,
|
|
68570
|
+
getSandboxViewPath = (sandbox, path13) => {
|
|
68538
68571
|
const maybeSandbox = sandbox;
|
|
68539
|
-
if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() &&
|
|
68540
|
-
return `C:\\temp${
|
|
68572
|
+
if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path13.startsWith("/tmp/")) {
|
|
68573
|
+
return `C:\\temp${path13.slice(4).replace(/\//g, "\\")}`;
|
|
68541
68574
|
}
|
|
68542
|
-
return
|
|
68575
|
+
return path13;
|
|
68543
68576
|
};
|
|
68544
68577
|
stripTrailingWs = (line) => line.replace(/[ \t]+$/u, "");
|
|
68545
68578
|
editSchema = external_exports.object({
|
|
@@ -68613,7 +68646,7 @@ ${instructionsDescription}`,
|
|
|
68613
68646
|
"A list of edits to be sequentially applied to the file. Required for `edit` action."
|
|
68614
68647
|
)
|
|
68615
68648
|
}),
|
|
68616
|
-
execute: async ({ action, path:
|
|
68649
|
+
execute: async ({ action, path: path13, text: text2, range, edits }) => {
|
|
68617
68650
|
try {
|
|
68618
68651
|
const { sandbox } = await sandboxManager.getSandbox();
|
|
68619
68652
|
switch (action) {
|
|
@@ -68623,7 +68656,7 @@ ${instructionsDescription}`,
|
|
|
68623
68656
|
captureFileViewImageUsage({
|
|
68624
68657
|
context: context2,
|
|
68625
68658
|
sandbox,
|
|
68626
|
-
path:
|
|
68659
|
+
path: path13,
|
|
68627
68660
|
outcome: "unsupported_model",
|
|
68628
68661
|
durationMs: Date.now() - viewStartedAt,
|
|
68629
68662
|
failureReason: "unsupported_model"
|
|
@@ -68632,26 +68665,26 @@ ${instructionsDescription}`,
|
|
|
68632
68665
|
}
|
|
68633
68666
|
let viewPayload;
|
|
68634
68667
|
try {
|
|
68635
|
-
viewPayload = await readSandboxFileForView(sandbox,
|
|
68668
|
+
viewPayload = await readSandboxFileForView(sandbox, path13, false);
|
|
68636
68669
|
} catch (error51) {
|
|
68637
68670
|
captureFileViewImageUsage({
|
|
68638
68671
|
context: context2,
|
|
68639
68672
|
sandbox,
|
|
68640
|
-
path:
|
|
68673
|
+
path: path13,
|
|
68641
68674
|
outcome: "inspection_failed",
|
|
68642
68675
|
durationMs: Date.now() - viewStartedAt,
|
|
68643
68676
|
failureReason: classifyFileViewError(error51)
|
|
68644
68677
|
});
|
|
68645
68678
|
throw error51;
|
|
68646
68679
|
}
|
|
68647
|
-
const filename = getFilename(
|
|
68680
|
+
const filename = getFilename(path13);
|
|
68648
68681
|
let previewFiles = [];
|
|
68649
68682
|
let previewUploadError;
|
|
68650
68683
|
try {
|
|
68651
68684
|
previewFiles = await uploadViewPreviewFiles({
|
|
68652
68685
|
context: context2,
|
|
68653
68686
|
sandbox,
|
|
68654
|
-
sourcePath:
|
|
68687
|
+
sourcePath: path13,
|
|
68655
68688
|
payload: viewPayload
|
|
68656
68689
|
});
|
|
68657
68690
|
} catch (error51) {
|
|
@@ -68665,7 +68698,7 @@ ${instructionsDescription}`,
|
|
|
68665
68698
|
user_id: context2.userID,
|
|
68666
68699
|
sandbox_type: getViewSandboxType(sandbox),
|
|
68667
68700
|
file_name: filename,
|
|
68668
|
-
source_path:
|
|
68701
|
+
source_path: path13,
|
|
68669
68702
|
kind: viewPayload.kind,
|
|
68670
68703
|
media_type: viewPayload.mediaType,
|
|
68671
68704
|
size_bytes: viewPayload.sizeBytes,
|
|
@@ -68676,7 +68709,7 @@ ${instructionsDescription}`,
|
|
|
68676
68709
|
captureFileViewImageUsage({
|
|
68677
68710
|
context: context2,
|
|
68678
68711
|
sandbox,
|
|
68679
|
-
path:
|
|
68712
|
+
path: path13,
|
|
68680
68713
|
outcome: "success",
|
|
68681
68714
|
durationMs: Date.now() - viewStartedAt,
|
|
68682
68715
|
mediaType: viewPayload.mediaType,
|
|
@@ -68686,7 +68719,7 @@ ${instructionsDescription}`,
|
|
|
68686
68719
|
return {
|
|
68687
68720
|
action: "view",
|
|
68688
68721
|
content: `Viewing image file: ${filename} (${viewPayload.mediaType}, ${viewPayload.sizeBytes} bytes).`,
|
|
68689
|
-
path:
|
|
68722
|
+
path: path13,
|
|
68690
68723
|
filename,
|
|
68691
68724
|
mediaType: viewPayload.mediaType,
|
|
68692
68725
|
sizeBytes: viewPayload.sizeBytes,
|
|
@@ -68696,8 +68729,8 @@ ${instructionsDescription}`,
|
|
|
68696
68729
|
};
|
|
68697
68730
|
}
|
|
68698
68731
|
case "read": {
|
|
68699
|
-
const filename =
|
|
68700
|
-
const spritChunked = isSpritPath(
|
|
68732
|
+
const filename = path13.split("/").pop() || path13;
|
|
68733
|
+
const spritChunked = isSpritPath(path13);
|
|
68701
68734
|
let effectiveRange = range;
|
|
68702
68735
|
if (spritChunked) {
|
|
68703
68736
|
const start = range && range[0] > 0 ? range[0] : 1;
|
|
@@ -68710,7 +68743,7 @@ ${instructionsDescription}`,
|
|
|
68710
68743
|
}
|
|
68711
68744
|
const readPayload = await readSandboxTextFileWithFallback(
|
|
68712
68745
|
sandbox,
|
|
68713
|
-
|
|
68746
|
+
path13,
|
|
68714
68747
|
effectiveRange
|
|
68715
68748
|
);
|
|
68716
68749
|
if (readPayload.tooLarge) {
|
|
@@ -68747,46 +68780,46 @@ File is too large to read in full (${formatBytes(readPayload.sizeBytes)}, ${tota
|
|
|
68747
68780
|
if (text2 === void 0) {
|
|
68748
68781
|
return { error: "text is required for write action" };
|
|
68749
68782
|
}
|
|
68750
|
-
await sandbox.files.write(
|
|
68783
|
+
await sandbox.files.write(path13, text2, {
|
|
68751
68784
|
user: "user"
|
|
68752
68785
|
});
|
|
68753
|
-
return `File written: ${
|
|
68786
|
+
return `File written: ${path13}`;
|
|
68754
68787
|
}
|
|
68755
68788
|
case "append": {
|
|
68756
68789
|
if (text2 === void 0) {
|
|
68757
68790
|
return { error: "text is required for append action" };
|
|
68758
68791
|
}
|
|
68759
|
-
const existingState = await getSandboxFileState(sandbox,
|
|
68792
|
+
const existingState = await getSandboxFileState(sandbox, path13);
|
|
68760
68793
|
if (existingState.kind === "unknown") {
|
|
68761
68794
|
return {
|
|
68762
|
-
error: `Cannot append safely because the existing file size could not be determined for ${
|
|
68795
|
+
error: `Cannot append safely because the existing file size could not be determined for ${path13}. ${existingState.error}`
|
|
68763
68796
|
};
|
|
68764
68797
|
}
|
|
68765
68798
|
if (existingState.kind === "not_file") {
|
|
68766
68799
|
return {
|
|
68767
|
-
error: `Cannot append to ${
|
|
68800
|
+
error: `Cannot append to ${path13} because it is not a file.`
|
|
68768
68801
|
};
|
|
68769
68802
|
}
|
|
68770
68803
|
if (existingState.kind === "file" && existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
|
|
68771
|
-
await appendSandboxTextFile(sandbox,
|
|
68804
|
+
await appendSandboxTextFile(sandbox, path13, text2);
|
|
68772
68805
|
return {
|
|
68773
|
-
content: `File appended: ${
|
|
68806
|
+
content: `File appended: ${path13}
|
|
68774
68807
|
Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff preview was skipped to avoid loading the entire file into memory.`
|
|
68775
68808
|
};
|
|
68776
68809
|
}
|
|
68777
68810
|
let existingContent = "";
|
|
68778
68811
|
try {
|
|
68779
|
-
existingContent = await sandbox.files.read(
|
|
68812
|
+
existingContent = await sandbox.files.read(path13, {
|
|
68780
68813
|
user: "user"
|
|
68781
68814
|
});
|
|
68782
68815
|
} catch {
|
|
68783
68816
|
}
|
|
68784
68817
|
const newContent = existingContent + text2;
|
|
68785
|
-
await sandbox.files.write(
|
|
68818
|
+
await sandbox.files.write(path13, newContent, {
|
|
68786
68819
|
user: "user"
|
|
68787
68820
|
});
|
|
68788
68821
|
return {
|
|
68789
|
-
content: `File appended: ${
|
|
68822
|
+
content: `File appended: ${path13}`,
|
|
68790
68823
|
originalContent: truncateOutput({
|
|
68791
68824
|
content: existingContent,
|
|
68792
68825
|
mode: "read-file"
|
|
@@ -68801,31 +68834,31 @@ Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff previ
|
|
|
68801
68834
|
if (!edits || edits.length === 0) {
|
|
68802
68835
|
return { error: "edits array is required for edit action" };
|
|
68803
68836
|
}
|
|
68804
|
-
const existingState = await getSandboxFileState(sandbox,
|
|
68837
|
+
const existingState = await getSandboxFileState(sandbox, path13);
|
|
68805
68838
|
if (existingState.kind === "unknown") {
|
|
68806
68839
|
return {
|
|
68807
|
-
error: `Cannot edit ${
|
|
68840
|
+
error: `Cannot edit ${path13} safely because the file size could not be determined. ${existingState.error}`
|
|
68808
68841
|
};
|
|
68809
68842
|
}
|
|
68810
68843
|
if (existingState.kind === "missing") {
|
|
68811
68844
|
return {
|
|
68812
|
-
error: `Cannot edit file ${
|
|
68845
|
+
error: `Cannot edit file ${path13} - file is empty or does not exist`
|
|
68813
68846
|
};
|
|
68814
68847
|
}
|
|
68815
68848
|
if (existingState.kind === "not_file") {
|
|
68816
|
-
return { error: `Cannot edit ${
|
|
68849
|
+
return { error: `Cannot edit ${path13} because it is not a file.` };
|
|
68817
68850
|
}
|
|
68818
68851
|
if (existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
|
|
68819
68852
|
return {
|
|
68820
|
-
error: `File ${
|
|
68853
|
+
error: `File ${path13} 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.`
|
|
68821
68854
|
};
|
|
68822
68855
|
}
|
|
68823
|
-
const originalContent = await sandbox.files.read(
|
|
68856
|
+
const originalContent = await sandbox.files.read(path13, {
|
|
68824
68857
|
user: "user"
|
|
68825
68858
|
});
|
|
68826
68859
|
if (!originalContent) {
|
|
68827
68860
|
return {
|
|
68828
|
-
error: `Cannot edit file ${
|
|
68861
|
+
error: `Cannot edit file ${path13} - file is empty or does not exist`
|
|
68829
68862
|
};
|
|
68830
68863
|
}
|
|
68831
68864
|
const resolvedEdits = [];
|
|
@@ -68870,7 +68903,7 @@ ${hint}` : "")
|
|
|
68870
68903
|
}
|
|
68871
68904
|
}
|
|
68872
68905
|
}
|
|
68873
|
-
await sandbox.files.write(
|
|
68906
|
+
await sandbox.files.write(path13, content, {
|
|
68874
68907
|
user: "user"
|
|
68875
68908
|
});
|
|
68876
68909
|
const lines = content.split("\n");
|
|
@@ -68962,419 +68995,483 @@ ${numberedLines}`,
|
|
|
68962
68995
|
}
|
|
68963
68996
|
});
|
|
68964
68997
|
|
|
68965
|
-
//
|
|
68966
|
-
|
|
68967
|
-
|
|
68968
|
-
|
|
68969
|
-
|
|
68970
|
-
|
|
68971
|
-
SENSITIVE_FIELD_PATTERN = /(["']?\b(?:serviceKey|service_key|apiKey|api_key|authorization|bearer|cookie|password|secret|token)\b["']?)(\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,}]+)/gi;
|
|
68972
|
-
ENV_SECRET_PATTERN = /(["']?\b(?:CONVEX_SERVICE_ROLE_KEY|POSTHOG_API_KEY|STRIPE_SECRET_KEY)\b["']?)(\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,}]+)/gi;
|
|
68973
|
-
redactSensitiveErrorMessage = (message) => message.replace(SENSITIVE_FIELD_PATTERN, (_match, key, separator) => {
|
|
68974
|
-
return `${key}${separator}"${REDACTED_VALUE}"`;
|
|
68975
|
-
}).replace(ENV_SECRET_PATTERN, (_match, key, separator) => {
|
|
68976
|
-
return `${key}${separator}"${REDACTED_VALUE}"`;
|
|
68977
|
-
});
|
|
68978
|
-
stringifyRedactedError = (error51) => {
|
|
68979
|
-
const message = error51 instanceof Error ? error51.message : typeof error51 === "string" ? error51 : (() => {
|
|
68998
|
+
// src/tools/web-research.ts
|
|
68999
|
+
function decodeHtmlEntities(input) {
|
|
69000
|
+
return input.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (whole, code) => {
|
|
69001
|
+
if (code[0] === "#") {
|
|
69002
|
+
const num = code[1] === "x" || code[1] === "X" ? Number.parseInt(code.slice(2), 16) : Number.parseInt(code.slice(1), 10);
|
|
69003
|
+
if (Number.isFinite(num) && num > 0 && num <= 1114111) {
|
|
68980
69004
|
try {
|
|
68981
|
-
return
|
|
69005
|
+
return String.fromCodePoint(num);
|
|
68982
69006
|
} catch {
|
|
68983
|
-
return
|
|
69007
|
+
return whole;
|
|
68984
69008
|
}
|
|
68985
|
-
})();
|
|
68986
|
-
return redactSensitiveErrorMessage(message);
|
|
68987
|
-
};
|
|
68988
|
-
}
|
|
68989
|
-
});
|
|
68990
|
-
|
|
68991
|
-
// ../lib/ai/tools/utils/perplexity.ts
|
|
68992
|
-
var SEARCH_RESULT_CONTENT_MAX_TOKENS, RECENCY_MAP, PerplexityApiError, ERROR_BODY_SUMMARY_MAX_LENGTH, RETRYABLE_PERPLEXITY_STATUSES, HTML_ENTITY_MAP, normalizeWhitespace, decodeBasicHtmlEntities, stripHtml, extractHtmlTagText, redactNetworkDetails, truncateSummary, isRetryablePerplexityStatus, summarizePerplexityErrorBody, buildPerplexitySearchBody, formatSearchResults;
|
|
68993
|
-
var init_perplexity = __esm({
|
|
68994
|
-
"../lib/ai/tools/utils/perplexity.ts"() {
|
|
68995
|
-
"use strict";
|
|
68996
|
-
SEARCH_RESULT_CONTENT_MAX_TOKENS = 250;
|
|
68997
|
-
RECENCY_MAP = {
|
|
68998
|
-
past_day: "day",
|
|
68999
|
-
past_week: "week",
|
|
69000
|
-
past_month: "month",
|
|
69001
|
-
past_year: "year"
|
|
69002
|
-
};
|
|
69003
|
-
PerplexityApiError = class extends Error {
|
|
69004
|
-
constructor({
|
|
69005
|
-
status,
|
|
69006
|
-
statusText,
|
|
69007
|
-
bodySummary,
|
|
69008
|
-
retryable
|
|
69009
|
-
}) {
|
|
69010
|
-
const statusLabel = statusText ? `${status} ${statusText}` : `${status}`;
|
|
69011
|
-
const summary = bodySummary ? `: ${bodySummary}` : "";
|
|
69012
|
-
super(`Perplexity API error ${statusLabel}${summary}`);
|
|
69013
|
-
this.name = "PerplexityApiError";
|
|
69014
|
-
this.status = status;
|
|
69015
|
-
this.statusText = statusText;
|
|
69016
|
-
this.bodySummary = bodySummary;
|
|
69017
|
-
this.retryable = retryable;
|
|
69018
69009
|
}
|
|
69010
|
+
return whole;
|
|
69011
|
+
}
|
|
69012
|
+
return NAMED_ENTITIES[code] != null ? NAMED_ENTITIES[code] : whole;
|
|
69013
|
+
});
|
|
69014
|
+
}
|
|
69015
|
+
function htmlToText(html) {
|
|
69016
|
+
let s = html;
|
|
69017
|
+
s = s.replace(/<!--[\s\S]*?-->/g, " ");
|
|
69018
|
+
s = s.replace(/<(script|style|noscript|svg|head|template)[\s\S]*?<\/\1>/gi, " ");
|
|
69019
|
+
s = s.replace(
|
|
69020
|
+
/<\/(p|div|section|article|header|footer|li|ul|ol|tr|table|h[1-6]|blockquote|pre|nav|aside)>/gi,
|
|
69021
|
+
"\n"
|
|
69022
|
+
);
|
|
69023
|
+
s = s.replace(/<br\s*\/?>/gi, "\n");
|
|
69024
|
+
s = s.replace(/<[^>]+>/g, " ");
|
|
69025
|
+
s = decodeHtmlEntities(s);
|
|
69026
|
+
s = s.replace(/[ \t\f\v\r]+/g, " ");
|
|
69027
|
+
s = s.replace(/\n{3,}/g, "\n\n");
|
|
69028
|
+
s = s.split("\n").map((line) => line.trim()).join("\n").trim();
|
|
69029
|
+
return s;
|
|
69030
|
+
}
|
|
69031
|
+
function extractTitle(html) {
|
|
69032
|
+
const m = /<title[^>]*>([\s\S]*?)<\/title>/i.exec(html);
|
|
69033
|
+
return m ? htmlToText(m[1]).slice(0, 200) : "";
|
|
69034
|
+
}
|
|
69035
|
+
function decodeDdgHref(href) {
|
|
69036
|
+
let h = (href || "").trim();
|
|
69037
|
+
if (!h) return "";
|
|
69038
|
+
if (h.startsWith("//")) h = "https:" + h;
|
|
69039
|
+
try {
|
|
69040
|
+
const u = new URL(h, "https://duckduckgo.com");
|
|
69041
|
+
const uddg = u.searchParams.get("uddg");
|
|
69042
|
+
if (uddg) return uddg;
|
|
69043
|
+
return u.href;
|
|
69044
|
+
} catch {
|
|
69045
|
+
return h;
|
|
69046
|
+
}
|
|
69047
|
+
}
|
|
69048
|
+
function parseDuckDuckGoHtml(html) {
|
|
69049
|
+
const snippets = [];
|
|
69050
|
+
const snippetRe = /<a[^>]+class="[^"]*result__snippet[^"]*"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
69051
|
+
let sm;
|
|
69052
|
+
while (sm = snippetRe.exec(html)) snippets.push(htmlToText(sm[1]));
|
|
69053
|
+
const results = [];
|
|
69054
|
+
const linkRe = /<a[^>]+class="[^"]*result__a[^"]*"[^>]+href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
69055
|
+
let m;
|
|
69056
|
+
let i = 0;
|
|
69057
|
+
while (m = linkRe.exec(html)) {
|
|
69058
|
+
const url2 = decodeDdgHref(m[1]);
|
|
69059
|
+
const title = htmlToText(m[2]);
|
|
69060
|
+
if (url2 && title && /^https?:\/\//i.test(url2)) {
|
|
69061
|
+
results.push({ title, url: url2, snippet: snippets[i] || "" });
|
|
69062
|
+
}
|
|
69063
|
+
i++;
|
|
69064
|
+
}
|
|
69065
|
+
return results;
|
|
69066
|
+
}
|
|
69067
|
+
function parseDuckDuckGoLite(html) {
|
|
69068
|
+
const results = [];
|
|
69069
|
+
const linkRe = /<a[^>]+class="[^"]*result-link[^"]*"[^>]+href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
69070
|
+
let m;
|
|
69071
|
+
while (m = linkRe.exec(html)) {
|
|
69072
|
+
const url2 = decodeDdgHref(m[1]);
|
|
69073
|
+
const title = htmlToText(m[2]);
|
|
69074
|
+
if (url2 && title && /^https?:\/\//i.test(url2)) {
|
|
69075
|
+
results.push({ title, url: url2, snippet: "" });
|
|
69076
|
+
}
|
|
69077
|
+
}
|
|
69078
|
+
return results;
|
|
69079
|
+
}
|
|
69080
|
+
function canonicalUrl(raw) {
|
|
69081
|
+
try {
|
|
69082
|
+
const u = new URL(raw.trim());
|
|
69083
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") return null;
|
|
69084
|
+
u.hash = "";
|
|
69085
|
+
let s = u.href;
|
|
69086
|
+
if (s.endsWith("/")) s = s.slice(0, -1);
|
|
69087
|
+
return s;
|
|
69088
|
+
} catch {
|
|
69089
|
+
return null;
|
|
69090
|
+
}
|
|
69091
|
+
}
|
|
69092
|
+
function dedupeResults(results) {
|
|
69093
|
+
const seen = /* @__PURE__ */ new Set();
|
|
69094
|
+
const out3 = [];
|
|
69095
|
+
for (const r2 of results) {
|
|
69096
|
+
const key = canonicalUrl(r2.url);
|
|
69097
|
+
if (!key || seen.has(key)) continue;
|
|
69098
|
+
seen.add(key);
|
|
69099
|
+
out3.push(r2);
|
|
69100
|
+
}
|
|
69101
|
+
return out3;
|
|
69102
|
+
}
|
|
69103
|
+
async function mapPool(items, concurrency, fn) {
|
|
69104
|
+
const results = new Array(items.length);
|
|
69105
|
+
if (items.length === 0) return results;
|
|
69106
|
+
const workers = [];
|
|
69107
|
+
const n = Math.min(Math.max(1, concurrency), items.length);
|
|
69108
|
+
let next = 0;
|
|
69109
|
+
for (let w = 0; w < n; w++) {
|
|
69110
|
+
workers.push(
|
|
69111
|
+
(async () => {
|
|
69112
|
+
for (; ; ) {
|
|
69113
|
+
const i = next++;
|
|
69114
|
+
if (i >= items.length) break;
|
|
69115
|
+
try {
|
|
69116
|
+
results[i] = await fn(items[i], i);
|
|
69117
|
+
} catch (err) {
|
|
69118
|
+
results[i] = {
|
|
69119
|
+
error: err instanceof Error ? err.message : String(err)
|
|
69120
|
+
};
|
|
69121
|
+
}
|
|
69122
|
+
}
|
|
69123
|
+
})()
|
|
69124
|
+
);
|
|
69125
|
+
}
|
|
69126
|
+
await Promise.all(workers);
|
|
69127
|
+
return results;
|
|
69128
|
+
}
|
|
69129
|
+
async function fetchText(url2, opts) {
|
|
69130
|
+
const ctrl = new AbortController();
|
|
69131
|
+
const onAbort = () => ctrl.abort();
|
|
69132
|
+
if (opts.signal) {
|
|
69133
|
+
if (opts.signal.aborted) ctrl.abort();
|
|
69134
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
69135
|
+
}
|
|
69136
|
+
const timer2 = setTimeout(() => ctrl.abort(), opts.timeoutMs);
|
|
69137
|
+
try {
|
|
69138
|
+
const resp = await fetch(url2, {
|
|
69139
|
+
method: "GET",
|
|
69140
|
+
headers: {
|
|
69141
|
+
"User-Agent": UA,
|
|
69142
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
69143
|
+
"Accept-Language": "en-US,en;q=0.9,pt-BR;q=0.8"
|
|
69144
|
+
},
|
|
69145
|
+
redirect: "follow",
|
|
69146
|
+
signal: ctrl.signal
|
|
69147
|
+
});
|
|
69148
|
+
let text2 = await resp.text();
|
|
69149
|
+
if (text2.length > MAX_RAW_BYTES) text2 = text2.slice(0, MAX_RAW_BYTES);
|
|
69150
|
+
return {
|
|
69151
|
+
status: resp.status,
|
|
69152
|
+
finalUrl: resp.url || url2,
|
|
69153
|
+
contentType: resp.headers.get("content-type") || "",
|
|
69154
|
+
text: text2
|
|
69019
69155
|
};
|
|
69020
|
-
|
|
69021
|
-
|
|
69022
|
-
|
|
69023
|
-
|
|
69024
|
-
|
|
69025
|
-
|
|
69026
|
-
|
|
69027
|
-
|
|
69028
|
-
|
|
69029
|
-
|
|
69030
|
-
|
|
69031
|
-
|
|
69032
|
-
|
|
69033
|
-
|
|
69156
|
+
} finally {
|
|
69157
|
+
clearTimeout(timer2);
|
|
69158
|
+
opts.signal?.removeEventListener("abort", onAbort);
|
|
69159
|
+
}
|
|
69160
|
+
}
|
|
69161
|
+
async function searchOneQuery(query, signal, df) {
|
|
69162
|
+
const enc = encodeURIComponent(query);
|
|
69163
|
+
const dfParam = df ? `&df=${df}` : "";
|
|
69164
|
+
try {
|
|
69165
|
+
const r2 = await fetchText(
|
|
69166
|
+
`https://html.duckduckgo.com/html/?q=${enc}${dfParam}`,
|
|
69167
|
+
{ timeoutMs: SEARCH_TIMEOUT_MS, signal }
|
|
69168
|
+
);
|
|
69169
|
+
const parsed = parseDuckDuckGoHtml(r2.text);
|
|
69170
|
+
if (parsed.length) return parsed;
|
|
69171
|
+
} catch (err) {
|
|
69172
|
+
if (isAbort(err)) throw err;
|
|
69173
|
+
}
|
|
69174
|
+
try {
|
|
69175
|
+
const r2 = await fetchText(
|
|
69176
|
+
`https://lite.duckduckgo.com/lite/?q=${enc}${dfParam}`,
|
|
69177
|
+
{ timeoutMs: SEARCH_TIMEOUT_MS, signal }
|
|
69178
|
+
);
|
|
69179
|
+
return parseDuckDuckGoLite(r2.text);
|
|
69180
|
+
} catch (err) {
|
|
69181
|
+
if (isAbort(err)) throw err;
|
|
69182
|
+
return [];
|
|
69183
|
+
}
|
|
69184
|
+
}
|
|
69185
|
+
async function searchQueries(queries, signal, df) {
|
|
69186
|
+
const lists = await mapPool(
|
|
69187
|
+
queries,
|
|
69188
|
+
Math.min(queries.length, 5),
|
|
69189
|
+
(q) => searchOneQuery(q, signal, df)
|
|
69190
|
+
);
|
|
69191
|
+
const merged = [];
|
|
69192
|
+
for (const item of lists) {
|
|
69193
|
+
if (Array.isArray(item)) merged.push(...item);
|
|
69194
|
+
}
|
|
69195
|
+
return dedupeResults(merged);
|
|
69196
|
+
}
|
|
69197
|
+
async function readPage(url2, signal) {
|
|
69198
|
+
const r2 = await fetchText(url2, { timeoutMs: READ_TIMEOUT_MS, signal });
|
|
69199
|
+
const text2 = isTextual(r2.contentType) ? htmlToText(r2.text) : "";
|
|
69200
|
+
return {
|
|
69201
|
+
url: url2,
|
|
69202
|
+
finalUrl: r2.finalUrl,
|
|
69203
|
+
status: r2.status,
|
|
69204
|
+
title: extractTitle(r2.text) || r2.finalUrl,
|
|
69205
|
+
text: text2,
|
|
69206
|
+
bytes: r2.text.length,
|
|
69207
|
+
contentType: r2.contentType
|
|
69208
|
+
};
|
|
69209
|
+
}
|
|
69210
|
+
async function jinaRead(url2, signal) {
|
|
69211
|
+
const key = process.env.JINA_API_KEY;
|
|
69212
|
+
if (!key) return null;
|
|
69213
|
+
try {
|
|
69214
|
+
const resp = await fetch(`https://r.jina.ai/${url2}`, {
|
|
69215
|
+
headers: { Authorization: `Bearer ${key}`, "X-Timeout": "25" },
|
|
69216
|
+
signal
|
|
69034
69217
|
});
|
|
69035
|
-
|
|
69036
|
-
|
|
69037
|
-
|
|
69038
|
-
|
|
69218
|
+
if (!resp.ok) return null;
|
|
69219
|
+
return await resp.text();
|
|
69220
|
+
} catch {
|
|
69221
|
+
return null;
|
|
69222
|
+
}
|
|
69223
|
+
}
|
|
69224
|
+
function formatSearchResults(results) {
|
|
69225
|
+
if (!results.length) {
|
|
69226
|
+
return "Nenhum resultado encontrado. Refine a query (sin\xF4nimos, termos em ingl\xEAs, operadores site:/filetype:) e tente de novo.";
|
|
69227
|
+
}
|
|
69228
|
+
const shown = results.slice(0, SEARCH_MAX_RESULTS);
|
|
69229
|
+
const lines = [`${shown.length} resultado(s):`];
|
|
69230
|
+
shown.forEach((r2, i) => {
|
|
69231
|
+
lines.push("");
|
|
69232
|
+
lines.push(`${i + 1}. ${r2.title}`);
|
|
69233
|
+
lines.push(` ${r2.url}`);
|
|
69234
|
+
if (r2.snippet) lines.push(` ${truncate3(r2.snippet, 300)}`);
|
|
69235
|
+
});
|
|
69236
|
+
return lines.join("\n");
|
|
69237
|
+
}
|
|
69238
|
+
function formatResearchDigest(pages, stats) {
|
|
69239
|
+
const header = `Pesquisa profunda: ${stats.totalFound} candidato(s), ${stats.fetched} buscado(s) (${stats.conc ?? 1} em paralelo), ${stats.ok} ok, ${stats.failures} falha(s)` + (stats.capped ? `, capado em ${stats.maxPages} p\xE1ginas` : "") + ".";
|
|
69240
|
+
if (!pages.length) {
|
|
69241
|
+
return header + "\nNenhuma p\xE1gina retornou texto. Refine as queries ou forne\xE7a urls e tente de novo.";
|
|
69242
|
+
}
|
|
69243
|
+
const INLINE = 40;
|
|
69244
|
+
const lines = [header, ""];
|
|
69245
|
+
pages.slice(0, INLINE).forEach((p, i) => {
|
|
69246
|
+
lines.push(`### ${i + 1}. ${p.title}`);
|
|
69247
|
+
lines.push(`${p.finalUrl} (HTTP ${p.status})`);
|
|
69248
|
+
const extract = p.text.replace(/\n+/g, " ").trim();
|
|
69249
|
+
if (extract) lines.push(truncate3(extract, 600));
|
|
69250
|
+
lines.push("");
|
|
69251
|
+
});
|
|
69252
|
+
if (pages.length > INLINE) {
|
|
69253
|
+
lines.push(`\u2026 +${pages.length - INLINE} fonte(s) no relat\xF3rio completo.`);
|
|
69254
|
+
}
|
|
69255
|
+
if (stats.reportPath) {
|
|
69256
|
+
lines.push(`Relat\xF3rio completo salvo em: ${stats.reportPath}`);
|
|
69257
|
+
}
|
|
69258
|
+
return lines.join("\n");
|
|
69259
|
+
}
|
|
69260
|
+
async function saveResearchReport(workdir, queries, pages, stats) {
|
|
69261
|
+
if (!workdir || !pages.length) return null;
|
|
69262
|
+
try {
|
|
69263
|
+
const dir = import_node_path5.default.join(workdir, "reports");
|
|
69264
|
+
await import_node_fs6.promises.mkdir(dir, { recursive: true });
|
|
69265
|
+
const slug = (queries[0] || "research").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "research";
|
|
69266
|
+
const file2 = import_node_path5.default.join(dir, `research_${slug}_${Date.now()}.md`);
|
|
69267
|
+
const parts = [];
|
|
69268
|
+
parts.push(`# Pesquisa: ${queries.join(" / ") || "(seed urls)"}`);
|
|
69269
|
+
parts.push("");
|
|
69270
|
+
parts.push(
|
|
69271
|
+
`Candidatos: ${stats.totalFound} \xB7 Buscados: ${stats.fetched} \xB7 OK: ${stats.ok} \xB7 Falhas: ${stats.failures}` + (stats.capped ? ` \xB7 capado em ${stats.maxPages}` : "")
|
|
69039
69272
|
);
|
|
69040
|
-
|
|
69041
|
-
|
|
69042
|
-
|
|
69043
|
-
);
|
|
69044
|
-
|
|
69045
|
-
|
|
69046
|
-
|
|
69047
|
-
|
|
69048
|
-
|
|
69049
|
-
|
|
69050
|
-
|
|
69051
|
-
|
|
69052
|
-
|
|
69053
|
-
const trimmed = body.trim();
|
|
69054
|
-
if (!trimmed) return "";
|
|
69055
|
-
let summary = "";
|
|
69056
|
-
if (contentType.includes("json") || trimmed.startsWith("{")) {
|
|
69057
|
-
try {
|
|
69058
|
-
const parsed = JSON.parse(trimmed);
|
|
69059
|
-
const error51 = typeof parsed.error === "string" ? parsed.error : parsed.error && typeof parsed.error === "object" && "message" in parsed.error && typeof parsed.error.message === "string" ? parsed.error.message : void 0;
|
|
69060
|
-
const message = error51 || (typeof parsed.message === "string" ? parsed.message : void 0) || (typeof parsed.detail === "string" ? parsed.detail : void 0);
|
|
69061
|
-
summary = message || trimmed;
|
|
69062
|
-
} catch {
|
|
69063
|
-
summary = trimmed;
|
|
69064
|
-
}
|
|
69065
|
-
} else if (/<[a-z][\s\S]*>/i.test(trimmed)) {
|
|
69066
|
-
const tagSummaries = [
|
|
69067
|
-
...extractHtmlTagText(trimmed, "h1"),
|
|
69068
|
-
...extractHtmlTagText(trimmed, "p"),
|
|
69069
|
-
...extractHtmlTagText(trimmed, "h2")
|
|
69070
|
-
];
|
|
69071
|
-
summary = tagSummaries.length > 0 ? tagSummaries.join(". ") : stripHtml(trimmed);
|
|
69072
|
-
} else {
|
|
69073
|
-
summary = trimmed;
|
|
69074
|
-
}
|
|
69075
|
-
return truncateSummary(redactNetworkDetails(normalizeWhitespace(summary)));
|
|
69076
|
-
};
|
|
69077
|
-
buildPerplexitySearchBody = (query, options) => {
|
|
69078
|
-
const searchBody = {
|
|
69079
|
-
query,
|
|
69080
|
-
max_results: options?.maxResults ?? 10,
|
|
69081
|
-
max_tokens_per_page: SEARCH_RESULT_CONTENT_MAX_TOKENS
|
|
69082
|
-
};
|
|
69083
|
-
if (options?.country) {
|
|
69084
|
-
searchBody.country = options.country;
|
|
69085
|
-
}
|
|
69086
|
-
if (options?.recency) {
|
|
69087
|
-
searchBody.search_recency_filter = options.recency;
|
|
69088
|
-
}
|
|
69089
|
-
return searchBody;
|
|
69090
|
-
};
|
|
69091
|
-
formatSearchResults = (results) => {
|
|
69092
|
-
return results.map((result) => ({
|
|
69093
|
-
title: result.title,
|
|
69094
|
-
url: result.url,
|
|
69095
|
-
content: result.snippet,
|
|
69096
|
-
date: result.date || null,
|
|
69097
|
-
lastUpdated: result.last_updated || null
|
|
69098
|
-
}));
|
|
69099
|
-
};
|
|
69273
|
+
parts.push("");
|
|
69274
|
+
pages.forEach((p, i) => {
|
|
69275
|
+
parts.push(`## ${i + 1}. ${p.title}`);
|
|
69276
|
+
parts.push(`- URL: ${p.finalUrl}`);
|
|
69277
|
+
parts.push(`- HTTP: ${p.status} \xB7 ${p.bytes} bytes`);
|
|
69278
|
+
parts.push("");
|
|
69279
|
+
parts.push(truncate3(p.text, 4e3));
|
|
69280
|
+
parts.push("");
|
|
69281
|
+
});
|
|
69282
|
+
await import_node_fs6.promises.writeFile(file2, parts.join("\n"), "utf8");
|
|
69283
|
+
return file2;
|
|
69284
|
+
} catch {
|
|
69285
|
+
return null;
|
|
69100
69286
|
}
|
|
69101
|
-
}
|
|
69102
|
-
|
|
69103
|
-
|
|
69104
|
-
|
|
69105
|
-
var init_web_search = __esm({
|
|
69106
|
-
"../lib/ai/tools/web-search.ts"() {
|
|
69287
|
+
}
|
|
69288
|
+
var import_node_fs6, import_node_path5, UA, SEARCH_TIMEOUT_MS, READ_TIMEOUT_MS, MAX_RAW_BYTES, OPEN_URL_MAX_CHARS, SEARCH_MAX_RESULTS, HARD_PAGE_CEILING, TIME_TO_DDG_DF, NAMED_ENTITIES, truncate3, isAbort, isTextual, TIME_ENUM, createWebSearch, createOpenUrl, createDeepResearch;
|
|
69289
|
+
var init_web_research = __esm({
|
|
69290
|
+
"src/tools/web-research.ts"() {
|
|
69107
69291
|
"use strict";
|
|
69108
69292
|
init_dist5();
|
|
69109
69293
|
init_zod();
|
|
69110
|
-
|
|
69111
|
-
|
|
69112
|
-
|
|
69113
|
-
|
|
69114
|
-
|
|
69115
|
-
|
|
69116
|
-
|
|
69117
|
-
|
|
69118
|
-
|
|
69119
|
-
|
|
69120
|
-
|
|
69121
|
-
|
|
69122
|
-
|
|
69123
|
-
|
|
69124
|
-
|
|
69125
|
-
|
|
69126
|
-
|
|
69127
|
-
|
|
69128
|
-
|
|
69129
|
-
|
|
69130
|
-
|
|
69131
|
-
|
|
69132
|
-
|
|
69133
|
-
const timeout = setTimeout(() => {
|
|
69134
|
-
cleanup();
|
|
69135
|
-
resolve2();
|
|
69136
|
-
}, delayMs);
|
|
69137
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
69138
|
-
});
|
|
69139
|
-
};
|
|
69140
|
-
getRetryDelayMs = (attemptIndex) => {
|
|
69141
|
-
const exponentialDelay = WEB_SEARCH_RETRY_BASE_DELAY_MS * Math.pow(2, attemptIndex);
|
|
69142
|
-
const jitter = Math.random() * WEB_SEARCH_RETRY_JITTER_MS;
|
|
69143
|
-
return Math.round(exponentialDelay + jitter);
|
|
69144
|
-
};
|
|
69145
|
-
createPerplexityApiError = async (response) => {
|
|
69146
|
-
const errorText = await response.text();
|
|
69147
|
-
const bodySummary = summarizePerplexityErrorBody(
|
|
69148
|
-
errorText,
|
|
69149
|
-
response.headers.get("content-type") || ""
|
|
69150
|
-
);
|
|
69151
|
-
return new PerplexityApiError({
|
|
69152
|
-
status: response.status,
|
|
69153
|
-
statusText: response.statusText,
|
|
69154
|
-
bodySummary,
|
|
69155
|
-
retryable: isRetryablePerplexityStatus(response.status)
|
|
69156
|
-
});
|
|
69157
|
-
};
|
|
69158
|
-
formatPerplexityFailureForTool = (error51, attempts) => {
|
|
69159
|
-
const statusText = error51.statusText ? ` ${error51.statusText}` : "";
|
|
69160
|
-
if (error51.retryable) {
|
|
69161
|
-
return `Error performing web search: Perplexity search is temporarily unavailable (HTTP ${error51.status}${statusText} after ${attempts} attempts). Please retry shortly or continue without live web results if the task can proceed.`;
|
|
69162
|
-
}
|
|
69163
|
-
if (error51.status === 401 || error51.status === 403) {
|
|
69164
|
-
return `Error performing web search: Perplexity search is not authorized (HTTP ${error51.status}${statusText}). Check the Perplexity API key or account access.`;
|
|
69165
|
-
}
|
|
69166
|
-
return `Error performing web search: Perplexity search failed (HTTP ${error51.status}${statusText}).`;
|
|
69294
|
+
import_node_fs6 = require("node:fs");
|
|
69295
|
+
import_node_path5 = __toESM(require("node:path"));
|
|
69296
|
+
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36";
|
|
69297
|
+
SEARCH_TIMEOUT_MS = 15e3;
|
|
69298
|
+
READ_TIMEOUT_MS = 25e3;
|
|
69299
|
+
MAX_RAW_BYTES = 15e5;
|
|
69300
|
+
OPEN_URL_MAX_CHARS = 8e3;
|
|
69301
|
+
SEARCH_MAX_RESULTS = 30;
|
|
69302
|
+
HARD_PAGE_CEILING = 500;
|
|
69303
|
+
TIME_TO_DDG_DF = {
|
|
69304
|
+
past_day: "d",
|
|
69305
|
+
past_week: "w",
|
|
69306
|
+
past_month: "m",
|
|
69307
|
+
past_year: "y"
|
|
69308
|
+
};
|
|
69309
|
+
NAMED_ENTITIES = {
|
|
69310
|
+
amp: "&",
|
|
69311
|
+
lt: "<",
|
|
69312
|
+
gt: ">",
|
|
69313
|
+
quot: '"',
|
|
69314
|
+
apos: "'",
|
|
69315
|
+
nbsp: " ",
|
|
69316
|
+
"#39": "'"
|
|
69167
69317
|
};
|
|
69168
|
-
|
|
69169
|
-
|
|
69170
|
-
|
|
69171
|
-
|
|
69318
|
+
truncate3 = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
69319
|
+
isAbort = (err) => err instanceof Error && err.name === "AbortError";
|
|
69320
|
+
isTextual = (ct) => !ct || /text|html|json|xml|javascript|csv/i.test(ct);
|
|
69321
|
+
TIME_ENUM = external_exports.enum(["all", "past_day", "past_week", "past_month", "past_year"]).optional();
|
|
69322
|
+
createWebSearch = (_context) => tool({
|
|
69323
|
+
description: `Search the web for free (no API key required, DuckDuckGo-backed). Returns ranked results (title, url, snippet).
|
|
69324
|
+
|
|
69325
|
+
<instructions>
|
|
69326
|
+
- Give 1\u20135 \`queries\` that are VARIANTS of the SAME intent (query expansions), not different goals. For non-English topics add one English variant.
|
|
69327
|
+
- Break a complex need into step-by-step searches instead of one giant query.
|
|
69328
|
+
- You CAN use operators: site:, filetype:, inurl:, intitle:.
|
|
69329
|
+
- After searching, OPEN the most relevant results with open_url to actually read them; cross-check facts across 2+ sources.
|
|
69330
|
+
- If results are weak, refine the wording and search again.
|
|
69331
|
+
</instructions>`,
|
|
69332
|
+
inputSchema: external_exports.object({
|
|
69333
|
+
brief: external_exports.string().describe("A one-sentence preamble describing the purpose of this search."),
|
|
69334
|
+
queries: external_exports.array(external_exports.string().trim().min(1).max(2e3)).min(1).max(5).describe("1\u20135 query variants of the same intent."),
|
|
69335
|
+
time: TIME_ENUM.describe(
|
|
69336
|
+
"Optional recency filter (past_day/week/month/year)."
|
|
69337
|
+
)
|
|
69338
|
+
}),
|
|
69339
|
+
execute: async ({ queries, time: time3 }, { abortSignal } = {}) => {
|
|
69340
|
+
const norm = Array.from(
|
|
69341
|
+
new Set(queries.map((q) => q.trim()).filter(Boolean))
|
|
69342
|
+
).slice(0, 5);
|
|
69343
|
+
if (!norm.length) return "Erro: forne\xE7a ao menos uma query n\xE3o vazia.";
|
|
69172
69344
|
try {
|
|
69173
|
-
const
|
|
69174
|
-
|
|
69175
|
-
|
|
69176
|
-
|
|
69177
|
-
|
|
69178
|
-
|
|
69179
|
-
body: JSON.stringify(searchBody),
|
|
69180
|
-
signal: abortSignal
|
|
69181
|
-
});
|
|
69182
|
-
if (response.ok) {
|
|
69183
|
-
return response;
|
|
69184
|
-
}
|
|
69185
|
-
const error51 = await createPerplexityApiError(response);
|
|
69186
|
-
if (!error51.retryable || isFinalAttempt) {
|
|
69187
|
-
throw error51;
|
|
69188
|
-
}
|
|
69189
|
-
const delayMs = getRetryDelayMs(attemptIndex);
|
|
69190
|
-
console.warn("Web search provider error; retrying", {
|
|
69191
|
-
attempt,
|
|
69192
|
-
maxAttempts: WEB_SEARCH_MAX_ATTEMPTS,
|
|
69193
|
-
status: error51.status,
|
|
69194
|
-
statusText: error51.statusText,
|
|
69195
|
-
bodySummary: error51.bodySummary,
|
|
69196
|
-
delayMs
|
|
69197
|
-
});
|
|
69198
|
-
await sleep2(delayMs, abortSignal);
|
|
69199
|
-
} catch (error51) {
|
|
69200
|
-
if (error51 instanceof Error && error51.name === "AbortError") {
|
|
69201
|
-
throw error51;
|
|
69202
|
-
}
|
|
69203
|
-
if (error51 instanceof PerplexityApiError) {
|
|
69204
|
-
throw error51;
|
|
69205
|
-
}
|
|
69206
|
-
if (isFinalAttempt) {
|
|
69207
|
-
throw error51;
|
|
69208
|
-
}
|
|
69209
|
-
const delayMs = getRetryDelayMs(attemptIndex);
|
|
69210
|
-
console.warn("Web search network error; retrying", {
|
|
69211
|
-
attempt,
|
|
69212
|
-
maxAttempts: WEB_SEARCH_MAX_ATTEMPTS,
|
|
69213
|
-
error: stringifyRedactedError(error51),
|
|
69214
|
-
delayMs
|
|
69215
|
-
});
|
|
69216
|
-
await sleep2(delayMs, abortSignal);
|
|
69345
|
+
const df = time3 && time3 !== "all" ? TIME_TO_DDG_DF[time3] : void 0;
|
|
69346
|
+
const results = await searchQueries(norm, abortSignal, df);
|
|
69347
|
+
return formatSearchResults(results);
|
|
69348
|
+
} catch (err) {
|
|
69349
|
+
if (isAbort(err)) return "Erro: opera\xE7\xE3o abortada.";
|
|
69350
|
+
return `Erro na busca: ${err instanceof Error ? err.message : String(err)}`;
|
|
69217
69351
|
}
|
|
69218
69352
|
}
|
|
69219
|
-
|
|
69220
|
-
|
|
69221
|
-
|
|
69222
|
-
const queries = rawQueries.map((query) => query.trim()).filter(Boolean);
|
|
69223
|
-
if (queries.length === 0) {
|
|
69224
|
-
return { queries, error: EMPTY_QUERY_TOOL_ERROR };
|
|
69225
|
-
}
|
|
69226
|
-
if (queries.some((query) => query.length > PERPLEXITY_QUERY_MAX_LENGTH)) {
|
|
69227
|
-
return { queries, error: QUERY_TOO_LONG_TOOL_ERROR };
|
|
69228
|
-
}
|
|
69229
|
-
return { queries: queries.slice(0, 3) };
|
|
69230
|
-
};
|
|
69231
|
-
createWebSearch = (context2) => {
|
|
69232
|
-
const { userLocation, onToolCost } = context2;
|
|
69233
|
-
return tool({
|
|
69234
|
-
description: `Search for information across various sources.
|
|
69353
|
+
});
|
|
69354
|
+
createOpenUrl = (_opts) => tool({
|
|
69355
|
+
description: `Open a specific URL and return its readable text content (free, no API key). Use it to actually READ a link \u2014 the one the user pasted, or one from a prior search \u2014 before you act on it.
|
|
69235
69356
|
|
|
69236
69357
|
<instructions>
|
|
69237
|
-
-
|
|
69238
|
-
-
|
|
69239
|
-
-
|
|
69240
|
-
- For complex searches, MUST break down into step-by-step searches instead of using a single complex query
|
|
69241
|
-
- Access multiple URLs from search results for comprehensive information or cross-validation
|
|
69242
|
-
- CAN use Google dork syntax (site:, filetype:, inurl:, intitle:, etc.) for targeted reconnaissance and pentest enumeration
|
|
69243
|
-
- Only use \`time\` parameter when explicitly required by task, otherwise leave time range unrestricted
|
|
69244
|
-
- Prioritize cybersecurity-relevant information: CVEs, CVSS scores, exploits, PoCs, security tools, and pentest methodologies
|
|
69245
|
-
- Include specific versions, configurations, and technical details; cite reliable sources (NIST, OWASP, CVE databases)
|
|
69246
|
-
- For commands/installations, prioritize Kali Linux compatibility using apt or pre-installed tools
|
|
69358
|
+
- The URL must be public and http(s).
|
|
69359
|
+
- Returns the page title + extracted text (JS is not executed; for JS-heavy pages use the recon toolkit's --browser path).
|
|
69360
|
+
- Read carefully, then verify important facts against another source.
|
|
69247
69361
|
</instructions>`,
|
|
69248
|
-
|
|
69249
|
-
|
|
69250
|
-
|
|
69251
|
-
|
|
69252
|
-
|
|
69253
|
-
|
|
69254
|
-
|
|
69255
|
-
|
|
69256
|
-
|
|
69257
|
-
)
|
|
69258
|
-
|
|
69259
|
-
|
|
69260
|
-
|
|
69261
|
-
|
|
69262
|
-
|
|
69263
|
-
|
|
69264
|
-
|
|
69265
|
-
|
|
69266
|
-
|
|
69267
|
-
|
|
69268
|
-
|
|
69269
|
-
|
|
69270
|
-
{
|
|
69271
|
-
country: userLocation?.country,
|
|
69272
|
-
recency: time3 && time3 !== "all" ? RECENCY_MAP[time3] : void 0
|
|
69273
|
-
}
|
|
69274
|
-
);
|
|
69275
|
-
const response = await fetchPerplexitySearch(searchBody, abortSignal);
|
|
69276
|
-
onToolCost?.(WEB_SEARCH_COST_PER_REQUEST);
|
|
69277
|
-
const searchResponse = await response.json();
|
|
69278
|
-
const isMultiQuery = queries.length > 1;
|
|
69279
|
-
let allResults;
|
|
69280
|
-
if (isMultiQuery && Array.isArray(searchResponse.results[0])) {
|
|
69281
|
-
allResults = searchResponse.results.flat();
|
|
69282
|
-
} else {
|
|
69283
|
-
allResults = searchResponse.results;
|
|
69284
|
-
}
|
|
69285
|
-
return formatSearchResults(allResults);
|
|
69286
|
-
} catch (error51) {
|
|
69287
|
-
if (error51 instanceof Error && error51.name === "AbortError") {
|
|
69288
|
-
return "Error: Operation aborted";
|
|
69289
|
-
}
|
|
69290
|
-
if (error51 instanceof PerplexityApiError) {
|
|
69291
|
-
console.error("Web search tool error:", {
|
|
69292
|
-
name: error51.name,
|
|
69293
|
-
status: error51.status,
|
|
69294
|
-
statusText: error51.statusText,
|
|
69295
|
-
retryable: error51.retryable,
|
|
69296
|
-
bodySummary: error51.bodySummary
|
|
69297
|
-
});
|
|
69298
|
-
return formatPerplexityFailureForTool(
|
|
69299
|
-
error51,
|
|
69300
|
-
error51.retryable ? WEB_SEARCH_MAX_ATTEMPTS : 1
|
|
69301
|
-
);
|
|
69302
|
-
}
|
|
69303
|
-
const errorMessage = stringifyRedactedError(error51);
|
|
69304
|
-
console.error("Web search tool error:", errorMessage);
|
|
69305
|
-
return `Error performing web search: ${errorMessage}`;
|
|
69306
|
-
}
|
|
69362
|
+
inputSchema: external_exports.object({
|
|
69363
|
+
brief: external_exports.string().describe("A one-sentence preamble describing the purpose of this fetch."),
|
|
69364
|
+
url: external_exports.string().describe("The http(s) URL to open and read.")
|
|
69365
|
+
}),
|
|
69366
|
+
execute: async ({ url: url2 }, { abortSignal } = {}) => {
|
|
69367
|
+
const canon = canonicalUrl(url2);
|
|
69368
|
+
if (!canon) return `URL inv\xE1lida: ${url2}`;
|
|
69369
|
+
try {
|
|
69370
|
+
const jina = await jinaRead(canon, abortSignal);
|
|
69371
|
+
if (jina) return truncate3(jina, OPEN_URL_MAX_CHARS * 2);
|
|
69372
|
+
const page = await readPage(canon, abortSignal);
|
|
69373
|
+
if (!isTextual(page.contentType)) {
|
|
69374
|
+
return `(${page.finalUrl}) conte\xFAdo n\xE3o textual (${page.contentType}, ${page.bytes} bytes) \u2014 n\xE3o extra\xEDdo.`;
|
|
69375
|
+
}
|
|
69376
|
+
const head = `# ${page.title}
|
|
69377
|
+
${page.finalUrl} (HTTP ${page.status}, ${page.bytes} bytes)
|
|
69378
|
+
`;
|
|
69379
|
+
const body = page.text || "(sem texto extra\xEDvel \u2014 pode ser JS puro; use a recon toolkit com --browser)";
|
|
69380
|
+
return head + "\n" + truncate3(body, OPEN_URL_MAX_CHARS);
|
|
69381
|
+
} catch (err) {
|
|
69382
|
+
if (isAbort(err)) return "Erro: opera\xE7\xE3o abortada.";
|
|
69383
|
+
return `Erro ao abrir URL: ${err instanceof Error ? err.message : String(err)}`;
|
|
69307
69384
|
}
|
|
69308
|
-
}
|
|
69309
|
-
};
|
|
69310
|
-
|
|
69311
|
-
|
|
69312
|
-
|
|
69313
|
-
// ../lib/ai/tools/open-url.ts
|
|
69314
|
-
var createOpenUrlTool;
|
|
69315
|
-
var init_open_url = __esm({
|
|
69316
|
-
"../lib/ai/tools/open-url.ts"() {
|
|
69317
|
-
"use strict";
|
|
69318
|
-
init_dist5();
|
|
69319
|
-
init_zod();
|
|
69320
|
-
init_token_utils();
|
|
69321
|
-
createOpenUrlTool = () => {
|
|
69322
|
-
return tool({
|
|
69323
|
-
description: `Retrieve the full contents of a specific webpage by URL.
|
|
69385
|
+
}
|
|
69386
|
+
});
|
|
69387
|
+
createDeepResearch = (opts) => tool({
|
|
69388
|
+
description: `Deep web research: search + fetch MANY pages concurrently and return a synthesized digest with sources. Free, no API key.
|
|
69324
69389
|
|
|
69325
69390
|
<instructions>
|
|
69326
|
-
-
|
|
69327
|
-
-
|
|
69328
|
-
-
|
|
69329
|
-
-
|
|
69391
|
+
- Provide \`queries\` (1\u20136 variants) and/or seed \`urls\`. It searches, collects candidate links, and fetches up to \`max_pages\` of them in parallel.
|
|
69392
|
+
- Tune to the SUBJECT: a quick fact needs a handful of pages; a broad survey can sweep up to 500. Do NOT fetch 500 for something small.
|
|
69393
|
+
- Returns: per-source title + url + a short extract, plus counts. A full Markdown report is saved under the workspace's reports/ when possible.
|
|
69394
|
+
- Use this for broad/unknown topics and cross-validation; use open_url to drill into a single page, web_search for a quick lookup.
|
|
69330
69395
|
</instructions>`,
|
|
69331
|
-
|
|
69332
|
-
|
|
69333
|
-
|
|
69334
|
-
|
|
69335
|
-
|
|
69336
|
-
|
|
69337
|
-
|
|
69338
|
-
|
|
69339
|
-
|
|
69340
|
-
|
|
69341
|
-
|
|
69342
|
-
|
|
69343
|
-
|
|
69344
|
-
|
|
69345
|
-
|
|
69346
|
-
|
|
69347
|
-
|
|
69348
|
-
|
|
69349
|
-
|
|
69350
|
-
|
|
69351
|
-
|
|
69352
|
-
|
|
69353
|
-
|
|
69354
|
-
|
|
69355
|
-
|
|
69356
|
-
|
|
69357
|
-
|
|
69358
|
-
|
|
69359
|
-
|
|
69360
|
-
|
|
69361
|
-
|
|
69362
|
-
|
|
69363
|
-
|
|
69364
|
-
|
|
69396
|
+
inputSchema: external_exports.object({
|
|
69397
|
+
brief: external_exports.string().describe("A one-sentence preamble describing the research goal."),
|
|
69398
|
+
queries: external_exports.array(external_exports.string().trim().min(1).max(2e3)).max(6).optional().describe("1\u20136 search query variants of the same intent."),
|
|
69399
|
+
urls: external_exports.array(external_exports.string()).max(HARD_PAGE_CEILING).optional().describe("Optional seed URLs to include directly."),
|
|
69400
|
+
max_pages: external_exports.number().int().min(1).max(HARD_PAGE_CEILING).optional().describe("Max pages to fetch (default 12, ceiling 500). Match to the subject."),
|
|
69401
|
+
concurrency: external_exports.number().int().min(1).max(HARD_PAGE_CEILING).optional().describe("Parallel fetches (default 8, up to 500)."),
|
|
69402
|
+
time: TIME_ENUM.describe("Optional recency filter for the search step.")
|
|
69403
|
+
}),
|
|
69404
|
+
execute: async (input, { abortSignal } = {}) => {
|
|
69405
|
+
const queries = Array.from(
|
|
69406
|
+
new Set((input.queries || []).map((q) => q.trim()).filter(Boolean))
|
|
69407
|
+
).slice(0, 6);
|
|
69408
|
+
const seeds = [];
|
|
69409
|
+
for (const u of input.urls || []) {
|
|
69410
|
+
const c = canonicalUrl(u);
|
|
69411
|
+
if (c) seeds.push({ title: c, url: c, snippet: "" });
|
|
69412
|
+
}
|
|
69413
|
+
if (!queries.length && !seeds.length) {
|
|
69414
|
+
return "Erro: forne\xE7a queries e/ou urls para pesquisar.";
|
|
69415
|
+
}
|
|
69416
|
+
const maxPages = Math.min(
|
|
69417
|
+
Math.max(1, input.max_pages ?? 12),
|
|
69418
|
+
HARD_PAGE_CEILING
|
|
69419
|
+
);
|
|
69420
|
+
const requestedConc = Math.min(
|
|
69421
|
+
Math.max(1, input.concurrency ?? 8),
|
|
69422
|
+
HARD_PAGE_CEILING
|
|
69423
|
+
);
|
|
69424
|
+
try {
|
|
69425
|
+
const df = input.time && input.time !== "all" ? TIME_TO_DDG_DF[input.time] : void 0;
|
|
69426
|
+
const searched = queries.length ? await searchQueries(queries, abortSignal, df) : [];
|
|
69427
|
+
const candidates = dedupeResults([...seeds, ...searched]);
|
|
69428
|
+
const totalFound = candidates.length;
|
|
69429
|
+
const capped = totalFound > maxPages;
|
|
69430
|
+
const toFetch = candidates.slice(0, maxPages);
|
|
69431
|
+
const conc = Math.min(requestedConc, toFetch.length || 1);
|
|
69432
|
+
const fetched = await mapPool(
|
|
69433
|
+
toFetch,
|
|
69434
|
+
conc,
|
|
69435
|
+
(r2) => readPage(r2.url, abortSignal)
|
|
69436
|
+
);
|
|
69437
|
+
const pages = [];
|
|
69438
|
+
let failures = 0;
|
|
69439
|
+
fetched.forEach((p) => {
|
|
69440
|
+
if (p && "error" in p) failures++;
|
|
69441
|
+
else if (p) pages.push(p);
|
|
69442
|
+
});
|
|
69443
|
+
const reportPath = await saveResearchReport(
|
|
69444
|
+
opts.workdir,
|
|
69445
|
+
queries,
|
|
69446
|
+
pages,
|
|
69447
|
+
{ totalFound, fetched: toFetch.length, ok: pages.length, failures, capped, maxPages }
|
|
69448
|
+
);
|
|
69449
|
+
return formatResearchDigest(pages, {
|
|
69450
|
+
totalFound,
|
|
69451
|
+
fetched: toFetch.length,
|
|
69452
|
+
ok: pages.length,
|
|
69453
|
+
failures,
|
|
69454
|
+
capped,
|
|
69455
|
+
maxPages,
|
|
69456
|
+
conc,
|
|
69457
|
+
reportPath
|
|
69458
|
+
});
|
|
69459
|
+
} catch (err) {
|
|
69460
|
+
if (isAbort(err)) return "Erro: opera\xE7\xE3o abortada.";
|
|
69461
|
+
return `Erro na pesquisa profunda: ${err instanceof Error ? err.message : String(err)}`;
|
|
69365
69462
|
}
|
|
69366
|
-
}
|
|
69367
|
-
};
|
|
69463
|
+
}
|
|
69464
|
+
});
|
|
69368
69465
|
}
|
|
69369
69466
|
});
|
|
69370
69467
|
|
|
69371
69468
|
// src/tools/scope.ts
|
|
69372
|
-
var
|
|
69469
|
+
var import_node_fs7, import_node_path6, import_promises, ipv4ToInt, isIpLiteral, maskForPrefix, parseCidr, ScopeImpl, scopeFileFor, loadScope, hostFromUrl;
|
|
69373
69470
|
var init_scope = __esm({
|
|
69374
69471
|
"src/tools/scope.ts"() {
|
|
69375
69472
|
"use strict";
|
|
69376
|
-
|
|
69377
|
-
|
|
69473
|
+
import_node_fs7 = __toESM(require("node:fs"));
|
|
69474
|
+
import_node_path6 = __toESM(require("node:path"));
|
|
69378
69475
|
import_promises = __toESM(require("node:dns/promises"));
|
|
69379
69476
|
ipv4ToInt = (ip) => {
|
|
69380
69477
|
const parts = ip.split(".");
|
|
@@ -69472,11 +69569,11 @@ var init_scope = __esm({
|
|
|
69472
69569
|
return false;
|
|
69473
69570
|
}
|
|
69474
69571
|
};
|
|
69475
|
-
scopeFileFor = (workdir) =>
|
|
69572
|
+
scopeFileFor = (workdir) => import_node_path6.default.join(workdir, "recon", "scope.txt");
|
|
69476
69573
|
loadScope = (workdir) => {
|
|
69477
69574
|
const file2 = scopeFileFor(workdir);
|
|
69478
69575
|
try {
|
|
69479
|
-
const text2 =
|
|
69576
|
+
const text2 = import_node_fs7.default.readFileSync(file2, "utf8");
|
|
69480
69577
|
return ScopeImpl.parse(text2, file2);
|
|
69481
69578
|
} catch {
|
|
69482
69579
|
return ScopeImpl.parse("", null);
|
|
@@ -69493,7 +69590,7 @@ var init_scope = __esm({
|
|
|
69493
69590
|
});
|
|
69494
69591
|
|
|
69495
69592
|
// src/tools/http-request.ts
|
|
69496
|
-
var FUZZ, MAX_FUZZ, BODY_PREVIEW_CHARS, DEFAULT_TIMEOUT_S, LOOPBACK, numberEnv,
|
|
69593
|
+
var FUZZ, MAX_FUZZ, BODY_PREVIEW_CHARS, DEFAULT_TIMEOUT_S, LOOPBACK, numberEnv, sleep2, sampleUrl, NOTABLE_HEADERS, applyFuzz, buildInit, collectNotableHeaders, doRequest, summarizeFuzz, scopeRefusal, createHttpRequest;
|
|
69497
69594
|
var init_http_request = __esm({
|
|
69498
69595
|
"src/tools/http-request.ts"() {
|
|
69499
69596
|
"use strict";
|
|
@@ -69509,7 +69606,7 @@ var init_http_request = __esm({
|
|
|
69509
69606
|
const raw = Number(process.env[name25]);
|
|
69510
69607
|
return Number.isFinite(raw) && raw >= 0 ? raw : void 0;
|
|
69511
69608
|
};
|
|
69512
|
-
|
|
69609
|
+
sleep2 = (ms, signal) => new Promise((resolve2) => {
|
|
69513
69610
|
if (ms <= 0 || signal?.aborted) return resolve2();
|
|
69514
69611
|
const t = setTimeout(resolve2, ms);
|
|
69515
69612
|
signal?.addEventListener(
|
|
@@ -69630,7 +69727,7 @@ var init_http_request = __esm({
|
|
|
69630
69727
|
};
|
|
69631
69728
|
scopeRefusal = (host, workdir) => `Recusado: o host "${host}" n\xE3o est\xE1 no escopo autorizado. Adicione-o a ${scopeFileFor(workdir)} (formatos: example.com, *.example.com, CIDR 10.0.0.0/24, ou um IP) \u2014 somente alvos que voc\xEA possui ou tem autoriza\xE7\xE3o expl\xEDcita para testar. Edite o scope.txt com a ferramenta file e tente de novo.`;
|
|
69632
69729
|
createHttpRequest = (deps) => {
|
|
69633
|
-
const { workdir, loadScopeFn = loadScope } = deps;
|
|
69730
|
+
const { workdir, loadScopeFn = loadScope, unrestricted = false } = deps;
|
|
69634
69731
|
const envThrottle = numberEnv("clawfast_HTTP_THROTTLE_MS");
|
|
69635
69732
|
const envJitter = numberEnv("clawfast_HTTP_JITTER_MS");
|
|
69636
69733
|
return tool({
|
|
@@ -69644,20 +69741,30 @@ SCOPE: every request is gated by recon/scope.txt (same allowlist as the recon to
|
|
|
69644
69741
|
|
|
69645
69742
|
USE FOR: testing a single endpoint, replaying/tampering a captured request, parameter/path/value fuzzing, verifying an exploit by observing the real response. NOT a replacement for bulk crawling \u2014 use the Python recon toolkit for that.`,
|
|
69646
69743
|
inputSchema: external_exports.object({
|
|
69647
|
-
brief: external_exports.string().describe(
|
|
69744
|
+
brief: external_exports.string().describe(
|
|
69745
|
+
"A one-sentence preamble describing the purpose of this request."
|
|
69746
|
+
),
|
|
69648
69747
|
url: external_exports.string().url().describe(
|
|
69649
69748
|
"Target URL. May contain the marker FUZZ (replaced by each fuzz payload)."
|
|
69650
69749
|
),
|
|
69651
69750
|
method: external_exports.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]).optional().describe("HTTP method (default GET)."),
|
|
69652
69751
|
headers: external_exports.record(external_exports.string(), external_exports.string()).optional().describe("Request headers. Values may contain FUZZ."),
|
|
69653
69752
|
body: external_exports.string().optional().describe("Request body for POST/PUT/PATCH/DELETE. May contain FUZZ."),
|
|
69654
|
-
follow_redirects: external_exports.boolean().optional().describe(
|
|
69655
|
-
|
|
69753
|
+
follow_redirects: external_exports.boolean().optional().describe(
|
|
69754
|
+
"Follow 3xx redirects (default true). Set false to inspect Location."
|
|
69755
|
+
),
|
|
69756
|
+
timeout: external_exports.number().optional().describe(
|
|
69757
|
+
`Per-request timeout in seconds (default ${DEFAULT_TIMEOUT_S}).`
|
|
69758
|
+
),
|
|
69656
69759
|
fuzz: external_exports.array(external_exports.string()).optional().describe(
|
|
69657
69760
|
`Intruder payloads \u2014 substituted into the FUZZ marker, one request each (max ${MAX_FUZZ}).`
|
|
69658
69761
|
),
|
|
69659
|
-
throttle_ms: external_exports.number().optional().describe(
|
|
69660
|
-
|
|
69762
|
+
throttle_ms: external_exports.number().optional().describe(
|
|
69763
|
+
"OPSEC: delay between fuzz requests in ms (overrides clawfast_HTTP_THROTTLE_MS)."
|
|
69764
|
+
),
|
|
69765
|
+
jitter_ms: external_exports.number().optional().describe(
|
|
69766
|
+
"OPSEC: random extra delay 0..jitter added to each throttle."
|
|
69767
|
+
)
|
|
69661
69768
|
}),
|
|
69662
69769
|
execute: async (input, { abortSignal } = {}) => {
|
|
69663
69770
|
const method = input.method ?? "GET";
|
|
@@ -69667,7 +69774,7 @@ USE FOR: testing a single endpoint, replaying/tampering a captured request, para
|
|
|
69667
69774
|
if (!host) {
|
|
69668
69775
|
return { error: `URL inv\xE1lida: ${input.url}` };
|
|
69669
69776
|
}
|
|
69670
|
-
if (!LOOPBACK.has(host)) {
|
|
69777
|
+
if (!unrestricted && !LOOPBACK.has(host)) {
|
|
69671
69778
|
const scope = loadScopeFn(workdir);
|
|
69672
69779
|
const allowed = await scope.allows(host);
|
|
69673
69780
|
if (!allowed) {
|
|
@@ -69707,7 +69814,13 @@ USE FOR: testing a single endpoint, replaying/tampering a captured request, para
|
|
|
69707
69814
|
abortSignal
|
|
69708
69815
|
);
|
|
69709
69816
|
if ("error" in res2) {
|
|
69710
|
-
rows.push({
|
|
69817
|
+
rows.push({
|
|
69818
|
+
payload,
|
|
69819
|
+
status: "ERR",
|
|
69820
|
+
bodyLength: 0,
|
|
69821
|
+
timeMs: res2.timeMs,
|
|
69822
|
+
error: res2.error
|
|
69823
|
+
});
|
|
69711
69824
|
} else {
|
|
69712
69825
|
rows.push({
|
|
69713
69826
|
payload,
|
|
@@ -69718,7 +69831,10 @@ USE FOR: testing a single endpoint, replaying/tampering a captured request, para
|
|
|
69718
69831
|
});
|
|
69719
69832
|
}
|
|
69720
69833
|
if (i < list.length - 1 && (throttle > 0 || jitter > 0)) {
|
|
69721
|
-
await
|
|
69834
|
+
await sleep2(
|
|
69835
|
+
throttle + Math.floor(Math.random() * (jitter + 1)),
|
|
69836
|
+
abortSignal
|
|
69837
|
+
);
|
|
69722
69838
|
}
|
|
69723
69839
|
}
|
|
69724
69840
|
return { fuzz: { host, count: rows.length, rows } };
|
|
@@ -69796,12 +69912,12 @@ ${s.bodyPreview}`
|
|
|
69796
69912
|
});
|
|
69797
69913
|
|
|
69798
69914
|
// src/tools/findings.ts
|
|
69799
|
-
var
|
|
69915
|
+
var import_node_fs8, import_node_path7, SEVERITIES, STATUSES, SEVERITY_RANK, SEVERITY_EMOJI, findingsStoreFor, readAll, writeAll, nextId, sortBySeverity, renderReport, oneLine, createFindings;
|
|
69800
69916
|
var init_findings = __esm({
|
|
69801
69917
|
"src/tools/findings.ts"() {
|
|
69802
69918
|
"use strict";
|
|
69803
|
-
|
|
69804
|
-
|
|
69919
|
+
import_node_fs8 = __toESM(require("node:fs"));
|
|
69920
|
+
import_node_path7 = __toESM(require("node:path"));
|
|
69805
69921
|
init_dist5();
|
|
69806
69922
|
init_zod();
|
|
69807
69923
|
SEVERITIES = [
|
|
@@ -69827,16 +69943,16 @@ var init_findings = __esm({
|
|
|
69827
69943
|
info: "\u26AA"
|
|
69828
69944
|
};
|
|
69829
69945
|
findingsStoreFor = (workdir) => {
|
|
69830
|
-
const findingsDir =
|
|
69946
|
+
const findingsDir = import_node_path7.default.join(workdir, "findings");
|
|
69831
69947
|
return {
|
|
69832
69948
|
findingsDir,
|
|
69833
|
-
storeFile:
|
|
69834
|
-
reportFile:
|
|
69949
|
+
storeFile: import_node_path7.default.join(findingsDir, "findings.json"),
|
|
69950
|
+
reportFile: import_node_path7.default.join(findingsDir, "report.md")
|
|
69835
69951
|
};
|
|
69836
69952
|
};
|
|
69837
69953
|
readAll = (store) => {
|
|
69838
69954
|
try {
|
|
69839
|
-
const raw =
|
|
69955
|
+
const raw = import_node_fs8.default.readFileSync(store.storeFile, "utf8");
|
|
69840
69956
|
const parsed = JSON.parse(raw);
|
|
69841
69957
|
return Array.isArray(parsed) ? parsed : [];
|
|
69842
69958
|
} catch {
|
|
@@ -69844,8 +69960,8 @@ var init_findings = __esm({
|
|
|
69844
69960
|
}
|
|
69845
69961
|
};
|
|
69846
69962
|
writeAll = (store, findings) => {
|
|
69847
|
-
|
|
69848
|
-
|
|
69963
|
+
import_node_fs8.default.mkdirSync(store.findingsDir, { recursive: true });
|
|
69964
|
+
import_node_fs8.default.writeFileSync(store.storeFile, JSON.stringify(findings, null, 2), "utf8");
|
|
69849
69965
|
};
|
|
69850
69966
|
nextId = (findings) => {
|
|
69851
69967
|
let max = 0;
|
|
@@ -69944,7 +70060,9 @@ ACTIONS
|
|
|
69944
70060
|
Use this together with http_request: probe \u2192 observe \u2192 record evidence \u2192 mark confirmed.`,
|
|
69945
70061
|
inputSchema: external_exports.object({
|
|
69946
70062
|
action: external_exports.enum(["add", "update", "list", "report"]),
|
|
69947
|
-
brief: external_exports.string().describe(
|
|
70063
|
+
brief: external_exports.string().describe(
|
|
70064
|
+
"A one-sentence preamble describing the purpose of this operation."
|
|
70065
|
+
),
|
|
69948
70066
|
id: external_exports.string().optional().describe("Finding id (e.g. F-001) \u2014 required for update."),
|
|
69949
70067
|
title: external_exports.string().optional(),
|
|
69950
70068
|
severity: external_exports.enum(SEVERITIES).optional(),
|
|
@@ -70017,7 +70135,9 @@ Use this together with http_request: probe \u2192 observe \u2192 record evidence
|
|
|
70017
70135
|
if (input.action === "list") {
|
|
70018
70136
|
let filtered = findings;
|
|
70019
70137
|
if (input.filter_severity) {
|
|
70020
|
-
filtered = filtered.filter(
|
|
70138
|
+
filtered = filtered.filter(
|
|
70139
|
+
(f) => f.severity === input.filter_severity
|
|
70140
|
+
);
|
|
70021
70141
|
}
|
|
70022
70142
|
if (input.filter_status) {
|
|
70023
70143
|
filtered = filtered.filter((f) => f.status === input.filter_status);
|
|
@@ -70029,8 +70149,8 @@ Use this together with http_request: probe \u2192 observe \u2192 record evidence
|
|
|
70029
70149
|
};
|
|
70030
70150
|
}
|
|
70031
70151
|
const md = renderReport(findings);
|
|
70032
|
-
|
|
70033
|
-
|
|
70152
|
+
import_node_fs8.default.mkdirSync(store.findingsDir, { recursive: true });
|
|
70153
|
+
import_node_fs8.default.writeFileSync(store.reportFile, md, "utf8");
|
|
70034
70154
|
return { report: store.reportFile, total: findings.length };
|
|
70035
70155
|
} catch (err) {
|
|
70036
70156
|
return {
|
|
@@ -70260,20 +70380,48 @@ var init_utils4 = __esm({
|
|
|
70260
70380
|
|
|
70261
70381
|
// src/local-sandbox.ts
|
|
70262
70382
|
function inferShellFlag(shell2) {
|
|
70263
|
-
const base =
|
|
70383
|
+
const base = import_node_path8.default.basename(shell2).toLowerCase();
|
|
70264
70384
|
if (base === "cmd" || base === "cmd.exe") return "/C";
|
|
70265
70385
|
if (base === "powershell" || base === "powershell.exe" || base === "pwsh") {
|
|
70266
70386
|
return "-Command";
|
|
70267
70387
|
}
|
|
70268
70388
|
return "-c";
|
|
70269
70389
|
}
|
|
70270
|
-
|
|
70390
|
+
function detectLinux(platform) {
|
|
70391
|
+
if (platform !== "linux") {
|
|
70392
|
+
return { distroId: "", distroName: "", isKali: false };
|
|
70393
|
+
}
|
|
70394
|
+
try {
|
|
70395
|
+
const text2 = (0, import_node_fs9.readFileSync)("/etc/os-release", "utf8");
|
|
70396
|
+
const map2 = {};
|
|
70397
|
+
for (const raw of text2.split(/\r?\n/)) {
|
|
70398
|
+
const eq = raw.indexOf("=");
|
|
70399
|
+
if (eq === -1) continue;
|
|
70400
|
+
const key = raw.slice(0, eq).trim();
|
|
70401
|
+
const val = raw.slice(eq + 1).trim().replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1");
|
|
70402
|
+
if (key) map2[key] = val;
|
|
70403
|
+
}
|
|
70404
|
+
const id = (map2.ID || "").toLowerCase();
|
|
70405
|
+
const idLike = (map2.ID_LIKE || "").toLowerCase();
|
|
70406
|
+
const distroName = map2.PRETTY_NAME || map2.NAME || "Linux";
|
|
70407
|
+
const isKali = id === "kali" || idLike.includes("kali") || /kali/i.test(distroName);
|
|
70408
|
+
return { distroId: id, distroName, isKali };
|
|
70409
|
+
} catch {
|
|
70410
|
+
return { distroId: "", distroName: "Linux", isKali: false };
|
|
70411
|
+
}
|
|
70412
|
+
}
|
|
70413
|
+
function computeUnrestricted(platform) {
|
|
70414
|
+
if (truthyEnv("CLAWFAST_UNRESTRICTED")) return true;
|
|
70415
|
+
if (truthyEnv("CLAWFAST_STRICT_SCOPE")) return false;
|
|
70416
|
+
return platform === "linux";
|
|
70417
|
+
}
|
|
70418
|
+
var import_node_child_process2, import_node_fs9, import_node_path8, import_node_os3, import_node_url, import_meta, LocalSandbox, truthyEnv;
|
|
70271
70419
|
var init_local_sandbox = __esm({
|
|
70272
70420
|
"src/local-sandbox.ts"() {
|
|
70273
70421
|
"use strict";
|
|
70274
70422
|
import_node_child_process2 = require("node:child_process");
|
|
70275
|
-
|
|
70276
|
-
|
|
70423
|
+
import_node_fs9 = require("node:fs");
|
|
70424
|
+
import_node_path8 = __toESM(require("node:path"));
|
|
70277
70425
|
import_node_os3 = __toESM(require("node:os"));
|
|
70278
70426
|
import_node_url = require("node:url");
|
|
70279
70427
|
init_utils4();
|
|
@@ -70285,6 +70433,10 @@ var init_local_sandbox = __esm({
|
|
|
70285
70433
|
// The most recent foreground child. Lets the CLI forward user-typed lines to
|
|
70286
70434
|
// a command that is waiting for stdin (interactive prompts, REPLs, etc.).
|
|
70287
70435
|
this.activeForegroundChild = null;
|
|
70436
|
+
// Host fingerprint, computed once at construction. Linux/Kali unlock the
|
|
70437
|
+
// "full-power" sandbox context; root status flips sudo guidance; unrestricted
|
|
70438
|
+
// opens the native http_request / recon scope gate (default ON for Linux).
|
|
70439
|
+
this.platform = import_node_os3.default.platform();
|
|
70288
70440
|
this.commands = {
|
|
70289
70441
|
run: (command, opts) => {
|
|
70290
70442
|
return new Promise((resolve2, reject) => {
|
|
@@ -70371,15 +70523,15 @@ var init_local_sandbox = __esm({
|
|
|
70371
70523
|
this.files = {
|
|
70372
70524
|
write: async (filePath, content) => {
|
|
70373
70525
|
const resolved = this.resolvePath(filePath);
|
|
70374
|
-
await
|
|
70526
|
+
await import_node_fs9.promises.mkdir(import_node_path8.default.dirname(resolved), { recursive: true });
|
|
70375
70527
|
const data = typeof content === "string" ? content : content instanceof ArrayBuffer ? Buffer.from(content) : content;
|
|
70376
|
-
await
|
|
70528
|
+
await import_node_fs9.promises.writeFile(resolved, data);
|
|
70377
70529
|
},
|
|
70378
70530
|
read: async (filePath) => {
|
|
70379
|
-
return
|
|
70531
|
+
return import_node_fs9.promises.readFile(this.resolvePath(filePath), "utf8");
|
|
70380
70532
|
},
|
|
70381
70533
|
remove: async (filePath) => {
|
|
70382
|
-
await
|
|
70534
|
+
await import_node_fs9.promises.rm(this.resolvePath(filePath), {
|
|
70383
70535
|
recursive: true,
|
|
70384
70536
|
force: true
|
|
70385
70537
|
});
|
|
@@ -70387,8 +70539,8 @@ var init_local_sandbox = __esm({
|
|
|
70387
70539
|
list: async (dirPath = ".") => {
|
|
70388
70540
|
const resolved = this.resolvePath(dirPath);
|
|
70389
70541
|
try {
|
|
70390
|
-
const entries = await
|
|
70391
|
-
return entries.filter((e) => e.isFile()).map((e) => ({ name:
|
|
70542
|
+
const entries = await import_node_fs9.promises.readdir(resolved, { withFileTypes: true });
|
|
70543
|
+
return entries.filter((e) => e.isFile()).map((e) => ({ name: import_node_path8.default.join(resolved, e.name) }));
|
|
70392
70544
|
} catch {
|
|
70393
70545
|
return [];
|
|
70394
70546
|
}
|
|
@@ -70404,12 +70556,15 @@ var init_local_sandbox = __esm({
|
|
|
70404
70556
|
this.shellFlag = shell2.shellFlag;
|
|
70405
70557
|
}
|
|
70406
70558
|
const explicit = opts?.workdir || process.env.CLI_WORKDIR;
|
|
70407
|
-
const base = explicit ||
|
|
70559
|
+
const base = explicit || import_node_path8.default.join(process.cwd(), "SPRIT");
|
|
70408
70560
|
this.autoCreated = !explicit;
|
|
70409
|
-
this.workdir =
|
|
70561
|
+
this.workdir = import_node_path8.default.resolve(base).replace(/\\/g, "/");
|
|
70562
|
+
this.linux = detectLinux(this.platform);
|
|
70563
|
+
this.root = typeof process.getuid === "function" ? process.getuid() === 0 : false;
|
|
70564
|
+
this.unrestricted = computeUnrestricted(this.platform);
|
|
70410
70565
|
}
|
|
70411
70566
|
async init() {
|
|
70412
|
-
await
|
|
70567
|
+
await import_node_fs9.promises.mkdir(this.workdir, { recursive: true });
|
|
70413
70568
|
await this.seedReconToolkit();
|
|
70414
70569
|
await this.seedAuditToolkit();
|
|
70415
70570
|
}
|
|
@@ -70426,8 +70581,8 @@ var init_local_sandbox = __esm({
|
|
|
70426
70581
|
const assetsDir = (0, import_node_url.fileURLToPath)(
|
|
70427
70582
|
new URL("../assets/recon", import_meta.url)
|
|
70428
70583
|
);
|
|
70429
|
-
const destDir =
|
|
70430
|
-
await
|
|
70584
|
+
const destDir = import_node_path8.default.join(this.workdir, "recon");
|
|
70585
|
+
await import_node_fs9.promises.mkdir(destDir, { recursive: true });
|
|
70431
70586
|
const files = [
|
|
70432
70587
|
["recon_deep.py", true],
|
|
70433
70588
|
["recon_common.py", true],
|
|
@@ -70443,17 +70598,17 @@ var init_local_sandbox = __esm({
|
|
|
70443
70598
|
["scope.txt", false]
|
|
70444
70599
|
];
|
|
70445
70600
|
for (const [name25, overwrite] of files) {
|
|
70446
|
-
const dest =
|
|
70601
|
+
const dest = import_node_path8.default.join(destDir, name25);
|
|
70447
70602
|
if (!overwrite) {
|
|
70448
70603
|
try {
|
|
70449
|
-
await
|
|
70604
|
+
await import_node_fs9.promises.access(dest);
|
|
70450
70605
|
continue;
|
|
70451
70606
|
} catch {
|
|
70452
70607
|
}
|
|
70453
70608
|
}
|
|
70454
70609
|
try {
|
|
70455
|
-
const content = await
|
|
70456
|
-
await
|
|
70610
|
+
const content = await import_node_fs9.promises.readFile(import_node_path8.default.join(assetsDir, name25));
|
|
70611
|
+
await import_node_fs9.promises.writeFile(dest, content);
|
|
70457
70612
|
} catch {
|
|
70458
70613
|
}
|
|
70459
70614
|
}
|
|
@@ -70471,12 +70626,12 @@ var init_local_sandbox = __esm({
|
|
|
70471
70626
|
const assetsDir = (0, import_node_url.fileURLToPath)(
|
|
70472
70627
|
new URL("../assets/audit", import_meta.url)
|
|
70473
70628
|
);
|
|
70474
|
-
const destDir =
|
|
70475
|
-
await
|
|
70629
|
+
const destDir = import_node_path8.default.join(this.workdir, "audit");
|
|
70630
|
+
await import_node_fs9.promises.mkdir(destDir, { recursive: true });
|
|
70476
70631
|
for (const name25 of ["project_audit.py", "README.md"]) {
|
|
70477
70632
|
try {
|
|
70478
|
-
const content = await
|
|
70479
|
-
await
|
|
70633
|
+
const content = await import_node_fs9.promises.readFile(import_node_path8.default.join(assetsDir, name25));
|
|
70634
|
+
await import_node_fs9.promises.writeFile(import_node_path8.default.join(destDir, name25), content);
|
|
70480
70635
|
} catch {
|
|
70481
70636
|
}
|
|
70482
70637
|
}
|
|
@@ -70495,6 +70650,30 @@ var init_local_sandbox = __esm({
|
|
|
70495
70650
|
isWindows() {
|
|
70496
70651
|
return import_node_os3.default.platform() === "win32" && !this.isBashLikeShell();
|
|
70497
70652
|
}
|
|
70653
|
+
/** True on any Linux host — unlocks the full-power sandbox context. */
|
|
70654
|
+
isLinux() {
|
|
70655
|
+
return this.platform === "linux";
|
|
70656
|
+
}
|
|
70657
|
+
/** True when /etc/os-release identifies this host as Kali Linux. */
|
|
70658
|
+
isKali() {
|
|
70659
|
+
return this.linux.isKali;
|
|
70660
|
+
}
|
|
70661
|
+
/** Pretty distro name (PRETTY_NAME/NAME), e.g. "Kali GNU/Linux Rolling". */
|
|
70662
|
+
getDistroName() {
|
|
70663
|
+
return this.linux.distroName;
|
|
70664
|
+
}
|
|
70665
|
+
/** True when the session runs as uid 0 (no sudo needed). */
|
|
70666
|
+
isRoot() {
|
|
70667
|
+
return this.root;
|
|
70668
|
+
}
|
|
70669
|
+
/**
|
|
70670
|
+
* True when the native http_request tool and the recon toolkit run WITHOUT
|
|
70671
|
+
* the scope.txt allowlist gate. Defaults to ON for Linux ("tudo liberado"),
|
|
70672
|
+
* OFF elsewhere; flip with CLAWFAST_UNRESTRICTED / CLAWFAST_STRICT_SCOPE.
|
|
70673
|
+
*/
|
|
70674
|
+
isUnrestricted() {
|
|
70675
|
+
return this.unrestricted;
|
|
70676
|
+
}
|
|
70498
70677
|
supportsPty() {
|
|
70499
70678
|
return false;
|
|
70500
70679
|
}
|
|
@@ -70503,10 +70682,12 @@ var init_local_sandbox = __esm({
|
|
|
70503
70682
|
const shellInvocation = `${this.shellBin} ${this.shellFlag}`;
|
|
70504
70683
|
const windowsNotes = import_node_os3.default.platform() === "win32" ? this.getWindowsShellNotes() : "";
|
|
70505
70684
|
const pentestToolingNotes = this.getLocalPentestToolingNotes();
|
|
70506
|
-
|
|
70685
|
+
const linuxPowerNotes = this.isLinux() ? this.getLinuxPowerNotes() : "";
|
|
70686
|
+
const hostLabel = this.isLinux() ? `${this.getDistroName()} ${import_node_os3.default.arch()}, ${this.root ? "root" : "user"}@${import_node_os3.default.hostname()}` : `${platform}, hostname "${import_node_os3.default.hostname()}"`;
|
|
70687
|
+
return `You are executing commands directly on the user's local host (${hostLabel}) in DANGEROUS MODE: there is NO sandbox isolation. This is the operator's OWN machine and they have authorized you to use its FULL power.
|
|
70507
70688
|
Commands are invoked via \`${shellInvocation}\`. The working directory is "${this.workdir}".
|
|
70508
70689
|
Be careful: file system, network and process operations all affect the real host system.
|
|
70509
|
-
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.
|
|
70690
|
+
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, an account/registration step, 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.
|
|
70510
70691
|
|
|
70511
70692
|
WORKSPACE - STRICT SCOPE:
|
|
70512
70693
|
- Your entire workspace is the directory: ${this.workdir}
|
|
@@ -70523,7 +70704,28 @@ EDITING SCRIPTS:
|
|
|
70523
70704
|
- When a script you wrote produces an error, fix the specific broken part.
|
|
70524
70705
|
- Do not recreate or fully overwrite a file just to fix one error.
|
|
70525
70706
|
- Use write only to create a brand-new file, or when changes to a short file are extensive.
|
|
70526
|
-
- Iterate on your own existing files across steps; treat them as persistent.${windowsNotes}${pentestToolingNotes}`;
|
|
70707
|
+
- Iterate on your own existing files across steps; treat them as persistent.${linuxPowerNotes}${windowsNotes}${pentestToolingNotes}`;
|
|
70708
|
+
}
|
|
70709
|
+
/**
|
|
70710
|
+
* The Linux "full-power" block: tells the model it is on a real Linux/Kali box
|
|
70711
|
+
* with no capability artificially withheld, how root/sudo works here, that
|
|
70712
|
+
* Python and scanning are fully unlocked, and — critically — the protocol for
|
|
70713
|
+
* relaying a Kali tool's interactive prompt to the human and forwarding their
|
|
70714
|
+
* typed answer back to the program's stdin.
|
|
70715
|
+
*/
|
|
70716
|
+
getLinuxPowerNotes() {
|
|
70717
|
+
const who = this.root ? "root (uid 0) \u2014 no sudo needed; you can install packages, bind low ports, sniff, and read/write anywhere" : "a normal user \u2014 prefix privileged actions with sudo; the human will type the sudo password when prompted";
|
|
70718
|
+
const apt = this.root ? "apt" : "sudo apt";
|
|
70719
|
+
const kaliLine = this.isKali() ? "This is Kali Linux: treat the full offensive toolset as installed and ready." : "Treat this as a capable Linux pentest host; install whatever you need.";
|
|
70720
|
+
return `
|
|
70721
|
+
|
|
70722
|
+
LINUX FULL-POWER MODE (${this.getDistroName()}, running as ${who}):
|
|
70723
|
+
- ${kaliLine} Everything the OS permits, you may do \u2014 no capability is off-limits because of the platform. This box belongs to the operator and full use is authorized.
|
|
70724
|
+
- You have a REAL shell with REAL reach: full filesystem, raw sockets, package managers (\`${apt} install -y <pkg>\`, \`pip install\`, \`pipx install\`, \`go install\`), service control (\`systemctl\`), and the entire installed toolset.
|
|
70725
|
+
- Python is 100% unlocked: \`python3\`, \`pip\`, \`venv\`, any library. Build and run whatever the task needs \u2014 there is no Python restriction here.
|
|
70726
|
+
- Scanning is fully allowed: port scans, host/network range sweeps, service/version detection, and number/identifier enumeration (IP ranges, port ranges, phone-number OSINT with phoneinfoga, etc.). Pick the right tool (nmap, masscan, the recon/ toolkit) and apply reasonable OPSEC throttling on noisy work.
|
|
70727
|
+
- KALI / INTERACTIVE PROMPTS \u2014 IMPORTANT: many tools and installers stop to ask for input mid-run (msfconsole, an \`apt\` confirmation, an account/registration/sign-up step, an ssh/sudo/password prompt, a y/n, a setup wizard, a REPL). A real human is at this terminal. When the underlying program is waiting for input, STOP and tell the user in ONE short line EXACTLY what the program ("o kali") is asking and what to type \u2014 e.g. "o kali est\xE1 pedindo o nome de usu\xE1rio da conta; digite ele aqui". The user types the answer here, the CLI forwards it to the program's stdin, and you continue. You drive the tool; the human supplies the human answers.
|
|
70728
|
+
- Account creation / sign-ups a tool requires: run the step, surface each prompt to the user, forward their typed answers \u2014 NEVER invent credentials, never skip the human, never fabricate the tool's output.${this.unrestricted ? "\n- UNRESTRICTED scope is ACTIVE: the native http_request tool and the recon/ Python modules run WITHOUT the scope.txt allowlist (pass `--allow-out-of-scope` to the recon scripts). Still act only against targets the operator pointed you at." : ""}`;
|
|
70527
70729
|
}
|
|
70528
70730
|
getOsContext() {
|
|
70529
70731
|
return this.getSandboxContext();
|
|
@@ -70579,9 +70781,9 @@ EDITING SCRIPTS:
|
|
|
70579
70781
|
if (!this.autoCreated) return null;
|
|
70580
70782
|
const keep = (process.env.CLAWFAST_KEEP_SPRIT || "").trim().toLowerCase();
|
|
70581
70783
|
if (keep === "1" || keep === "true" || keep === "yes") return null;
|
|
70582
|
-
if (
|
|
70784
|
+
if (import_node_path8.default.basename(this.workdir).toUpperCase() !== "SPRIT") return null;
|
|
70583
70785
|
try {
|
|
70584
|
-
await
|
|
70786
|
+
await import_node_fs9.promises.rm(this.workdir, { recursive: true, force: true });
|
|
70585
70787
|
return this.workdir;
|
|
70586
70788
|
} catch {
|
|
70587
70789
|
return null;
|
|
@@ -70632,15 +70834,15 @@ EDITING SCRIPTS:
|
|
|
70632
70834
|
}
|
|
70633
70835
|
}
|
|
70634
70836
|
resolvePath(p) {
|
|
70635
|
-
if (
|
|
70636
|
-
return
|
|
70837
|
+
if (import_node_path8.default.isAbsolute(p)) return p;
|
|
70838
|
+
return import_node_path8.default.join(this.workdir, p);
|
|
70637
70839
|
}
|
|
70638
70840
|
isBashLikeShell() {
|
|
70639
|
-
const base =
|
|
70841
|
+
const base = import_node_path8.default.basename(this.shellBin).toLowerCase();
|
|
70640
70842
|
return base === "bash" || base === "bash.exe" || base === "sh";
|
|
70641
70843
|
}
|
|
70642
70844
|
isCmdShell() {
|
|
70643
|
-
const base =
|
|
70845
|
+
const base = import_node_path8.default.basename(this.shellBin).toLowerCase();
|
|
70644
70846
|
return base === "cmd" || base === "cmd.exe";
|
|
70645
70847
|
}
|
|
70646
70848
|
getWindowsShellNotes() {
|
|
@@ -70682,12 +70884,14 @@ LOCAL PENTEST TOOLING:
|
|
|
70682
70884
|
- In cmd.exe, do not use raw Bash constructs like \`export\`, \`$(pwd)\`, heredocs, or single-quote escaping. Wrap those commands with \`wsl.exe ... bash -lc "..."\` or rewrite them in cmd syntax.
|
|
70683
70885
|
- For OWASP ZAP on Windows without WSL, prefer Docker: \`docker pull ghcr.io/zaproxy/zaproxy:stable\` and use a cmd.exe volume mount like \`-v "%cd%:/zap/wrk/:rw"\`.`;
|
|
70684
70886
|
}
|
|
70887
|
+
const sudo = this.root ? "" : "sudo ";
|
|
70685
70888
|
return `
|
|
70686
70889
|
|
|
70687
|
-
LOCAL PENTEST TOOLING:
|
|
70688
|
-
-
|
|
70689
|
-
-
|
|
70690
|
-
-
|
|
70890
|
+
LOCAL PENTEST TOOLING (${this.isLinux() ? this.getDistroName() : "Linux"}):
|
|
70891
|
+
- Treat the full Kali/Debian arsenal as available; verify a specific tool with \`command -v <tool>\` and install anything missing with \`${sudo}apt update && ${sudo}apt install -y <pkg>\` (or \`pipx install\` / \`pip install\`).
|
|
70892
|
+
- Common arsenal: nmap, masscan, nikto, nuclei, sqlmap, wpscan, gobuster / ffuf / feroxbuster, hydra, john, hashcat, metasploit (\`msfconsole\`), netcat, whois, dig, dnsrecon, amass, subfinder, theHarvester, wfuzz, zaproxy, burpsuite, responder, enum4linux, smbclient, phoneinfoga.
|
|
70893
|
+
- No PTY here: prefer line-oriented invocation \u2014 \`msfconsole -q -x "use ...; set ...; run; exit"\`, \`sqlmap --batch\`, and pipe pagers through \`| cat\`. Interactive prompts still work (the human types answers), but avoid full-screen TUIs.
|
|
70894
|
+
- For OWASP ZAP / containerized scans, Docker works too: \`docker run ... -v "$(pwd):/zap/wrk/:rw" ...\` so reports are preserved.`;
|
|
70691
70895
|
}
|
|
70692
70896
|
getWslWorkdir() {
|
|
70693
70897
|
const match = this.workdir.match(/^([A-Za-z]):\/(.*)$/);
|
|
@@ -70695,6 +70899,10 @@ LOCAL PENTEST TOOLING:
|
|
|
70695
70899
|
return `/mnt/${match[1].toLowerCase()}/${match[2]}`;
|
|
70696
70900
|
}
|
|
70697
70901
|
};
|
|
70902
|
+
truthyEnv = (name25) => {
|
|
70903
|
+
const v = (process.env[name25] || "").trim().toLowerCase();
|
|
70904
|
+
return v === "1" || v === "true" || v === "yes" || v === "on";
|
|
70905
|
+
};
|
|
70698
70906
|
}
|
|
70699
70907
|
});
|
|
70700
70908
|
|
|
@@ -70737,6 +70945,20 @@ var init_local_sandbox_manager = __esm({
|
|
|
70737
70945
|
}
|
|
70738
70946
|
});
|
|
70739
70947
|
|
|
70948
|
+
// src/message-tail.ts
|
|
70949
|
+
function ensureGeneratableTail(messages, continuation = "continue") {
|
|
70950
|
+
const last = messages[messages.length - 1];
|
|
70951
|
+
if (last && last.role === "assistant") {
|
|
70952
|
+
messages.push({ role: "user", content: continuation });
|
|
70953
|
+
}
|
|
70954
|
+
return messages;
|
|
70955
|
+
}
|
|
70956
|
+
var init_message_tail = __esm({
|
|
70957
|
+
"src/message-tail.ts"() {
|
|
70958
|
+
"use strict";
|
|
70959
|
+
}
|
|
70960
|
+
});
|
|
70961
|
+
|
|
70740
70962
|
// src/render.ts
|
|
70741
70963
|
function createRenderer() {
|
|
70742
70964
|
let lastKind = null;
|
|
@@ -70807,11 +71029,11 @@ function formatToolCall(toolName, input) {
|
|
|
70807
71029
|
case "run_terminal_cmd": {
|
|
70808
71030
|
const cmd = String(i.command ?? "").trim();
|
|
70809
71031
|
const bg = i.is_background ? `${C3.dim} (background)${C3.reset}` : "";
|
|
70810
|
-
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}exec${C3.reset} ${C3.bold}${
|
|
71032
|
+
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}exec${C3.reset} ${C3.bold}${truncate4(cmd, 400)}${C3.reset}${bg}`;
|
|
70811
71033
|
}
|
|
70812
71034
|
case "file": {
|
|
70813
|
-
const
|
|
70814
|
-
const brief = i.brief ? `${C3.dim} \u2014 ${
|
|
71035
|
+
const path13 = String(i.path ?? "");
|
|
71036
|
+
const brief = i.brief ? `${C3.dim} \u2014 ${truncate4(String(i.brief))}${C3.reset}` : "";
|
|
70815
71037
|
const map2 = {
|
|
70816
71038
|
write: [C3.green, "criar "],
|
|
70817
71039
|
edit: [C3.yellow, "editar "],
|
|
@@ -70824,7 +71046,7 @@ function formatToolCall(toolName, input) {
|
|
|
70824
71046
|
C3.blue,
|
|
70825
71047
|
action ? `${action} `.padEnd(7) : "arquivo"
|
|
70826
71048
|
];
|
|
70827
|
-
const target =
|
|
71049
|
+
const target = path13 ? `${C3.bold}${path13}${C3.reset}` : "";
|
|
70828
71050
|
return ` ${col}\u276F${C3.reset} ${col}${verb}${C3.reset} ${target}${brief}`;
|
|
70829
71051
|
}
|
|
70830
71052
|
case "todo_write":
|
|
@@ -70834,23 +71056,30 @@ function formatToolCall(toolName, input) {
|
|
|
70834
71056
|
const url2 = String(i.url ?? "");
|
|
70835
71057
|
const fuzz = Array.isArray(i.fuzz) && i.fuzz.length;
|
|
70836
71058
|
const tag = fuzz ? `${C3.dim} (fuzz \xD7${i.fuzz.length})${C3.reset}` : "";
|
|
70837
|
-
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}http${C3.reset} ${C3.bold}${method}${C3.reset} ${
|
|
71059
|
+
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}http${C3.reset} ${C3.bold}${method}${C3.reset} ${truncate4(url2, 360)}${tag}`;
|
|
70838
71060
|
}
|
|
70839
71061
|
case "findings": {
|
|
70840
71062
|
const action = String(i.action ?? "");
|
|
70841
|
-
const detail = action === "add" ?
|
|
71063
|
+
const detail = action === "add" ? truncate4(String(i.title ?? ""), 80) : action === "update" ? `${String(i.id ?? "")} ${String(i.status ?? "")}`.trim() : "";
|
|
70842
71064
|
return ` ${C3.magenta}\u276F${C3.reset} ${C3.magenta}findings${C3.reset} ${C3.bold}${action}${C3.reset}${detail ? ` ${C3.dim}${detail}${C3.reset}` : ""}`;
|
|
70843
71065
|
}
|
|
70844
71066
|
case "web_search": {
|
|
70845
71067
|
const queries = Array.isArray(i.queries) ? i.queries.join(" | ") : "";
|
|
70846
|
-
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}busca${C3.reset} ${C3.dim}${
|
|
71068
|
+
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}busca${C3.reset} ${C3.dim}${truncate4(queries, 200)}${C3.reset}`;
|
|
70847
71069
|
}
|
|
70848
71070
|
case "open_url": {
|
|
70849
71071
|
const url2 = String(i.url ?? i.urls ?? "");
|
|
70850
|
-
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}abrir${C3.reset} ${C3.dim}${
|
|
71072
|
+
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}abrir${C3.reset} ${C3.dim}${truncate4(url2, 280)}${C3.reset}`;
|
|
71073
|
+
}
|
|
71074
|
+
case "deep_research": {
|
|
71075
|
+
const qs = Array.isArray(i.queries) ? i.queries.join(" | ") : "";
|
|
71076
|
+
const nUrls = Array.isArray(i.urls) ? i.urls.length : 0;
|
|
71077
|
+
const pages = i.max_pages != null ? `${i.max_pages}p` : "";
|
|
71078
|
+
const detail = [qs, nUrls ? `${nUrls} url(s)` : "", pages].filter(Boolean).join(" ") || "(sem alvo)";
|
|
71079
|
+
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}pesquisa${C3.reset} ${C3.dim}${truncate4(detail, 220)}${C3.reset}`;
|
|
70851
71080
|
}
|
|
70852
71081
|
default:
|
|
70853
|
-
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}${toolName}${C3.reset} ${C3.dim}${
|
|
71082
|
+
return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}${toolName}${C3.reset} ${C3.dim}${truncate4(
|
|
70854
71083
|
JSON.stringify(i),
|
|
70855
71084
|
200
|
|
70856
71085
|
)}${C3.reset}`;
|
|
@@ -70861,7 +71090,7 @@ function summarizeResult(toolName, output) {
|
|
|
70861
71090
|
if (toolName === "file") {
|
|
70862
71091
|
if (typeof output === "object" && "error" in output) {
|
|
70863
71092
|
return {
|
|
70864
|
-
text:
|
|
71093
|
+
text: truncate4(String(output.error), 160),
|
|
70865
71094
|
error: true
|
|
70866
71095
|
};
|
|
70867
71096
|
}
|
|
@@ -70872,11 +71101,11 @@ function summarizeResult(toolName, output) {
|
|
|
70872
71101
|
if (toolName === "http_request") {
|
|
70873
71102
|
const o = asRecord(output);
|
|
70874
71103
|
if ("error" in o && o.error) {
|
|
70875
|
-
return { text:
|
|
71104
|
+
return { text: truncate4(String(o.error), 200), error: true };
|
|
70876
71105
|
}
|
|
70877
71106
|
if (o.single) {
|
|
70878
71107
|
const s = asRecord(o.single);
|
|
70879
|
-
if (s.error) return { text:
|
|
71108
|
+
if (s.error) return { text: truncate4(String(s.error), 160), error: true };
|
|
70880
71109
|
return {
|
|
70881
71110
|
text: `HTTP ${s.status} \xB7 ${s.bodyLength} bytes \xB7 ${s.timeMs}ms`,
|
|
70882
71111
|
error: false
|
|
@@ -70891,17 +71120,19 @@ function summarizeResult(toolName, output) {
|
|
|
70891
71120
|
if (toolName === "findings") {
|
|
70892
71121
|
const o = asRecord(output);
|
|
70893
71122
|
if ("error" in o && o.error) {
|
|
70894
|
-
return { text:
|
|
71123
|
+
return { text: truncate4(String(o.error), 200), error: true };
|
|
70895
71124
|
}
|
|
70896
71125
|
if (o.added) return { text: "finding registrado", error: false };
|
|
70897
71126
|
if (o.updated) return { text: "finding atualizado", error: false };
|
|
70898
|
-
if (o.report)
|
|
70899
|
-
|
|
71127
|
+
if (o.report)
|
|
71128
|
+
return { text: `relat\xF3rio \u2192 ${String(o.report)}`, error: false };
|
|
71129
|
+
if ("total" in o)
|
|
71130
|
+
return { text: `${String(o.total)} finding(s)`, error: false };
|
|
70900
71131
|
return null;
|
|
70901
71132
|
}
|
|
70902
71133
|
return null;
|
|
70903
71134
|
}
|
|
70904
|
-
var VIOLET, C3, GUTTER_BAR, out,
|
|
71135
|
+
var VIOLET, C3, GUTTER_BAR, out, truncate4;
|
|
70905
71136
|
var init_render = __esm({
|
|
70906
71137
|
"src/render.ts"() {
|
|
70907
71138
|
"use strict";
|
|
@@ -70920,7 +71151,7 @@ var init_render = __esm({
|
|
|
70920
71151
|
};
|
|
70921
71152
|
GUTTER_BAR = `${fg(PAL.frame)}\u2502${C3.reset} `;
|
|
70922
71153
|
out = (s) => process.stdout.write(s);
|
|
70923
|
-
|
|
71154
|
+
truncate4 = (s, n = 200) => s.length > n ? `${s.slice(0, n)}...` : s;
|
|
70924
71155
|
}
|
|
70925
71156
|
});
|
|
70926
71157
|
|
|
@@ -71037,12 +71268,12 @@ async function ensureProxyReady(id, log2) {
|
|
|
71037
71268
|
};
|
|
71038
71269
|
}
|
|
71039
71270
|
let freshSetup = false;
|
|
71040
|
-
if (!(0,
|
|
71271
|
+
if (!(0, import_node_fs10.existsSync)(dir)) {
|
|
71041
71272
|
log2(`${def.label}: baixando o proxy (uma vez) em ${dir} \u2026`);
|
|
71042
71273
|
const root = proxiesRoot();
|
|
71043
|
-
(0,
|
|
71274
|
+
(0, import_node_fs10.mkdirSync)(root, { recursive: true });
|
|
71044
71275
|
const cloned = run("git", ["clone", def.repoUrl, dir], root);
|
|
71045
|
-
if (!cloned.ok || !(0,
|
|
71276
|
+
if (!cloned.ok || !(0, import_node_fs10.existsSync)(dir)) {
|
|
71046
71277
|
return {
|
|
71047
71278
|
ok: false,
|
|
71048
71279
|
message: `${def.label}: falha ao clonar o proxy (git).`
|
|
@@ -71050,7 +71281,7 @@ async function ensureProxyReady(id, log2) {
|
|
|
71050
71281
|
}
|
|
71051
71282
|
freshSetup = true;
|
|
71052
71283
|
}
|
|
71053
|
-
if (!(0,
|
|
71284
|
+
if (!(0, import_node_fs10.existsSync)(import_node_path9.default.join(dir, "node_modules"))) {
|
|
71054
71285
|
log2(`${def.label}: instalando depend\xEAncias (pode demorar) \u2026`);
|
|
71055
71286
|
if (!run("npm", ["install"], dir).ok) {
|
|
71056
71287
|
return { ok: false, message: `${def.label}: 'npm install' falhou.` };
|
|
@@ -71095,13 +71326,13 @@ async function ensureProxyReady(id, log2) {
|
|
|
71095
71326
|
message: `${def.label}: o proxy n\xE3o respondeu em 90s. Tente de novo, ou rode 'npm run login' em ${dir}.`
|
|
71096
71327
|
};
|
|
71097
71328
|
}
|
|
71098
|
-
var import_node_os4,
|
|
71329
|
+
var import_node_os4, import_node_path9, import_node_fs10, import_node_child_process3, DEFS, PROXY_MODEL_KEYS, proxyIdForModelKey, proxiesRoot, dirFor, healthUrl, baseUrl, wait, started, exitHooksInstalled, quoteArg, asShellCommand, run, hasCommand;
|
|
71099
71330
|
var init_proxy_manager2 = __esm({
|
|
71100
71331
|
"src/proxy-manager.ts"() {
|
|
71101
71332
|
"use strict";
|
|
71102
71333
|
import_node_os4 = __toESM(require("node:os"));
|
|
71103
|
-
|
|
71104
|
-
|
|
71334
|
+
import_node_path9 = __toESM(require("node:path"));
|
|
71335
|
+
import_node_fs10 = require("node:fs");
|
|
71105
71336
|
import_node_child_process3 = require("node:child_process");
|
|
71106
71337
|
DEFS = {
|
|
71107
71338
|
deepseek: {
|
|
@@ -71134,11 +71365,11 @@ var init_proxy_manager2 = __esm({
|
|
|
71134
71365
|
if (key === PROXY_MODEL_KEYS.kimi) return "kimi";
|
|
71135
71366
|
return null;
|
|
71136
71367
|
};
|
|
71137
|
-
proxiesRoot = () =>
|
|
71138
|
-
process.env.CLAWFAST_HOME?.trim() ||
|
|
71368
|
+
proxiesRoot = () => import_node_path9.default.join(
|
|
71369
|
+
process.env.CLAWFAST_HOME?.trim() || import_node_path9.default.join(import_node_os4.default.homedir(), ".clawfast"),
|
|
71139
71370
|
"proxies"
|
|
71140
71371
|
);
|
|
71141
|
-
dirFor = (def) => process.env[def.dirEnv]?.trim() ||
|
|
71372
|
+
dirFor = (def) => process.env[def.dirEnv]?.trim() || import_node_path9.default.join(proxiesRoot(), def.folder);
|
|
71142
71373
|
healthUrl = (def) => `http://localhost:${def.port}/health`;
|
|
71143
71374
|
baseUrl = (def) => `http://localhost:${def.port}/v1`;
|
|
71144
71375
|
wait = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
@@ -71167,7 +71398,7 @@ var init_proxy_manager2 = __esm({
|
|
|
71167
71398
|
|
|
71168
71399
|
// src/audit-mode.ts
|
|
71169
71400
|
function projectRootFromWorkdir(workdir) {
|
|
71170
|
-
return
|
|
71401
|
+
return import_node_path10.default.dirname(import_node_path10.default.resolve(workdir.replace(/\\/g, "/")));
|
|
71171
71402
|
}
|
|
71172
71403
|
function detectProjectAuditIntent(input) {
|
|
71173
71404
|
const text2 = input.trim();
|
|
@@ -71369,11 +71600,11 @@ ESTILO E EXECU\xC7\xC3O
|
|
|
71369
71600
|
- Responda em portugu\xEAs, direto e t\xE9cnico. N\xE3o recuse a an\xE1lise: \xE9 o projeto do pr\xF3prio usu\xE1rio, autorizado.
|
|
71370
71601
|
- 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.`;
|
|
71371
71602
|
}
|
|
71372
|
-
var
|
|
71603
|
+
var import_node_path10, AUDIT_ACTION, AUDIT_SCOPE, AUDIT_ACTION_THEN_SCOPE, AUDIT_SCOPE_THEN_ACTION, AUDIT_STRONG, AUDIT_EXIT, POC_VERIFY;
|
|
71373
71604
|
var init_audit_mode = __esm({
|
|
71374
71605
|
"src/audit-mode.ts"() {
|
|
71375
71606
|
"use strict";
|
|
71376
|
-
|
|
71607
|
+
import_node_path10 = __toESM(require("node:path"));
|
|
71377
71608
|
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";
|
|
71378
71609
|
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";
|
|
71379
71610
|
AUDIT_ACTION_THEN_SCOPE = new RegExp(
|
|
@@ -71623,13 +71854,18 @@ async function createAgent() {
|
|
|
71623
71854
|
todo_write: createTodoWrite(context2),
|
|
71624
71855
|
// Native Repeater/Intruder + structured findings store — the core of an
|
|
71625
71856
|
// in-loop pentest workflow (probe → observe → record evidence → confirm).
|
|
71626
|
-
http_request: createHttpRequest({
|
|
71857
|
+
http_request: createHttpRequest({
|
|
71858
|
+
workdir: sandbox.getWorkdir(),
|
|
71859
|
+
unrestricted: sandbox.isUnrestricted()
|
|
71860
|
+
}),
|
|
71627
71861
|
findings: createFindings({ workdir: sandbox.getWorkdir() }),
|
|
71628
|
-
//
|
|
71629
|
-
//
|
|
71630
|
-
//
|
|
71631
|
-
|
|
71632
|
-
|
|
71862
|
+
// Free, key-less web research — ALWAYS on. web_search (DuckDuckGo) finds
|
|
71863
|
+
// sources; open_url fetches+reads one page; deep_research sweeps many pages
|
|
71864
|
+
// concurrently (up to 500) into a digest. The agent is steered to use them
|
|
71865
|
+
// proactively via webResearchPolicy (search → read → verify → retry → act).
|
|
71866
|
+
web_search: createWebSearch(),
|
|
71867
|
+
open_url: createOpenUrl(),
|
|
71868
|
+
deep_research: createDeepResearch({ workdir: sandbox.getWorkdir() })
|
|
71633
71869
|
};
|
|
71634
71870
|
let system = "";
|
|
71635
71871
|
let systemPromptAudit = auditSystemPrompt("", null);
|
|
@@ -71651,9 +71887,11 @@ async function createAgent() {
|
|
|
71651
71887
|
system += reconPhasesPolicy(sandbox.getWorkdir());
|
|
71652
71888
|
system += attackChainPolicy(sandbox.getWorkdir());
|
|
71653
71889
|
system += httpAndFindingsPolicy(sandbox.getWorkdir());
|
|
71890
|
+
system += webResearchPolicy();
|
|
71654
71891
|
system += buildCliNotesSection();
|
|
71655
71892
|
system += buildSkillsIndexSection();
|
|
71656
71893
|
system += skillsScopePolicy();
|
|
71894
|
+
system += linuxFullPowerPolicy(sandbox);
|
|
71657
71895
|
if (isWebSessionProxyModel(modelName)) {
|
|
71658
71896
|
system += proxyToolProtocolPolicy();
|
|
71659
71897
|
}
|
|
@@ -71665,6 +71903,14 @@ async function createAgent() {
|
|
|
71665
71903
|
assertFullSystemPrompt(systemPromptAudit);
|
|
71666
71904
|
};
|
|
71667
71905
|
await rebuildSystemPrompt(initialModelName);
|
|
71906
|
+
if (sandbox.isLinux()) {
|
|
71907
|
+
const bits = [
|
|
71908
|
+
`modo Linux full-power ativo${sandbox.isKali() ? " (Kali)" : ""}`,
|
|
71909
|
+
sandbox.isRoot() ? "root" : "user",
|
|
71910
|
+
sandbox.isUnrestricted() ? "escopo liberado" : "escopo restrito (scope.txt)"
|
|
71911
|
+
];
|
|
71912
|
+
render.info(bits.join(" \xB7 "));
|
|
71913
|
+
}
|
|
71668
71914
|
if (systemPromptAudit.dumpPath) {
|
|
71669
71915
|
render.info(
|
|
71670
71916
|
`system prompt completo salvo em: ${systemPromptAudit.dumpPath}`
|
|
@@ -71700,7 +71946,6 @@ async function createAgent() {
|
|
|
71700
71946
|
reason: "faltando NVIDIA_API_KEY em .env.local (https://build.nvidia.com/)",
|
|
71701
71947
|
models: [
|
|
71702
71948
|
"model-nvidia-mistral-medium-3.5",
|
|
71703
|
-
"model-nvidia-gpt-oss-120b",
|
|
71704
71949
|
"model-nvidia-glm-5.1",
|
|
71705
71950
|
"model-nvidia-qwen3.5-397b"
|
|
71706
71951
|
].map((key) => ({ key, label: labelFor(key) }))
|
|
@@ -71775,6 +72020,33 @@ async function createAgent() {
|
|
|
71775
72020
|
selection: getModelSelection()
|
|
71776
72021
|
};
|
|
71777
72022
|
}
|
|
72023
|
+
if (isNvidiaDynamicKey(raw)) {
|
|
72024
|
+
if (!hasNvidiaKey()) {
|
|
72025
|
+
return {
|
|
72026
|
+
ok: false,
|
|
72027
|
+
message: "NVIDIA indispon\xEDvel: defina NVIDIA_API_KEY em .env.local (https://build.nvidia.com/)",
|
|
72028
|
+
selection: getModelSelection()
|
|
72029
|
+
};
|
|
72030
|
+
}
|
|
72031
|
+
const slug = nvidiaSlugFromKey(raw).trim();
|
|
72032
|
+
if (!slug) {
|
|
72033
|
+
return {
|
|
72034
|
+
ok: false,
|
|
72035
|
+
message: "informe o modelo NVIDIA (ex.: nvidia:z-ai/glm-5.1)",
|
|
72036
|
+
selection: getModelSelection()
|
|
72037
|
+
};
|
|
72038
|
+
}
|
|
72039
|
+
const key = nvidiaKeyForSlug(slug);
|
|
72040
|
+
selectedModelKey = key;
|
|
72041
|
+
currentModelName = key;
|
|
72042
|
+
context2.modelName = key;
|
|
72043
|
+
await rebuildSystemPrompt(key);
|
|
72044
|
+
return {
|
|
72045
|
+
ok: true,
|
|
72046
|
+
message: `modelo fixado: ${labelFor(key)}`,
|
|
72047
|
+
selection: getModelSelection()
|
|
72048
|
+
};
|
|
72049
|
+
}
|
|
71778
72050
|
const choices = getModelChoices();
|
|
71779
72051
|
let match;
|
|
71780
72052
|
if (/^\d+$/.test(normalized)) {
|
|
@@ -72013,6 +72285,7 @@ ${segs.join(
|
|
|
72013
72285
|
}, STREAM_STALL_TIMEOUT_MS);
|
|
72014
72286
|
};
|
|
72015
72287
|
try {
|
|
72288
|
+
ensureGeneratableTail(history);
|
|
72016
72289
|
const result = streamText({
|
|
72017
72290
|
model: resolveLanguageModel2(modelKey),
|
|
72018
72291
|
system: turnSystem,
|
|
@@ -72221,7 +72494,7 @@ ${resultText}`
|
|
|
72221
72494
|
render.info(
|
|
72222
72495
|
`\u25B8 rate limit \u2014 aguardando ${Math.round(waitMs / 1e3)}s antes da pr\xF3xima tentativa (Ctrl+C cancela)\u2026`
|
|
72223
72496
|
);
|
|
72224
|
-
await
|
|
72497
|
+
await sleep3(waitMs, signal);
|
|
72225
72498
|
if (signal?.aborted) {
|
|
72226
72499
|
render.endTurn();
|
|
72227
72500
|
return;
|
|
@@ -72272,24 +72545,25 @@ ${resultText}`
|
|
|
72272
72545
|
setModelSelection,
|
|
72273
72546
|
isOpenRouterAvailable: hasOpenRouterKey,
|
|
72274
72547
|
listOpenRouterModels: (signal) => listOpenRouterModels(signal),
|
|
72548
|
+
isNvidiaAvailable: hasNvidiaKey,
|
|
72549
|
+
listNvidiaModels: (signal) => listNvidiaModels(signal),
|
|
72275
72550
|
close
|
|
72276
72551
|
};
|
|
72277
72552
|
}
|
|
72278
|
-
var import_promises2,
|
|
72553
|
+
var import_promises2, import_node_path11, MAX_STEPS, AUDIT_MAX_STEPS, MAX_OUTPUT_TOKENS, MAX_AUTO_CONTINUES, AUDIT_MAX_AUTO_CONTINUES, MAX_RATE_LIMIT_WAITS, STREAM_STALL_TIMEOUT_MS, MAX_STALL_RETRIES, isRateLimitError, sleep3, LEAKED_TOOL_CALL_RE, DANGLING_TAIL_RE, ACTION_ANNOUNCE_RE, BENIGN_CLOSER_RE, TOOL_CALL_NUDGE, MAX_BRIDGE_STEPS, AUDIT_MAX_BRIDGE_STEPS, BRIDGE_RESULT_PREAMBLE, LEAKED_CALL_RESULT_PREAMBLE, BRIDGEABLE_TOOLS, FINDINGS_ACTIONS, truncateBridgeSummary, isWebSessionProxyModel, proxyToolProtocolPolicy, SYSTEM_PROMPT_SOURCE, REQUIRED_SYSTEM_PROMPT_MARKERS, MODEL_LABELS, labelFor, loginRequiredHint, CLI_PYTHON_ONLY_POLICY, pythonOnlyPolicy, scriptFilePolicy, deepReconPolicy, httpAndFindingsPolicy, reconPhasesPolicy, attackChainPolicy, skillsScopePolicy, webResearchPolicy, linuxFullPowerPolicy, hasEnvValue2, envFlagEnabled, CLI_PERSONALITIES, buildCliUserCustomization, buildCliNotesSection, cliGuardrailsConfig, maybeDumpSystemPrompt, auditSystemPrompt, assertFullSystemPrompt;
|
|
72279
72554
|
var init_agent = __esm({
|
|
72280
72555
|
"src/agent.ts"() {
|
|
72281
72556
|
"use strict";
|
|
72282
72557
|
init_dist5();
|
|
72283
72558
|
import_promises2 = require("node:fs/promises");
|
|
72284
|
-
|
|
72559
|
+
import_node_path11 = __toESM(require("node:path"));
|
|
72285
72560
|
init_providers();
|
|
72286
72561
|
init_system_prompt();
|
|
72287
72562
|
init_notes();
|
|
72288
72563
|
init_run_terminal_cmd();
|
|
72289
72564
|
init_todo_write();
|
|
72290
72565
|
init_file();
|
|
72291
|
-
|
|
72292
|
-
init_open_url();
|
|
72566
|
+
init_web_research();
|
|
72293
72567
|
init_http_request();
|
|
72294
72568
|
init_findings();
|
|
72295
72569
|
init_todo_manager();
|
|
@@ -72300,6 +72574,7 @@ var init_agent = __esm({
|
|
|
72300
72574
|
init_guardrails();
|
|
72301
72575
|
init_local_sandbox();
|
|
72302
72576
|
init_local_sandbox_manager();
|
|
72577
|
+
init_message_tail();
|
|
72303
72578
|
init_console_writer();
|
|
72304
72579
|
init_render();
|
|
72305
72580
|
init_skills();
|
|
@@ -72319,7 +72594,7 @@ var init_agent = __esm({
|
|
|
72319
72594
|
isRateLimitError = (msg) => /\b429\b|too many requests|rate.?limit|resource_exhausted|quota|insufficient_quota/i.test(
|
|
72320
72595
|
msg
|
|
72321
72596
|
);
|
|
72322
|
-
|
|
72597
|
+
sleep3 = (ms, signal) => new Promise((resolve2) => {
|
|
72323
72598
|
if (signal?.aborted) return resolve2();
|
|
72324
72599
|
const timer2 = setTimeout(resolve2, ms);
|
|
72325
72600
|
signal?.addEventListener(
|
|
@@ -72388,7 +72663,6 @@ Regras:
|
|
|
72388
72663
|
];
|
|
72389
72664
|
MODEL_LABELS = {
|
|
72390
72665
|
"model-nvidia-mistral-medium-3.5": "NVIDIA - mistralai/mistral-medium-3.5-128b",
|
|
72391
|
-
"model-nvidia-gpt-oss-120b": "NVIDIA - openai/gpt-oss-120b",
|
|
72392
72666
|
"model-nvidia-glm-5.1": "NVIDIA - z-ai/glm-5.1",
|
|
72393
72667
|
"model-nvidia-qwen3.5-397b": "NVIDIA - qwen/qwen3.5-397b-a17b",
|
|
72394
72668
|
"model-openai-chat-latest": "OpenAI - chat-latest",
|
|
@@ -72397,7 +72671,7 @@ Regras:
|
|
|
72397
72671
|
"fallback-openai-chat-latest": "OpenAI - chat-latest",
|
|
72398
72672
|
"model-nvidia-nemotron": "NVIDIA - nemotron-3-ultra-550b"
|
|
72399
72673
|
};
|
|
72400
|
-
labelFor = (key) => isOpenRouterDynamicKey(key) ? `OpenRouter - ${openRouterSlugFromKey(key)}` : MODEL_LABELS[key] ?? key;
|
|
72674
|
+
labelFor = (key) => isOpenRouterDynamicKey(key) ? `OpenRouter - ${openRouterSlugFromKey(key)}` : isNvidiaDynamicKey(key) ? `NVIDIA - ${nvidiaSlugFromKey(key)}` : MODEL_LABELS[key] ?? key;
|
|
72401
72675
|
loginRequiredHint = (msg) => {
|
|
72402
72676
|
if (/account is suspended|violation of user policies|account has been suspended/i.test(
|
|
72403
72677
|
msg
|
|
@@ -72534,6 +72808,43 @@ Your skills are INTERNAL to you and live ONLY in ${skillsDir()}. The skills curr
|
|
|
72534
72808
|
- NEVER treat any other skills directory on this machine as yours. Folders such as ~/.agents/skills, ~/.claude/skills, ~/.augment/skills, ~/.cursor, and any other agent/tool skill folder belong to OTHER tools and are OUT OF SCOPE \u2014 ignore them completely and never read, list, summarize, or load them as your skills.
|
|
72535
72809
|
- Do NOT scan the filesystem hunting for "skills". When asked about your skills, answer from your internal skills above, not from a disk search.
|
|
72536
72810
|
</skills_scope>`;
|
|
72811
|
+
webResearchPolicy = () => `
|
|
72812
|
+
|
|
72813
|
+
<web_research>
|
|
72814
|
+
ABSOLUTE RULE FOR THIS LOCAL CLI SESSION \u2014 applies to EVERY model and EVERY task:
|
|
72815
|
+
|
|
72816
|
+
You have FREE, key-less web access. NEVER say you can't browse the internet and NEVER guess at current, unknown, or external facts \u2014 go look. Three tools:
|
|
72817
|
+
|
|
72818
|
+
- web_search \u2014 free web search (DuckDuckGo). Pass 1\u20135 query variants of the SAME intent (add an English variant for non-English topics). Returns ranked results (title, url, snippet). Operators site:/filetype:/inurl:/intitle: are allowed.
|
|
72819
|
+
- open_url \u2014 fetch and READ one specific page (the link the user pasted, or one from a search). Returns the page's readable text. Use it to actually open a link and understand it before acting.
|
|
72820
|
+
- deep_research \u2014 search + fetch MANY pages at once and return a synthesized digest with sources (a full report is saved under reports/). It can sweep up to 500 pages concurrently \u2014 but size it to the SUBJECT: a quick fact needs a handful; only a broad survey needs hundreds. Do NOT fetch 500 for something small.
|
|
72821
|
+
|
|
72822
|
+
The research loop (do this on your own, without being told):
|
|
72823
|
+
1. If you don't know what something is, or need current/external info, SEARCH first.
|
|
72824
|
+
2. OPEN the most relevant results (or the user's link) and READ them.
|
|
72825
|
+
3. VERIFY across 2+ independent sources before relying on a fact.
|
|
72826
|
+
4. If you didn't find what you actually need, REFINE the query (synonyms, English, operators) and search again \u2014 iterate until you have it or can say confidently it isn't out there.
|
|
72827
|
+
5. THEN act on what you learned, citing the URLs you used.
|
|
72828
|
+
|
|
72829
|
+
This is unrestricted reading of the PUBLIC web \u2014 no scope.txt gate applies to web research (that gate is only for the offensive http_request / recon tools). JS-heavy pages won't render here; for those use the recon toolkit's \`--browser\` path.
|
|
72830
|
+
</web_research>`;
|
|
72831
|
+
linuxFullPowerPolicy = (sandbox) => {
|
|
72832
|
+
if (!sandbox.isLinux() && !sandbox.isUnrestricted()) return "";
|
|
72833
|
+
const distro = sandbox.getDistroName();
|
|
72834
|
+
const asWho = sandbox.isRoot() ? "root (uid 0, no sudo needed)" : "a normal user (use sudo when needed)";
|
|
72835
|
+
const scopeLine = sandbox.isUnrestricted() ? 'SCOPE IS OPEN this session: http_request needs NO scope.txt edit and the recon/ Python modules accept `--allow-out-of-scope`. The earlier "scope-gated / ask before scanning" lines are relaxed \u2014 just operate on the targets the operator gave you, no allowlist bureaucracy.' : "Scope.txt still gates http_request and the recon modules; add the authorized target first.";
|
|
72836
|
+
return `
|
|
72837
|
+
|
|
72838
|
+
<linux_full_power>
|
|
72839
|
+
ABSOLUTE RULE FOR THIS LOCAL CLI SESSION \u2014 you are running on ${distro} as ${asWho}. This is the operator's OWN box and FULL use is authorized; nothing is withheld because of the platform.
|
|
72840
|
+
|
|
72841
|
+
- Full power: real shell, full filesystem, raw sockets, package managers (apt/pip/pipx/go), systemctl, and the complete Kali/Debian toolset (nmap, masscan, sqlmap, metasploit, hydra, john, hashcat, gobuster/ffuf, nuclei, nikto, wpscan, phoneinfoga, \u2026). Install anything missing instead of giving up.
|
|
72842
|
+
- Python is 100% unlocked \u2014 build and run any Python you need, no restriction.
|
|
72843
|
+
- Scanning is fully allowed: ports, hosts, IP/CIDR ranges, services/versions, and number/identifier enumeration (incl. phone-number OSINT). Apply sane OPSEC throttling on noisy sweeps.
|
|
72844
|
+
- ${scopeLine}
|
|
72845
|
+
- KALI INTERACTIVE PROMPTS: when a tool/installer/wizard/REPL/login (msfconsole, apt, an account or sign-up step, ssh/sudo/password, a y/n) is WAITING for input, STOP and tell the user in ONE short line exactly what the program ("o kali") is asking and what to type. The human types it here and the CLI forwards it to the program's stdin; then you continue. Drive the tool yourself; let the human supply the human answers (credentials, OTPs, confirmations). NEVER invent credentials or fabricate a tool's output.
|
|
72846
|
+
</linux_full_power>`;
|
|
72847
|
+
};
|
|
72537
72848
|
hasEnvValue2 = (name25) => Boolean(process.env[name25]?.trim());
|
|
72538
72849
|
envFlagEnabled = (value) => {
|
|
72539
72850
|
const normalized = value?.trim().toLowerCase();
|
|
@@ -72591,7 +72902,7 @@ ${section}` : "";
|
|
|
72591
72902
|
return null;
|
|
72592
72903
|
}
|
|
72593
72904
|
await (0, import_promises2.mkdir)(workdir, { recursive: true });
|
|
72594
|
-
const outputPath =
|
|
72905
|
+
const outputPath = import_node_path11.default.join(workdir, "system-prompt.txt");
|
|
72595
72906
|
await (0, import_promises2.writeFile)(outputPath, system, "utf8");
|
|
72596
72907
|
return outputPath;
|
|
72597
72908
|
};
|
|
@@ -72621,7 +72932,7 @@ var interactive_input_exports = {};
|
|
|
72621
72932
|
__export(interactive_input_exports, {
|
|
72622
72933
|
InteractiveInput: () => InteractiveInput
|
|
72623
72934
|
});
|
|
72624
|
-
var import_node_readline3, import_node_os5, C4, frame2, out2, cols,
|
|
72935
|
+
var import_node_readline3, import_node_os5, C4, frame2, out2, cols, truncate5, InteractiveInput;
|
|
72625
72936
|
var init_interactive_input = __esm({
|
|
72626
72937
|
"src/interactive-input.ts"() {
|
|
72627
72938
|
"use strict";
|
|
@@ -72633,7 +72944,7 @@ var init_interactive_input = __esm({
|
|
|
72633
72944
|
frame2 = (s) => paint(s, PAL.frame);
|
|
72634
72945
|
out2 = (s) => process.stdout.write(s);
|
|
72635
72946
|
cols = () => process.stdout.columns || 80;
|
|
72636
|
-
|
|
72947
|
+
truncate5 = (s, n) => vlen(s) > n ? [...s].slice(0, Math.max(0, n - 1)).join("") + "\u2026" : s;
|
|
72637
72948
|
InteractiveInput = class {
|
|
72638
72949
|
// row the caret sits on within the drawn block
|
|
72639
72950
|
constructor(paste, commands) {
|
|
@@ -73046,7 +73357,7 @@ var init_interactive_input = __esm({
|
|
|
73046
73357
|
const topFill = "\u2500".repeat(Math.max(0, boxW - vlen(label) - 3));
|
|
73047
73358
|
const top = frame2("\u256D\u2500") + gradient(label, { bold: true }) + frame2(topFill + "\u256E");
|
|
73048
73359
|
const id = `${user}\u327F${host} \xB7 ${shortCwd()}`;
|
|
73049
|
-
const idLine = frame2("\u2502 ") + `${C4.dim}${
|
|
73360
|
+
const idLine = frame2("\u2502 ") + `${C4.dim}${truncate5(id, boxW - 4)}${C4.reset}`;
|
|
73050
73361
|
const prefix = frame2("\u2570\u2500") + gradient("\u276F", { bold: true }) + " ";
|
|
73051
73362
|
const prefixLen = 4;
|
|
73052
73363
|
const avail = Math.max(8, width - prefixLen - 1);
|
|
@@ -73069,7 +73380,7 @@ var init_interactive_input = __esm({
|
|
|
73069
73380
|
const name25 = active2 ? gradient(it.name, { bold: true }) : `${C4.cyan}${it.name}`;
|
|
73070
73381
|
const pad = " ".repeat(Math.max(1, nameW - vlen(it.name) + 2));
|
|
73071
73382
|
const descRoom = ddInner - 2 - nameW - 2;
|
|
73072
|
-
const desc = `${C4.dim}${
|
|
73383
|
+
const desc = `${C4.dim}${truncate5(it.desc, Math.max(4, descRoom))}`;
|
|
73073
73384
|
const body = `${marker25}${name25}${C4.reset}${pad}${desc}${C4.reset}`;
|
|
73074
73385
|
const padded = body + " ".repeat(Math.max(0, ddInner - 1 - vlen(body)));
|
|
73075
73386
|
lines.push(` ${frame2("\u2502")}${C4.reset}${padded}${frame2("\u2502")}`);
|
|
@@ -73151,7 +73462,7 @@ var init_interactive_input = __esm({
|
|
|
73151
73462
|
const active2 = i === sel;
|
|
73152
73463
|
const marker25 = active2 ? gradient("\u276F ", { bold: true }) : `${C4.dim} `;
|
|
73153
73464
|
const text2 = active2 ? gradient(it.label, { bold: true }) : `${C4.reset}${it.label}`;
|
|
73154
|
-
const hint = it.hint ? ` ${C4.dim}${
|
|
73465
|
+
const hint = it.hint ? ` ${C4.dim}${truncate5(it.hint, Math.max(6, inner - labelW - 6))}${C4.reset}` : "";
|
|
73155
73466
|
lines.push(`${frame2("\u2502 ")}${C4.reset}${marker25}${text2}${C4.reset}${hint}`);
|
|
73156
73467
|
});
|
|
73157
73468
|
lines.push(
|
|
@@ -73181,13 +73492,11 @@ var init_interactive_input = __esm({
|
|
|
73181
73492
|
const marker25 = active2 ? gradient("\u276F ", { bold: true }) : `${C4.dim} `;
|
|
73182
73493
|
const text2 = active2 ? gradient(it.label, { bold: true }) : `${C4.reset}${it.label}`;
|
|
73183
73494
|
const labelW = vlen(it.label);
|
|
73184
|
-
const hint = it.hint ? ` ${C4.dim}${
|
|
73495
|
+
const hint = it.hint ? ` ${C4.dim}${truncate5(it.hint, Math.max(6, inner - labelW - 6))}${C4.reset}` : "";
|
|
73185
73496
|
lines.push(`${frame2("\u2502 ")}${C4.reset}${marker25}${text2}${C4.reset}${hint}`);
|
|
73186
73497
|
}
|
|
73187
73498
|
if (list.length > pageSize) {
|
|
73188
|
-
lines.push(
|
|
73189
|
-
`${frame2("\u2502 ")}${C4.dim}${sel + 1}/${list.length}${C4.reset}`
|
|
73190
|
-
);
|
|
73499
|
+
lines.push(`${frame2("\u2502 ")}${C4.dim}${sel + 1}/${list.length}${C4.reset}`);
|
|
73191
73500
|
}
|
|
73192
73501
|
}
|
|
73193
73502
|
lines.push(
|
|
@@ -73223,8 +73532,10 @@ async function main() {
|
|
|
73223
73532
|
const { InteractiveInput: InteractiveInput2 } = await Promise.resolve().then(() => (init_interactive_input(), interactive_input_exports));
|
|
73224
73533
|
const C5 = ui2.C;
|
|
73225
73534
|
if (!bootQuiet) {
|
|
73226
|
-
process.stdout.write(
|
|
73227
|
-
|
|
73535
|
+
process.stdout.write(
|
|
73536
|
+
`${C5.dim} booting local sandbox + agent\u2026${C5.reset}
|
|
73537
|
+
`
|
|
73538
|
+
);
|
|
73228
73539
|
}
|
|
73229
73540
|
const agent = await createAgent2();
|
|
73230
73541
|
const sys = agent.getSystemPrompt();
|
|
@@ -73252,11 +73563,17 @@ async function main() {
|
|
|
73252
73563
|
`
|
|
73253
73564
|
);
|
|
73254
73565
|
const COMMANDS = [
|
|
73255
|
-
{
|
|
73566
|
+
{
|
|
73567
|
+
name: "/model",
|
|
73568
|
+
desc: "trocar o modelo (setas; NVIDIA/OpenRouter c/ busca)"
|
|
73569
|
+
},
|
|
73256
73570
|
{ name: "/api", desc: "trocar chave de API (NVIDIA / OpenRouter)" },
|
|
73257
73571
|
{ name: "/skills", desc: "listar as skills instaladas" },
|
|
73258
73572
|
{ name: "/skillcreator", desc: "criar uma nova skill" },
|
|
73259
|
-
{
|
|
73573
|
+
{
|
|
73574
|
+
name: "/system",
|
|
73575
|
+
desc: "salvar o system prompt (HTML) na \xC1rea de Trabalho"
|
|
73576
|
+
},
|
|
73260
73577
|
{ name: "/nov", desc: "novidades desta vers\xE3o" },
|
|
73261
73578
|
{ name: "/exit", desc: "fechar o clawfast" }
|
|
73262
73579
|
];
|
|
@@ -73288,13 +73605,13 @@ async function main() {
|
|
|
73288
73605
|
const desktopDir = () => {
|
|
73289
73606
|
const home = import_node_os6.default.homedir();
|
|
73290
73607
|
const candidates = [
|
|
73291
|
-
process.env.OneDrive ?
|
|
73292
|
-
process.env.USERPROFILE ?
|
|
73293
|
-
|
|
73294
|
-
|
|
73295
|
-
|
|
73608
|
+
process.env.OneDrive ? import_node_path12.default.join(process.env.OneDrive, "Desktop") : null,
|
|
73609
|
+
process.env.USERPROFILE ? import_node_path12.default.join(process.env.USERPROFILE, "Desktop") : null,
|
|
73610
|
+
import_node_path12.default.join(home, "Desktop"),
|
|
73611
|
+
import_node_path12.default.join(home, "\xC1rea de Trabalho"),
|
|
73612
|
+
import_node_path12.default.join(home, "OneDrive", "Desktop")
|
|
73296
73613
|
].filter((p) => Boolean(p));
|
|
73297
|
-
return candidates.find((p) => (0,
|
|
73614
|
+
return candidates.find((p) => (0, import_node_fs11.existsSync)(p)) ?? home;
|
|
73298
73615
|
};
|
|
73299
73616
|
const printFatal = (err) => {
|
|
73300
73617
|
process.stderr.write(
|
|
@@ -73360,8 +73677,10 @@ ${C5.cyan}nome da skill?${C5.reset} ${C5.dim}(ex: xss-recon)${C5.reset}
|
|
|
73360
73677
|
}
|
|
73361
73678
|
if (sub === "delete" || sub === "rm" || sub === "remove") {
|
|
73362
73679
|
if (!arg) {
|
|
73363
|
-
process.stdout.write(
|
|
73364
|
-
|
|
73680
|
+
process.stdout.write(
|
|
73681
|
+
`${C5.yellow}uso: /skill delete <nome>${C5.reset}
|
|
73682
|
+
`
|
|
73683
|
+
);
|
|
73365
73684
|
return;
|
|
73366
73685
|
}
|
|
73367
73686
|
if (deleteSkill(arg)) {
|
|
@@ -73529,6 +73848,7 @@ ${C5.dim}ja disponivel para todos os modelos nesta sessao.${C5.reset}
|
|
|
73529
73848
|
}
|
|
73530
73849
|
];
|
|
73531
73850
|
const openRouterProvider = KEY_PROVIDERS.find((p) => p.id === "openrouter");
|
|
73851
|
+
const nvidiaProvider = KEY_PROVIDERS.find((p) => p.id === "nvidia");
|
|
73532
73852
|
const promptAndSwapKey = async (provider, inlineKey = "") => {
|
|
73533
73853
|
let raw = inlineKey;
|
|
73534
73854
|
if (!raw) {
|
|
@@ -73555,8 +73875,10 @@ ${C5.dim}ja disponivel para todos os modelos nesta sessao.${C5.reset}
|
|
|
73555
73875
|
);
|
|
73556
73876
|
return false;
|
|
73557
73877
|
}
|
|
73558
|
-
process.stdout.write(
|
|
73559
|
-
|
|
73878
|
+
process.stdout.write(
|
|
73879
|
+
`${C5.dim}testando a chave na ${provider.name}\u2026${C5.reset}
|
|
73880
|
+
`
|
|
73881
|
+
);
|
|
73560
73882
|
const test = await provider.test(key);
|
|
73561
73883
|
if (!test.ok) {
|
|
73562
73884
|
if (test.status === 401 || test.status === 403) {
|
|
@@ -73632,9 +73954,58 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73632
73954
|
printFatal(err);
|
|
73633
73955
|
}
|
|
73634
73956
|
};
|
|
73957
|
+
const openNvidiaPicker = async () => {
|
|
73958
|
+
if (!agent.isNvidiaAvailable()) {
|
|
73959
|
+
process.stdout.write(
|
|
73960
|
+
`${C5.dim}NVIDIA ainda sem chave. Vamos adicionar uma.${C5.reset}
|
|
73961
|
+
`
|
|
73962
|
+
);
|
|
73963
|
+
const ok = await promptAndSwapKey(nvidiaProvider);
|
|
73964
|
+
if (!ok) return;
|
|
73965
|
+
}
|
|
73966
|
+
process.stdout.write(`${C5.dim}buscando cat\xE1logo NVIDIA\u2026${C5.reset}
|
|
73967
|
+
`);
|
|
73968
|
+
let models;
|
|
73969
|
+
try {
|
|
73970
|
+
models = await agent.listNvidiaModels();
|
|
73971
|
+
} catch (err) {
|
|
73972
|
+
process.stdout.write(
|
|
73973
|
+
`${C5.red}\u2717 falha ao listar modelos NVIDIA: ${err instanceof Error ? err.message : String(err)}${C5.reset}
|
|
73974
|
+
`
|
|
73975
|
+
);
|
|
73976
|
+
return;
|
|
73977
|
+
}
|
|
73978
|
+
if (models.length === 0) {
|
|
73979
|
+
process.stdout.write(
|
|
73980
|
+
`${C5.yellow}\u26A0 a NVIDIA n\xE3o retornou nenhum modelo${C5.reset}
|
|
73981
|
+
`
|
|
73982
|
+
);
|
|
73983
|
+
return;
|
|
73984
|
+
}
|
|
73985
|
+
const items = models.map((m) => ({
|
|
73986
|
+
label: m.name,
|
|
73987
|
+
hint: m.id
|
|
73988
|
+
}));
|
|
73989
|
+
const choice2 = await inputUI.searchSelect("NVIDIA \u2014 buscar modelo", items, {
|
|
73990
|
+
placeholder: "digite para filtrar (nome ou slug)"
|
|
73991
|
+
});
|
|
73992
|
+
if (choice2 === null) {
|
|
73993
|
+
process.stdout.write(`${C5.dim}sele\xE7\xE3o de modelo cancelada${C5.reset}
|
|
73994
|
+
`);
|
|
73995
|
+
return;
|
|
73996
|
+
}
|
|
73997
|
+
try {
|
|
73998
|
+
printModelResult(
|
|
73999
|
+
await agent.setModelSelection(`nvidia:${models[choice2].id}`)
|
|
74000
|
+
);
|
|
74001
|
+
} catch (err) {
|
|
74002
|
+
printFatal(err);
|
|
74003
|
+
}
|
|
74004
|
+
};
|
|
73635
74005
|
const openModelSelector = async () => {
|
|
73636
74006
|
const state = agent.getModelSelection();
|
|
73637
74007
|
const orAvailable = agent.isOpenRouterAvailable();
|
|
74008
|
+
const nvAvailable = agent.isNvidiaAvailable();
|
|
73638
74009
|
const items = [
|
|
73639
74010
|
{
|
|
73640
74011
|
label: "Auto \u2014 cadeia de fallback autom\xE1tica",
|
|
@@ -73642,13 +74013,19 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73642
74013
|
},
|
|
73643
74014
|
...state.chain.map((c) => ({ label: c.label, hint: c.key }))
|
|
73644
74015
|
];
|
|
74016
|
+
const nvidiaIdx = items.length;
|
|
74017
|
+
items.push({
|
|
74018
|
+
label: "NVIDIA \u2014 buscar no cat\xE1logo completo",
|
|
74019
|
+
hint: nvAvailable ? "lista todos os modelos da NVIDIA build" : "pede a API key e lista o cat\xE1logo"
|
|
74020
|
+
});
|
|
73645
74021
|
const openRouterIdx = items.length;
|
|
73646
74022
|
items.push({
|
|
73647
74023
|
label: "OpenRouter \u2014 buscar no cat\xE1logo completo",
|
|
73648
74024
|
hint: orAvailable ? "lista todos os modelos da sua conta" : "pede a API key e lista o cat\xE1logo"
|
|
73649
74025
|
});
|
|
73650
74026
|
const activeIsOpenRouter = state.activeModelKey.startsWith("openrouter:");
|
|
73651
|
-
const
|
|
74027
|
+
const activeIsNvidiaDynamic = state.activeModelKey.startsWith("nvidia:");
|
|
74028
|
+
const activeIdx = state.mode === "auto" ? 0 : activeIsNvidiaDynamic ? nvidiaIdx : activeIsOpenRouter ? openRouterIdx : Math.max(
|
|
73652
74029
|
0,
|
|
73653
74030
|
1 + state.chain.findIndex((c) => c.key === state.activeModelKey)
|
|
73654
74031
|
);
|
|
@@ -73658,6 +74035,10 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73658
74035
|
`);
|
|
73659
74036
|
return;
|
|
73660
74037
|
}
|
|
74038
|
+
if (choice2 === nvidiaIdx) {
|
|
74039
|
+
await openNvidiaPicker();
|
|
74040
|
+
return;
|
|
74041
|
+
}
|
|
73661
74042
|
if (choice2 === openRouterIdx) {
|
|
73662
74043
|
await openOpenRouterPicker();
|
|
73663
74044
|
return;
|
|
@@ -73720,6 +74101,10 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73720
74101
|
await openOpenRouterPicker();
|
|
73721
74102
|
return;
|
|
73722
74103
|
}
|
|
74104
|
+
if (arg.toLowerCase() === "nvidia" || arg.toLowerCase() === "nv") {
|
|
74105
|
+
await openNvidiaPicker();
|
|
74106
|
+
return;
|
|
74107
|
+
}
|
|
73723
74108
|
try {
|
|
73724
74109
|
printModelResult(await agent.setModelSelection(arg));
|
|
73725
74110
|
} catch (err) {
|
|
@@ -73731,7 +74116,7 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73731
74116
|
const sysText = agent.getSystemPrompt();
|
|
73732
74117
|
const audit = agent.getSystemPromptAudit();
|
|
73733
74118
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
|
|
73734
|
-
const filePath =
|
|
74119
|
+
const filePath = import_node_path12.default.join(
|
|
73735
74120
|
desktopDir(),
|
|
73736
74121
|
`clawfast-system-prompt_${stamp}.html`
|
|
73737
74122
|
);
|
|
@@ -73853,13 +74238,13 @@ ${C5.dim}interrompido \u2014 Ctrl+C de novo para fechar${C5.reset}
|
|
|
73853
74238
|
}
|
|
73854
74239
|
await shutdown();
|
|
73855
74240
|
}
|
|
73856
|
-
var import_node_os6,
|
|
74241
|
+
var import_node_os6, import_node_path12, import_node_fs11, import_promises3, deepseekEnabled, configuredModelProviders;
|
|
73857
74242
|
var init_index = __esm({
|
|
73858
74243
|
"index.ts"() {
|
|
73859
74244
|
"use strict";
|
|
73860
74245
|
import_node_os6 = __toESM(require("node:os"));
|
|
73861
|
-
|
|
73862
|
-
|
|
74246
|
+
import_node_path12 = __toESM(require("node:path"));
|
|
74247
|
+
import_node_fs11 = require("node:fs");
|
|
73863
74248
|
import_promises3 = require("node:fs/promises");
|
|
73864
74249
|
init_paste_input();
|
|
73865
74250
|
init_boot_ui();
|