clawfast 2.2.2 → 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 +951 -687
- 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-"]
|
|
@@ -46085,7 +46097,6 @@ var init_providers = __esm({
|
|
|
46085
46097
|
"model-nvidia-mistral-medium-3.5": nvidia.chat(
|
|
46086
46098
|
"mistralai/mistral-medium-3.5-128b"
|
|
46087
46099
|
),
|
|
46088
|
-
"model-nvidia-gpt-oss-120b": nvidia.chat("openai/gpt-oss-120b"),
|
|
46089
46100
|
"model-nvidia-glm-5.1": nvidia.chat("z-ai/glm-5.1"),
|
|
46090
46101
|
"model-nvidia-qwen3.5-397b": nvidia.chat("qwen/qwen3.5-397b-a17b"),
|
|
46091
46102
|
// Extra explicit keys for the CLI.
|
|
@@ -46123,8 +46134,6 @@ var init_providers = __esm({
|
|
|
46123
46134
|
...hasEnvValue("NVIDIA_API_KEY") ? [
|
|
46124
46135
|
"model-nvidia-mistral-medium-3.5",
|
|
46125
46136
|
// NVIDIA mistralai/mistral-medium-3.5-128b
|
|
46126
|
-
"model-nvidia-gpt-oss-120b",
|
|
46127
|
-
// NVIDIA openai/gpt-oss-120b
|
|
46128
46137
|
"model-nvidia-glm-5.1",
|
|
46129
46138
|
// NVIDIA z-ai/glm-5.1
|
|
46130
46139
|
"model-nvidia-qwen3.5-397b"
|
|
@@ -46150,7 +46159,6 @@ var init_providers = __esm({
|
|
|
46150
46159
|
"model-opus-4.6": "May 2025",
|
|
46151
46160
|
"model-kimi-k2.6": "April 2024",
|
|
46152
46161
|
"model-nvidia-mistral-medium-3.5": "Unknown",
|
|
46153
|
-
"model-nvidia-gpt-oss-120b": "June 2024",
|
|
46154
46162
|
"model-nvidia-glm-5.1": "Unknown",
|
|
46155
46163
|
"model-nvidia-qwen3.5-397b": "Unknown",
|
|
46156
46164
|
"model-deepseek-proxy": "July 2024",
|
|
@@ -46174,7 +46182,6 @@ var init_providers = __esm({
|
|
|
46174
46182
|
"model-opus-4.6": "Anthropic Claude Opus 4.6",
|
|
46175
46183
|
"model-kimi-k2.6": "Moonshot Kimi K2.6",
|
|
46176
46184
|
"model-nvidia-mistral-medium-3.5": "NVIDIA - Mistral Medium 3.5",
|
|
46177
|
-
"model-nvidia-gpt-oss-120b": "NVIDIA - OpenAI GPT-OSS 120B",
|
|
46178
46185
|
"model-nvidia-glm-5.1": "NVIDIA - Z.ai GLM 5.1",
|
|
46179
46186
|
"model-nvidia-qwen3.5-397b": "NVIDIA - Qwen3.5 397B A17B",
|
|
46180
46187
|
"model-deepseek-proxy": "DeepSeek (sessao web logada / deepsproxy)",
|
|
@@ -49218,8 +49225,8 @@ var init_background_process_tracker = __esm({
|
|
|
49218
49225
|
/**
|
|
49219
49226
|
* Normalize file path for comparison
|
|
49220
49227
|
*/
|
|
49221
|
-
normalizePath(
|
|
49222
|
-
let normalized =
|
|
49228
|
+
normalizePath(path13) {
|
|
49229
|
+
let normalized = path13.trim().replace(/\/+/g, "/");
|
|
49223
49230
|
if (normalized.startsWith("./")) {
|
|
49224
49231
|
normalized = normalized.slice(2);
|
|
49225
49232
|
}
|
|
@@ -49457,8 +49464,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
49457
49464
|
return decodedFile;
|
|
49458
49465
|
};
|
|
49459
49466
|
}
|
|
49460
|
-
function normalizeWindowsPath(
|
|
49461
|
-
return
|
|
49467
|
+
function normalizeWindowsPath(path13) {
|
|
49468
|
+
return path13.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
49462
49469
|
}
|
|
49463
49470
|
var import_path;
|
|
49464
49471
|
var init_module_node = __esm({
|
|
@@ -52347,9 +52354,9 @@ async function addSourceContext(frames) {
|
|
|
52347
52354
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
52348
52355
|
return frames;
|
|
52349
52356
|
}
|
|
52350
|
-
function getContextLinesFromFile(
|
|
52357
|
+
function getContextLinesFromFile(path13, ranges, output) {
|
|
52351
52358
|
return new Promise((resolve2) => {
|
|
52352
|
-
const stream = (0, import_node_fs5.createReadStream)(
|
|
52359
|
+
const stream = (0, import_node_fs5.createReadStream)(path13);
|
|
52353
52360
|
const lineReaded = (0, import_node_readline2.createInterface)({
|
|
52354
52361
|
input: stream
|
|
52355
52362
|
});
|
|
@@ -52364,7 +52371,7 @@ function getContextLinesFromFile(path12, ranges, output) {
|
|
|
52364
52371
|
let rangeStart = range[0];
|
|
52365
52372
|
let rangeEnd = range[1];
|
|
52366
52373
|
function onStreamError() {
|
|
52367
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
52374
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path13, 1);
|
|
52368
52375
|
lineReaded.close();
|
|
52369
52376
|
lineReaded.removeAllListeners();
|
|
52370
52377
|
destroyStreamAndResolve();
|
|
@@ -52425,8 +52432,8 @@ function clearLineContext(frame3) {
|
|
|
52425
52432
|
delete frame3.context_line;
|
|
52426
52433
|
delete frame3.post_context;
|
|
52427
52434
|
}
|
|
52428
|
-
function shouldSkipContextLinesForFile(
|
|
52429
|
-
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:");
|
|
52430
52437
|
}
|
|
52431
52438
|
function shouldSkipContextLinesForFrame(frame3) {
|
|
52432
52439
|
if (void 0 !== frame3.lineno && frame3.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -67836,8 +67843,8 @@ var init_logger2 = __esm({
|
|
|
67836
67843
|
});
|
|
67837
67844
|
|
|
67838
67845
|
// ../lib/ai/tools/file.ts
|
|
67839
|
-
function isSpritPath(
|
|
67840
|
-
return
|
|
67846
|
+
function isSpritPath(path13) {
|
|
67847
|
+
return path13.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
|
|
67841
67848
|
}
|
|
67842
67849
|
function getViewSandboxType(sandbox) {
|
|
67843
67850
|
return isCentrifugoSandbox(sandbox) ? "centrifugo" : "e2b";
|
|
@@ -67868,7 +67875,7 @@ function captureFileViewImageUsage(args) {
|
|
|
67868
67875
|
const {
|
|
67869
67876
|
context: context2,
|
|
67870
67877
|
sandbox,
|
|
67871
|
-
path:
|
|
67878
|
+
path: path13,
|
|
67872
67879
|
outcome,
|
|
67873
67880
|
durationMs,
|
|
67874
67881
|
mediaType,
|
|
@@ -67886,7 +67893,7 @@ function captureFileViewImageUsage(args) {
|
|
|
67886
67893
|
model: getActiveModelName(context2),
|
|
67887
67894
|
configured_model: context2.modelName,
|
|
67888
67895
|
sandbox_type: getViewSandboxType(sandbox),
|
|
67889
|
-
file_extension: getFileExtension(
|
|
67896
|
+
file_extension: getFileExtension(path13),
|
|
67890
67897
|
outcome,
|
|
67891
67898
|
success: outcome === "success",
|
|
67892
67899
|
duration_ms: durationMs,
|
|
@@ -67960,22 +67967,22 @@ async function runSandboxCommand(sandbox, command, envVars, timeoutMs = 6e4) {
|
|
|
67960
67967
|
function isWindowsSandbox(sandbox) {
|
|
67961
67968
|
return isCentrifugoSandbox(sandbox) && sandbox.isWindows();
|
|
67962
67969
|
}
|
|
67963
|
-
function getWindowsNativePath(
|
|
67964
|
-
if (/^[A-Za-z]:[\\/]/.test(
|
|
67965
|
-
if (
|
|
67966
|
-
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, "\\")}`;
|
|
67967
67974
|
}
|
|
67968
|
-
return
|
|
67975
|
+
return path13.replace(/\//g, "\\");
|
|
67969
67976
|
}
|
|
67970
|
-
function getPythonPathForSandbox(sandbox,
|
|
67971
|
-
return isWindowsSandbox(sandbox) ? getWindowsNativePath(
|
|
67977
|
+
function getPythonPathForSandbox(sandbox, path13) {
|
|
67978
|
+
return isWindowsSandbox(sandbox) ? getWindowsNativePath(path13) : path13;
|
|
67972
67979
|
}
|
|
67973
|
-
function toWindowsBashPath(
|
|
67974
|
-
const drive =
|
|
67980
|
+
function toWindowsBashPath(path13) {
|
|
67981
|
+
const drive = path13.match(/^([A-Za-z]):[\\/](.*)$/);
|
|
67975
67982
|
if (drive) {
|
|
67976
67983
|
return `/${drive[1].toLowerCase()}/${drive[2].replace(/\\/g, "/")}`;
|
|
67977
67984
|
}
|
|
67978
|
-
return
|
|
67985
|
+
return path13.replace(/\\/g, "/");
|
|
67979
67986
|
}
|
|
67980
67987
|
async function detectSandboxShell(sandbox) {
|
|
67981
67988
|
if (!isWindowsSandbox(sandbox)) return "bash";
|
|
@@ -68014,8 +68021,8 @@ PY`;
|
|
|
68014
68021
|
}
|
|
68015
68022
|
}
|
|
68016
68023
|
}
|
|
68017
|
-
async function getSandboxFileState(sandbox,
|
|
68018
|
-
const pythonPath = getPythonPathForSandbox(sandbox,
|
|
68024
|
+
async function getSandboxFileState(sandbox, path13) {
|
|
68025
|
+
const pythonPath = getPythonPathForSandbox(sandbox, path13);
|
|
68019
68026
|
const result = await runPythonScript(
|
|
68020
68027
|
sandbox,
|
|
68021
68028
|
FILE_STATE_SCRIPT,
|
|
@@ -68032,23 +68039,23 @@ async function getSandboxFileState(sandbox, path12) {
|
|
|
68032
68039
|
if (result.exitCode !== 0) {
|
|
68033
68040
|
return {
|
|
68034
68041
|
kind: "unknown",
|
|
68035
|
-
path:
|
|
68042
|
+
path: path13,
|
|
68036
68043
|
error: result.stderr || result.stdout || "file state command failed"
|
|
68037
68044
|
};
|
|
68038
68045
|
}
|
|
68039
68046
|
try {
|
|
68040
68047
|
const payload = JSON.parse(result.stdout.trim());
|
|
68041
68048
|
if (payload.kind === "file" && typeof payload.sizeBytes === "number" && Number.isFinite(payload.sizeBytes)) {
|
|
68042
|
-
return { ...payload, path:
|
|
68049
|
+
return { ...payload, path: path13 };
|
|
68043
68050
|
}
|
|
68044
68051
|
if (payload.kind === "missing" || payload.kind === "not_file") {
|
|
68045
|
-
return { ...payload, path:
|
|
68052
|
+
return { ...payload, path: path13 };
|
|
68046
68053
|
}
|
|
68047
68054
|
} catch {
|
|
68048
68055
|
}
|
|
68049
68056
|
return {
|
|
68050
68057
|
kind: "unknown",
|
|
68051
|
-
path:
|
|
68058
|
+
path: path13,
|
|
68052
68059
|
error: result.stderr || result.stdout || "invalid file state response"
|
|
68053
68060
|
};
|
|
68054
68061
|
}
|
|
@@ -68080,8 +68087,8 @@ ${numberedContent}${truncatedNotice}${footerNotice}`;
|
|
|
68080
68087
|
})
|
|
68081
68088
|
};
|
|
68082
68089
|
}
|
|
68083
|
-
async function readSandboxTextFile(sandbox,
|
|
68084
|
-
const pythonPath = getPythonPathForSandbox(sandbox,
|
|
68090
|
+
async function readSandboxTextFile(sandbox, path13, range) {
|
|
68091
|
+
const pythonPath = getPythonPathForSandbox(sandbox, path13);
|
|
68085
68092
|
const envVars = {
|
|
68086
68093
|
clawfast_FILE_READ_PATH: pythonPath,
|
|
68087
68094
|
clawfast_FILE_READ_RANGE_START: String(range?.[0] ?? 0),
|
|
@@ -68109,40 +68116,40 @@ async function readSandboxTextFile(sandbox, path12, range) {
|
|
|
68109
68116
|
}
|
|
68110
68117
|
return payload;
|
|
68111
68118
|
}
|
|
68112
|
-
async function readSandboxTextFileWithFallback(sandbox,
|
|
68119
|
+
async function readSandboxTextFileWithFallback(sandbox, path13, range) {
|
|
68113
68120
|
try {
|
|
68114
|
-
return await readSandboxTextFile(sandbox,
|
|
68121
|
+
return await readSandboxTextFile(sandbox, path13, range);
|
|
68115
68122
|
} catch (error51) {
|
|
68116
68123
|
const errorMessage = error51 instanceof Error ? error51.message : String(error51);
|
|
68117
68124
|
if (errorMessage.startsWith("Invalid ") || errorMessage.includes("File not found")) {
|
|
68118
68125
|
throw error51;
|
|
68119
68126
|
}
|
|
68120
|
-
const state = await getSandboxFileState(sandbox,
|
|
68127
|
+
const state = await getSandboxFileState(sandbox, path13);
|
|
68121
68128
|
if (state.kind === "unknown") {
|
|
68122
68129
|
throw new Error(
|
|
68123
|
-
`Unable to determine file size for ${
|
|
68130
|
+
`Unable to determine file size for ${path13}; refusing to load the file into memory. ${state.error}`
|
|
68124
68131
|
);
|
|
68125
68132
|
}
|
|
68126
68133
|
if (state.kind === "missing") {
|
|
68127
|
-
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}`);
|
|
68128
68135
|
}
|
|
68129
68136
|
if (state.kind === "not_file") {
|
|
68130
|
-
throw new Error(`File is not a regular file: ${
|
|
68137
|
+
throw new Error(`File is not a regular file: ${path13}`);
|
|
68131
68138
|
}
|
|
68132
68139
|
if (state.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
|
|
68133
68140
|
if (range) {
|
|
68134
68141
|
throw new Error(
|
|
68135
|
-
`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.`
|
|
68136
68143
|
);
|
|
68137
68144
|
}
|
|
68138
68145
|
return {
|
|
68139
|
-
path:
|
|
68146
|
+
path: path13,
|
|
68140
68147
|
sizeBytes: state.sizeBytes,
|
|
68141
68148
|
totalLines: 0,
|
|
68142
68149
|
tooLarge: true
|
|
68143
68150
|
};
|
|
68144
68151
|
}
|
|
68145
|
-
const fileContent = await sandbox.files.read(
|
|
68152
|
+
const fileContent = await sandbox.files.read(path13, {
|
|
68146
68153
|
user: "user"
|
|
68147
68154
|
});
|
|
68148
68155
|
const lines = fileContent.split("\n");
|
|
@@ -68166,7 +68173,7 @@ async function readSandboxTextFileWithFallback(sandbox, path12, range) {
|
|
|
68166
68173
|
const startIndex = start - 1;
|
|
68167
68174
|
const endIndex = end === -1 ? lines.length : end;
|
|
68168
68175
|
return {
|
|
68169
|
-
path:
|
|
68176
|
+
path: path13,
|
|
68170
68177
|
sizeBytes: Buffer.byteLength(fileContent),
|
|
68171
68178
|
totalLines: lines.length,
|
|
68172
68179
|
content: lines.slice(startIndex, endIndex).join("\n"),
|
|
@@ -68174,7 +68181,7 @@ async function readSandboxTextFileWithFallback(sandbox, path12, range) {
|
|
|
68174
68181
|
};
|
|
68175
68182
|
}
|
|
68176
68183
|
return {
|
|
68177
|
-
path:
|
|
68184
|
+
path: path13,
|
|
68178
68185
|
sizeBytes: Buffer.byteLength(fileContent),
|
|
68179
68186
|
totalLines: lines.length,
|
|
68180
68187
|
content: fileContent,
|
|
@@ -68182,7 +68189,7 @@ async function readSandboxTextFileWithFallback(sandbox, path12, range) {
|
|
|
68182
68189
|
};
|
|
68183
68190
|
}
|
|
68184
68191
|
}
|
|
68185
|
-
async function appendSandboxTextFile(sandbox,
|
|
68192
|
+
async function appendSandboxTextFile(sandbox, path13, text2) {
|
|
68186
68193
|
const tempPath = `/tmp/clawfast_append_${Date.now()}_${Math.random().toString(36).slice(2)}.tmp`;
|
|
68187
68194
|
await sandbox.files.write(tempPath, text2, {
|
|
68188
68195
|
user: "user"
|
|
@@ -68191,7 +68198,7 @@ async function appendSandboxTextFile(sandbox, path12, text2) {
|
|
|
68191
68198
|
sandbox,
|
|
68192
68199
|
APPEND_TEXT_FILE_SCRIPT,
|
|
68193
68200
|
{
|
|
68194
|
-
clawfast_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox,
|
|
68201
|
+
clawfast_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path13),
|
|
68195
68202
|
clawfast_FILE_APPEND_SOURCE_PATH: getPythonPathForSandbox(
|
|
68196
68203
|
sandbox,
|
|
68197
68204
|
tempPath
|
|
@@ -68203,13 +68210,13 @@ async function appendSandboxTextFile(sandbox, path12, text2) {
|
|
|
68203
68210
|
throw new Error(result.stderr || result.stdout || "Failed to append file");
|
|
68204
68211
|
}
|
|
68205
68212
|
}
|
|
68206
|
-
async function readSandboxFileForView(sandbox,
|
|
68213
|
+
async function readSandboxFileForView(sandbox, path13, includeData) {
|
|
68207
68214
|
if (isCentrifugoSandbox(sandbox) && sandbox.isWindows()) {
|
|
68208
68215
|
throw new Error(
|
|
68209
68216
|
"The view action is not available for Windows local sandboxes yet. Use a Linux/E2B sandbox or inspect the image manually."
|
|
68210
68217
|
);
|
|
68211
68218
|
}
|
|
68212
|
-
const sandboxPath = getSandboxViewPath(sandbox,
|
|
68219
|
+
const sandboxPath = getSandboxViewPath(sandbox, path13);
|
|
68213
68220
|
const viewEnvVars = {
|
|
68214
68221
|
clawfast_FILE_VIEW_PATH: sandboxPath,
|
|
68215
68222
|
clawfast_FILE_VIEW_INCLUDE_DATA: includeData ? "1" : "0",
|
|
@@ -68553,19 +68560,19 @@ try:
|
|
|
68553
68560
|
except OSError:
|
|
68554
68561
|
pass
|
|
68555
68562
|
`;
|
|
68556
|
-
getFilename = (
|
|
68557
|
-
getFileExtension = (
|
|
68558
|
-
const filename = getFilename(
|
|
68563
|
+
getFilename = (path13) => path13.split("/").pop() || path13;
|
|
68564
|
+
getFileExtension = (path13) => {
|
|
68565
|
+
const filename = getFilename(path13);
|
|
68559
68566
|
const dotIndex = filename.lastIndexOf(".");
|
|
68560
68567
|
if (dotIndex <= 0 || dotIndex === filename.length - 1) return void 0;
|
|
68561
68568
|
return filename.slice(dotIndex + 1).toLowerCase();
|
|
68562
68569
|
};
|
|
68563
|
-
getSandboxViewPath = (sandbox,
|
|
68570
|
+
getSandboxViewPath = (sandbox, path13) => {
|
|
68564
68571
|
const maybeSandbox = sandbox;
|
|
68565
|
-
if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() &&
|
|
68566
|
-
return `C:\\temp${
|
|
68572
|
+
if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path13.startsWith("/tmp/")) {
|
|
68573
|
+
return `C:\\temp${path13.slice(4).replace(/\//g, "\\")}`;
|
|
68567
68574
|
}
|
|
68568
|
-
return
|
|
68575
|
+
return path13;
|
|
68569
68576
|
};
|
|
68570
68577
|
stripTrailingWs = (line) => line.replace(/[ \t]+$/u, "");
|
|
68571
68578
|
editSchema = external_exports.object({
|
|
@@ -68639,7 +68646,7 @@ ${instructionsDescription}`,
|
|
|
68639
68646
|
"A list of edits to be sequentially applied to the file. Required for `edit` action."
|
|
68640
68647
|
)
|
|
68641
68648
|
}),
|
|
68642
|
-
execute: async ({ action, path:
|
|
68649
|
+
execute: async ({ action, path: path13, text: text2, range, edits }) => {
|
|
68643
68650
|
try {
|
|
68644
68651
|
const { sandbox } = await sandboxManager.getSandbox();
|
|
68645
68652
|
switch (action) {
|
|
@@ -68649,7 +68656,7 @@ ${instructionsDescription}`,
|
|
|
68649
68656
|
captureFileViewImageUsage({
|
|
68650
68657
|
context: context2,
|
|
68651
68658
|
sandbox,
|
|
68652
|
-
path:
|
|
68659
|
+
path: path13,
|
|
68653
68660
|
outcome: "unsupported_model",
|
|
68654
68661
|
durationMs: Date.now() - viewStartedAt,
|
|
68655
68662
|
failureReason: "unsupported_model"
|
|
@@ -68658,26 +68665,26 @@ ${instructionsDescription}`,
|
|
|
68658
68665
|
}
|
|
68659
68666
|
let viewPayload;
|
|
68660
68667
|
try {
|
|
68661
|
-
viewPayload = await readSandboxFileForView(sandbox,
|
|
68668
|
+
viewPayload = await readSandboxFileForView(sandbox, path13, false);
|
|
68662
68669
|
} catch (error51) {
|
|
68663
68670
|
captureFileViewImageUsage({
|
|
68664
68671
|
context: context2,
|
|
68665
68672
|
sandbox,
|
|
68666
|
-
path:
|
|
68673
|
+
path: path13,
|
|
68667
68674
|
outcome: "inspection_failed",
|
|
68668
68675
|
durationMs: Date.now() - viewStartedAt,
|
|
68669
68676
|
failureReason: classifyFileViewError(error51)
|
|
68670
68677
|
});
|
|
68671
68678
|
throw error51;
|
|
68672
68679
|
}
|
|
68673
|
-
const filename = getFilename(
|
|
68680
|
+
const filename = getFilename(path13);
|
|
68674
68681
|
let previewFiles = [];
|
|
68675
68682
|
let previewUploadError;
|
|
68676
68683
|
try {
|
|
68677
68684
|
previewFiles = await uploadViewPreviewFiles({
|
|
68678
68685
|
context: context2,
|
|
68679
68686
|
sandbox,
|
|
68680
|
-
sourcePath:
|
|
68687
|
+
sourcePath: path13,
|
|
68681
68688
|
payload: viewPayload
|
|
68682
68689
|
});
|
|
68683
68690
|
} catch (error51) {
|
|
@@ -68691,7 +68698,7 @@ ${instructionsDescription}`,
|
|
|
68691
68698
|
user_id: context2.userID,
|
|
68692
68699
|
sandbox_type: getViewSandboxType(sandbox),
|
|
68693
68700
|
file_name: filename,
|
|
68694
|
-
source_path:
|
|
68701
|
+
source_path: path13,
|
|
68695
68702
|
kind: viewPayload.kind,
|
|
68696
68703
|
media_type: viewPayload.mediaType,
|
|
68697
68704
|
size_bytes: viewPayload.sizeBytes,
|
|
@@ -68702,7 +68709,7 @@ ${instructionsDescription}`,
|
|
|
68702
68709
|
captureFileViewImageUsage({
|
|
68703
68710
|
context: context2,
|
|
68704
68711
|
sandbox,
|
|
68705
|
-
path:
|
|
68712
|
+
path: path13,
|
|
68706
68713
|
outcome: "success",
|
|
68707
68714
|
durationMs: Date.now() - viewStartedAt,
|
|
68708
68715
|
mediaType: viewPayload.mediaType,
|
|
@@ -68712,7 +68719,7 @@ ${instructionsDescription}`,
|
|
|
68712
68719
|
return {
|
|
68713
68720
|
action: "view",
|
|
68714
68721
|
content: `Viewing image file: ${filename} (${viewPayload.mediaType}, ${viewPayload.sizeBytes} bytes).`,
|
|
68715
|
-
path:
|
|
68722
|
+
path: path13,
|
|
68716
68723
|
filename,
|
|
68717
68724
|
mediaType: viewPayload.mediaType,
|
|
68718
68725
|
sizeBytes: viewPayload.sizeBytes,
|
|
@@ -68722,8 +68729,8 @@ ${instructionsDescription}`,
|
|
|
68722
68729
|
};
|
|
68723
68730
|
}
|
|
68724
68731
|
case "read": {
|
|
68725
|
-
const filename =
|
|
68726
|
-
const spritChunked = isSpritPath(
|
|
68732
|
+
const filename = path13.split("/").pop() || path13;
|
|
68733
|
+
const spritChunked = isSpritPath(path13);
|
|
68727
68734
|
let effectiveRange = range;
|
|
68728
68735
|
if (spritChunked) {
|
|
68729
68736
|
const start = range && range[0] > 0 ? range[0] : 1;
|
|
@@ -68736,7 +68743,7 @@ ${instructionsDescription}`,
|
|
|
68736
68743
|
}
|
|
68737
68744
|
const readPayload = await readSandboxTextFileWithFallback(
|
|
68738
68745
|
sandbox,
|
|
68739
|
-
|
|
68746
|
+
path13,
|
|
68740
68747
|
effectiveRange
|
|
68741
68748
|
);
|
|
68742
68749
|
if (readPayload.tooLarge) {
|
|
@@ -68773,46 +68780,46 @@ File is too large to read in full (${formatBytes(readPayload.sizeBytes)}, ${tota
|
|
|
68773
68780
|
if (text2 === void 0) {
|
|
68774
68781
|
return { error: "text is required for write action" };
|
|
68775
68782
|
}
|
|
68776
|
-
await sandbox.files.write(
|
|
68783
|
+
await sandbox.files.write(path13, text2, {
|
|
68777
68784
|
user: "user"
|
|
68778
68785
|
});
|
|
68779
|
-
return `File written: ${
|
|
68786
|
+
return `File written: ${path13}`;
|
|
68780
68787
|
}
|
|
68781
68788
|
case "append": {
|
|
68782
68789
|
if (text2 === void 0) {
|
|
68783
68790
|
return { error: "text is required for append action" };
|
|
68784
68791
|
}
|
|
68785
|
-
const existingState = await getSandboxFileState(sandbox,
|
|
68792
|
+
const existingState = await getSandboxFileState(sandbox, path13);
|
|
68786
68793
|
if (existingState.kind === "unknown") {
|
|
68787
68794
|
return {
|
|
68788
|
-
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}`
|
|
68789
68796
|
};
|
|
68790
68797
|
}
|
|
68791
68798
|
if (existingState.kind === "not_file") {
|
|
68792
68799
|
return {
|
|
68793
|
-
error: `Cannot append to ${
|
|
68800
|
+
error: `Cannot append to ${path13} because it is not a file.`
|
|
68794
68801
|
};
|
|
68795
68802
|
}
|
|
68796
68803
|
if (existingState.kind === "file" && existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
|
|
68797
|
-
await appendSandboxTextFile(sandbox,
|
|
68804
|
+
await appendSandboxTextFile(sandbox, path13, text2);
|
|
68798
68805
|
return {
|
|
68799
|
-
content: `File appended: ${
|
|
68806
|
+
content: `File appended: ${path13}
|
|
68800
68807
|
Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff preview was skipped to avoid loading the entire file into memory.`
|
|
68801
68808
|
};
|
|
68802
68809
|
}
|
|
68803
68810
|
let existingContent = "";
|
|
68804
68811
|
try {
|
|
68805
|
-
existingContent = await sandbox.files.read(
|
|
68812
|
+
existingContent = await sandbox.files.read(path13, {
|
|
68806
68813
|
user: "user"
|
|
68807
68814
|
});
|
|
68808
68815
|
} catch {
|
|
68809
68816
|
}
|
|
68810
68817
|
const newContent = existingContent + text2;
|
|
68811
|
-
await sandbox.files.write(
|
|
68818
|
+
await sandbox.files.write(path13, newContent, {
|
|
68812
68819
|
user: "user"
|
|
68813
68820
|
});
|
|
68814
68821
|
return {
|
|
68815
|
-
content: `File appended: ${
|
|
68822
|
+
content: `File appended: ${path13}`,
|
|
68816
68823
|
originalContent: truncateOutput({
|
|
68817
68824
|
content: existingContent,
|
|
68818
68825
|
mode: "read-file"
|
|
@@ -68827,31 +68834,31 @@ Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff previ
|
|
|
68827
68834
|
if (!edits || edits.length === 0) {
|
|
68828
68835
|
return { error: "edits array is required for edit action" };
|
|
68829
68836
|
}
|
|
68830
|
-
const existingState = await getSandboxFileState(sandbox,
|
|
68837
|
+
const existingState = await getSandboxFileState(sandbox, path13);
|
|
68831
68838
|
if (existingState.kind === "unknown") {
|
|
68832
68839
|
return {
|
|
68833
|
-
error: `Cannot edit ${
|
|
68840
|
+
error: `Cannot edit ${path13} safely because the file size could not be determined. ${existingState.error}`
|
|
68834
68841
|
};
|
|
68835
68842
|
}
|
|
68836
68843
|
if (existingState.kind === "missing") {
|
|
68837
68844
|
return {
|
|
68838
|
-
error: `Cannot edit file ${
|
|
68845
|
+
error: `Cannot edit file ${path13} - file is empty or does not exist`
|
|
68839
68846
|
};
|
|
68840
68847
|
}
|
|
68841
68848
|
if (existingState.kind === "not_file") {
|
|
68842
|
-
return { error: `Cannot edit ${
|
|
68849
|
+
return { error: `Cannot edit ${path13} because it is not a file.` };
|
|
68843
68850
|
}
|
|
68844
68851
|
if (existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
|
|
68845
68852
|
return {
|
|
68846
|
-
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.`
|
|
68847
68854
|
};
|
|
68848
68855
|
}
|
|
68849
|
-
const originalContent = await sandbox.files.read(
|
|
68856
|
+
const originalContent = await sandbox.files.read(path13, {
|
|
68850
68857
|
user: "user"
|
|
68851
68858
|
});
|
|
68852
68859
|
if (!originalContent) {
|
|
68853
68860
|
return {
|
|
68854
|
-
error: `Cannot edit file ${
|
|
68861
|
+
error: `Cannot edit file ${path13} - file is empty or does not exist`
|
|
68855
68862
|
};
|
|
68856
68863
|
}
|
|
68857
68864
|
const resolvedEdits = [];
|
|
@@ -68896,7 +68903,7 @@ ${hint}` : "")
|
|
|
68896
68903
|
}
|
|
68897
68904
|
}
|
|
68898
68905
|
}
|
|
68899
|
-
await sandbox.files.write(
|
|
68906
|
+
await sandbox.files.write(path13, content, {
|
|
68900
68907
|
user: "user"
|
|
68901
68908
|
});
|
|
68902
68909
|
const lines = content.split("\n");
|
|
@@ -68988,419 +68995,483 @@ ${numberedLines}`,
|
|
|
68988
68995
|
}
|
|
68989
68996
|
});
|
|
68990
68997
|
|
|
68991
|
-
//
|
|
68992
|
-
|
|
68993
|
-
|
|
68994
|
-
|
|
68995
|
-
|
|
68996
|
-
|
|
68997
|
-
SENSITIVE_FIELD_PATTERN = /(["']?\b(?:serviceKey|service_key|apiKey|api_key|authorization|bearer|cookie|password|secret|token)\b["']?)(\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,}]+)/gi;
|
|
68998
|
-
ENV_SECRET_PATTERN = /(["']?\b(?:CONVEX_SERVICE_ROLE_KEY|POSTHOG_API_KEY|STRIPE_SECRET_KEY)\b["']?)(\s*[:=]\s*)(?:"[^"]*"|'[^']*'|[^\s,}]+)/gi;
|
|
68999
|
-
redactSensitiveErrorMessage = (message) => message.replace(SENSITIVE_FIELD_PATTERN, (_match, key, separator) => {
|
|
69000
|
-
return `${key}${separator}"${REDACTED_VALUE}"`;
|
|
69001
|
-
}).replace(ENV_SECRET_PATTERN, (_match, key, separator) => {
|
|
69002
|
-
return `${key}${separator}"${REDACTED_VALUE}"`;
|
|
69003
|
-
});
|
|
69004
|
-
stringifyRedactedError = (error51) => {
|
|
69005
|
-
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) {
|
|
69006
69004
|
try {
|
|
69007
|
-
return
|
|
69005
|
+
return String.fromCodePoint(num);
|
|
69008
69006
|
} catch {
|
|
69009
|
-
return
|
|
69007
|
+
return whole;
|
|
69010
69008
|
}
|
|
69011
|
-
})();
|
|
69012
|
-
return redactSensitiveErrorMessage(message);
|
|
69013
|
-
};
|
|
69014
|
-
}
|
|
69015
|
-
});
|
|
69016
|
-
|
|
69017
|
-
// ../lib/ai/tools/utils/perplexity.ts
|
|
69018
|
-
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;
|
|
69019
|
-
var init_perplexity = __esm({
|
|
69020
|
-
"../lib/ai/tools/utils/perplexity.ts"() {
|
|
69021
|
-
"use strict";
|
|
69022
|
-
SEARCH_RESULT_CONTENT_MAX_TOKENS = 250;
|
|
69023
|
-
RECENCY_MAP = {
|
|
69024
|
-
past_day: "day",
|
|
69025
|
-
past_week: "week",
|
|
69026
|
-
past_month: "month",
|
|
69027
|
-
past_year: "year"
|
|
69028
|
-
};
|
|
69029
|
-
PerplexityApiError = class extends Error {
|
|
69030
|
-
constructor({
|
|
69031
|
-
status,
|
|
69032
|
-
statusText,
|
|
69033
|
-
bodySummary,
|
|
69034
|
-
retryable
|
|
69035
|
-
}) {
|
|
69036
|
-
const statusLabel = statusText ? `${status} ${statusText}` : `${status}`;
|
|
69037
|
-
const summary = bodySummary ? `: ${bodySummary}` : "";
|
|
69038
|
-
super(`Perplexity API error ${statusLabel}${summary}`);
|
|
69039
|
-
this.name = "PerplexityApiError";
|
|
69040
|
-
this.status = status;
|
|
69041
|
-
this.statusText = statusText;
|
|
69042
|
-
this.bodySummary = bodySummary;
|
|
69043
|
-
this.retryable = retryable;
|
|
69044
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
|
|
69045
69155
|
};
|
|
69046
|
-
|
|
69047
|
-
|
|
69048
|
-
|
|
69049
|
-
|
|
69050
|
-
|
|
69051
|
-
|
|
69052
|
-
|
|
69053
|
-
|
|
69054
|
-
|
|
69055
|
-
|
|
69056
|
-
|
|
69057
|
-
|
|
69058
|
-
|
|
69059
|
-
|
|
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
|
|
69060
69217
|
});
|
|
69061
|
-
|
|
69062
|
-
|
|
69063
|
-
|
|
69064
|
-
|
|
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}` : "")
|
|
69065
69272
|
);
|
|
69066
|
-
|
|
69067
|
-
|
|
69068
|
-
|
|
69069
|
-
);
|
|
69070
|
-
|
|
69071
|
-
|
|
69072
|
-
|
|
69073
|
-
|
|
69074
|
-
|
|
69075
|
-
|
|
69076
|
-
|
|
69077
|
-
|
|
69078
|
-
|
|
69079
|
-
const trimmed = body.trim();
|
|
69080
|
-
if (!trimmed) return "";
|
|
69081
|
-
let summary = "";
|
|
69082
|
-
if (contentType.includes("json") || trimmed.startsWith("{")) {
|
|
69083
|
-
try {
|
|
69084
|
-
const parsed = JSON.parse(trimmed);
|
|
69085
|
-
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;
|
|
69086
|
-
const message = error51 || (typeof parsed.message === "string" ? parsed.message : void 0) || (typeof parsed.detail === "string" ? parsed.detail : void 0);
|
|
69087
|
-
summary = message || trimmed;
|
|
69088
|
-
} catch {
|
|
69089
|
-
summary = trimmed;
|
|
69090
|
-
}
|
|
69091
|
-
} else if (/<[a-z][\s\S]*>/i.test(trimmed)) {
|
|
69092
|
-
const tagSummaries = [
|
|
69093
|
-
...extractHtmlTagText(trimmed, "h1"),
|
|
69094
|
-
...extractHtmlTagText(trimmed, "p"),
|
|
69095
|
-
...extractHtmlTagText(trimmed, "h2")
|
|
69096
|
-
];
|
|
69097
|
-
summary = tagSummaries.length > 0 ? tagSummaries.join(". ") : stripHtml(trimmed);
|
|
69098
|
-
} else {
|
|
69099
|
-
summary = trimmed;
|
|
69100
|
-
}
|
|
69101
|
-
return truncateSummary(redactNetworkDetails(normalizeWhitespace(summary)));
|
|
69102
|
-
};
|
|
69103
|
-
buildPerplexitySearchBody = (query, options) => {
|
|
69104
|
-
const searchBody = {
|
|
69105
|
-
query,
|
|
69106
|
-
max_results: options?.maxResults ?? 10,
|
|
69107
|
-
max_tokens_per_page: SEARCH_RESULT_CONTENT_MAX_TOKENS
|
|
69108
|
-
};
|
|
69109
|
-
if (options?.country) {
|
|
69110
|
-
searchBody.country = options.country;
|
|
69111
|
-
}
|
|
69112
|
-
if (options?.recency) {
|
|
69113
|
-
searchBody.search_recency_filter = options.recency;
|
|
69114
|
-
}
|
|
69115
|
-
return searchBody;
|
|
69116
|
-
};
|
|
69117
|
-
formatSearchResults = (results) => {
|
|
69118
|
-
return results.map((result) => ({
|
|
69119
|
-
title: result.title,
|
|
69120
|
-
url: result.url,
|
|
69121
|
-
content: result.snippet,
|
|
69122
|
-
date: result.date || null,
|
|
69123
|
-
lastUpdated: result.last_updated || null
|
|
69124
|
-
}));
|
|
69125
|
-
};
|
|
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;
|
|
69126
69286
|
}
|
|
69127
|
-
}
|
|
69128
|
-
|
|
69129
|
-
|
|
69130
|
-
|
|
69131
|
-
var init_web_search = __esm({
|
|
69132
|
-
"../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"() {
|
|
69133
69291
|
"use strict";
|
|
69134
69292
|
init_dist5();
|
|
69135
69293
|
init_zod();
|
|
69136
|
-
|
|
69137
|
-
|
|
69138
|
-
|
|
69139
|
-
|
|
69140
|
-
|
|
69141
|
-
|
|
69142
|
-
|
|
69143
|
-
|
|
69144
|
-
|
|
69145
|
-
|
|
69146
|
-
|
|
69147
|
-
|
|
69148
|
-
|
|
69149
|
-
|
|
69150
|
-
|
|
69151
|
-
|
|
69152
|
-
|
|
69153
|
-
|
|
69154
|
-
|
|
69155
|
-
|
|
69156
|
-
|
|
69157
|
-
|
|
69158
|
-
|
|
69159
|
-
const timeout = setTimeout(() => {
|
|
69160
|
-
cleanup();
|
|
69161
|
-
resolve2();
|
|
69162
|
-
}, delayMs);
|
|
69163
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
69164
|
-
});
|
|
69165
|
-
};
|
|
69166
|
-
getRetryDelayMs = (attemptIndex) => {
|
|
69167
|
-
const exponentialDelay = WEB_SEARCH_RETRY_BASE_DELAY_MS * Math.pow(2, attemptIndex);
|
|
69168
|
-
const jitter = Math.random() * WEB_SEARCH_RETRY_JITTER_MS;
|
|
69169
|
-
return Math.round(exponentialDelay + jitter);
|
|
69170
|
-
};
|
|
69171
|
-
createPerplexityApiError = async (response) => {
|
|
69172
|
-
const errorText = await response.text();
|
|
69173
|
-
const bodySummary = summarizePerplexityErrorBody(
|
|
69174
|
-
errorText,
|
|
69175
|
-
response.headers.get("content-type") || ""
|
|
69176
|
-
);
|
|
69177
|
-
return new PerplexityApiError({
|
|
69178
|
-
status: response.status,
|
|
69179
|
-
statusText: response.statusText,
|
|
69180
|
-
bodySummary,
|
|
69181
|
-
retryable: isRetryablePerplexityStatus(response.status)
|
|
69182
|
-
});
|
|
69183
|
-
};
|
|
69184
|
-
formatPerplexityFailureForTool = (error51, attempts) => {
|
|
69185
|
-
const statusText = error51.statusText ? ` ${error51.statusText}` : "";
|
|
69186
|
-
if (error51.retryable) {
|
|
69187
|
-
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.`;
|
|
69188
|
-
}
|
|
69189
|
-
if (error51.status === 401 || error51.status === 403) {
|
|
69190
|
-
return `Error performing web search: Perplexity search is not authorized (HTTP ${error51.status}${statusText}). Check the Perplexity API key or account access.`;
|
|
69191
|
-
}
|
|
69192
|
-
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": "'"
|
|
69193
69317
|
};
|
|
69194
|
-
|
|
69195
|
-
|
|
69196
|
-
|
|
69197
|
-
|
|
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.";
|
|
69198
69344
|
try {
|
|
69199
|
-
const
|
|
69200
|
-
|
|
69201
|
-
|
|
69202
|
-
|
|
69203
|
-
|
|
69204
|
-
|
|
69205
|
-
body: JSON.stringify(searchBody),
|
|
69206
|
-
signal: abortSignal
|
|
69207
|
-
});
|
|
69208
|
-
if (response.ok) {
|
|
69209
|
-
return response;
|
|
69210
|
-
}
|
|
69211
|
-
const error51 = await createPerplexityApiError(response);
|
|
69212
|
-
if (!error51.retryable || isFinalAttempt) {
|
|
69213
|
-
throw error51;
|
|
69214
|
-
}
|
|
69215
|
-
const delayMs = getRetryDelayMs(attemptIndex);
|
|
69216
|
-
console.warn("Web search provider error; retrying", {
|
|
69217
|
-
attempt,
|
|
69218
|
-
maxAttempts: WEB_SEARCH_MAX_ATTEMPTS,
|
|
69219
|
-
status: error51.status,
|
|
69220
|
-
statusText: error51.statusText,
|
|
69221
|
-
bodySummary: error51.bodySummary,
|
|
69222
|
-
delayMs
|
|
69223
|
-
});
|
|
69224
|
-
await sleep2(delayMs, abortSignal);
|
|
69225
|
-
} catch (error51) {
|
|
69226
|
-
if (error51 instanceof Error && error51.name === "AbortError") {
|
|
69227
|
-
throw error51;
|
|
69228
|
-
}
|
|
69229
|
-
if (error51 instanceof PerplexityApiError) {
|
|
69230
|
-
throw error51;
|
|
69231
|
-
}
|
|
69232
|
-
if (isFinalAttempt) {
|
|
69233
|
-
throw error51;
|
|
69234
|
-
}
|
|
69235
|
-
const delayMs = getRetryDelayMs(attemptIndex);
|
|
69236
|
-
console.warn("Web search network error; retrying", {
|
|
69237
|
-
attempt,
|
|
69238
|
-
maxAttempts: WEB_SEARCH_MAX_ATTEMPTS,
|
|
69239
|
-
error: stringifyRedactedError(error51),
|
|
69240
|
-
delayMs
|
|
69241
|
-
});
|
|
69242
|
-
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)}`;
|
|
69243
69351
|
}
|
|
69244
69352
|
}
|
|
69245
|
-
|
|
69246
|
-
|
|
69247
|
-
|
|
69248
|
-
const queries = rawQueries.map((query) => query.trim()).filter(Boolean);
|
|
69249
|
-
if (queries.length === 0) {
|
|
69250
|
-
return { queries, error: EMPTY_QUERY_TOOL_ERROR };
|
|
69251
|
-
}
|
|
69252
|
-
if (queries.some((query) => query.length > PERPLEXITY_QUERY_MAX_LENGTH)) {
|
|
69253
|
-
return { queries, error: QUERY_TOO_LONG_TOOL_ERROR };
|
|
69254
|
-
}
|
|
69255
|
-
return { queries: queries.slice(0, 3) };
|
|
69256
|
-
};
|
|
69257
|
-
createWebSearch = (context2) => {
|
|
69258
|
-
const { userLocation, onToolCost } = context2;
|
|
69259
|
-
return tool({
|
|
69260
|
-
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.
|
|
69261
69356
|
|
|
69262
69357
|
<instructions>
|
|
69263
|
-
-
|
|
69264
|
-
-
|
|
69265
|
-
-
|
|
69266
|
-
- For complex searches, MUST break down into step-by-step searches instead of using a single complex query
|
|
69267
|
-
- Access multiple URLs from search results for comprehensive information or cross-validation
|
|
69268
|
-
- CAN use Google dork syntax (site:, filetype:, inurl:, intitle:, etc.) for targeted reconnaissance and pentest enumeration
|
|
69269
|
-
- Only use \`time\` parameter when explicitly required by task, otherwise leave time range unrestricted
|
|
69270
|
-
- Prioritize cybersecurity-relevant information: CVEs, CVSS scores, exploits, PoCs, security tools, and pentest methodologies
|
|
69271
|
-
- Include specific versions, configurations, and technical details; cite reliable sources (NIST, OWASP, CVE databases)
|
|
69272
|
-
- 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.
|
|
69273
69361
|
</instructions>`,
|
|
69274
|
-
|
|
69275
|
-
|
|
69276
|
-
|
|
69277
|
-
|
|
69278
|
-
|
|
69279
|
-
|
|
69280
|
-
|
|
69281
|
-
|
|
69282
|
-
|
|
69283
|
-
)
|
|
69284
|
-
|
|
69285
|
-
|
|
69286
|
-
|
|
69287
|
-
|
|
69288
|
-
|
|
69289
|
-
|
|
69290
|
-
|
|
69291
|
-
|
|
69292
|
-
|
|
69293
|
-
|
|
69294
|
-
|
|
69295
|
-
|
|
69296
|
-
{
|
|
69297
|
-
country: userLocation?.country,
|
|
69298
|
-
recency: time3 && time3 !== "all" ? RECENCY_MAP[time3] : void 0
|
|
69299
|
-
}
|
|
69300
|
-
);
|
|
69301
|
-
const response = await fetchPerplexitySearch(searchBody, abortSignal);
|
|
69302
|
-
onToolCost?.(WEB_SEARCH_COST_PER_REQUEST);
|
|
69303
|
-
const searchResponse = await response.json();
|
|
69304
|
-
const isMultiQuery = queries.length > 1;
|
|
69305
|
-
let allResults;
|
|
69306
|
-
if (isMultiQuery && Array.isArray(searchResponse.results[0])) {
|
|
69307
|
-
allResults = searchResponse.results.flat();
|
|
69308
|
-
} else {
|
|
69309
|
-
allResults = searchResponse.results;
|
|
69310
|
-
}
|
|
69311
|
-
return formatSearchResults(allResults);
|
|
69312
|
-
} catch (error51) {
|
|
69313
|
-
if (error51 instanceof Error && error51.name === "AbortError") {
|
|
69314
|
-
return "Error: Operation aborted";
|
|
69315
|
-
}
|
|
69316
|
-
if (error51 instanceof PerplexityApiError) {
|
|
69317
|
-
console.error("Web search tool error:", {
|
|
69318
|
-
name: error51.name,
|
|
69319
|
-
status: error51.status,
|
|
69320
|
-
statusText: error51.statusText,
|
|
69321
|
-
retryable: error51.retryable,
|
|
69322
|
-
bodySummary: error51.bodySummary
|
|
69323
|
-
});
|
|
69324
|
-
return formatPerplexityFailureForTool(
|
|
69325
|
-
error51,
|
|
69326
|
-
error51.retryable ? WEB_SEARCH_MAX_ATTEMPTS : 1
|
|
69327
|
-
);
|
|
69328
|
-
}
|
|
69329
|
-
const errorMessage = stringifyRedactedError(error51);
|
|
69330
|
-
console.error("Web search tool error:", errorMessage);
|
|
69331
|
-
return `Error performing web search: ${errorMessage}`;
|
|
69332
|
-
}
|
|
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)}`;
|
|
69333
69384
|
}
|
|
69334
|
-
}
|
|
69335
|
-
};
|
|
69336
|
-
|
|
69337
|
-
|
|
69338
|
-
|
|
69339
|
-
// ../lib/ai/tools/open-url.ts
|
|
69340
|
-
var createOpenUrlTool;
|
|
69341
|
-
var init_open_url = __esm({
|
|
69342
|
-
"../lib/ai/tools/open-url.ts"() {
|
|
69343
|
-
"use strict";
|
|
69344
|
-
init_dist5();
|
|
69345
|
-
init_zod();
|
|
69346
|
-
init_token_utils();
|
|
69347
|
-
createOpenUrlTool = () => {
|
|
69348
|
-
return tool({
|
|
69349
|
-
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.
|
|
69350
69389
|
|
|
69351
69390
|
<instructions>
|
|
69352
|
-
-
|
|
69353
|
-
-
|
|
69354
|
-
-
|
|
69355
|
-
-
|
|
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.
|
|
69356
69395
|
</instructions>`,
|
|
69357
|
-
|
|
69358
|
-
|
|
69359
|
-
|
|
69360
|
-
|
|
69361
|
-
|
|
69362
|
-
|
|
69363
|
-
|
|
69364
|
-
|
|
69365
|
-
|
|
69366
|
-
|
|
69367
|
-
|
|
69368
|
-
|
|
69369
|
-
|
|
69370
|
-
|
|
69371
|
-
|
|
69372
|
-
|
|
69373
|
-
|
|
69374
|
-
|
|
69375
|
-
|
|
69376
|
-
|
|
69377
|
-
|
|
69378
|
-
|
|
69379
|
-
|
|
69380
|
-
|
|
69381
|
-
|
|
69382
|
-
|
|
69383
|
-
|
|
69384
|
-
|
|
69385
|
-
|
|
69386
|
-
|
|
69387
|
-
|
|
69388
|
-
|
|
69389
|
-
|
|
69390
|
-
|
|
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)}`;
|
|
69391
69462
|
}
|
|
69392
|
-
}
|
|
69393
|
-
};
|
|
69463
|
+
}
|
|
69464
|
+
});
|
|
69394
69465
|
}
|
|
69395
69466
|
});
|
|
69396
69467
|
|
|
69397
69468
|
// src/tools/scope.ts
|
|
69398
|
-
var
|
|
69469
|
+
var import_node_fs7, import_node_path6, import_promises, ipv4ToInt, isIpLiteral, maskForPrefix, parseCidr, ScopeImpl, scopeFileFor, loadScope, hostFromUrl;
|
|
69399
69470
|
var init_scope = __esm({
|
|
69400
69471
|
"src/tools/scope.ts"() {
|
|
69401
69472
|
"use strict";
|
|
69402
|
-
|
|
69403
|
-
|
|
69473
|
+
import_node_fs7 = __toESM(require("node:fs"));
|
|
69474
|
+
import_node_path6 = __toESM(require("node:path"));
|
|
69404
69475
|
import_promises = __toESM(require("node:dns/promises"));
|
|
69405
69476
|
ipv4ToInt = (ip) => {
|
|
69406
69477
|
const parts = ip.split(".");
|
|
@@ -69498,11 +69569,11 @@ var init_scope = __esm({
|
|
|
69498
69569
|
return false;
|
|
69499
69570
|
}
|
|
69500
69571
|
};
|
|
69501
|
-
scopeFileFor = (workdir) =>
|
|
69572
|
+
scopeFileFor = (workdir) => import_node_path6.default.join(workdir, "recon", "scope.txt");
|
|
69502
69573
|
loadScope = (workdir) => {
|
|
69503
69574
|
const file2 = scopeFileFor(workdir);
|
|
69504
69575
|
try {
|
|
69505
|
-
const text2 =
|
|
69576
|
+
const text2 = import_node_fs7.default.readFileSync(file2, "utf8");
|
|
69506
69577
|
return ScopeImpl.parse(text2, file2);
|
|
69507
69578
|
} catch {
|
|
69508
69579
|
return ScopeImpl.parse("", null);
|
|
@@ -69519,7 +69590,7 @@ var init_scope = __esm({
|
|
|
69519
69590
|
});
|
|
69520
69591
|
|
|
69521
69592
|
// src/tools/http-request.ts
|
|
69522
|
-
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;
|
|
69523
69594
|
var init_http_request = __esm({
|
|
69524
69595
|
"src/tools/http-request.ts"() {
|
|
69525
69596
|
"use strict";
|
|
@@ -69535,7 +69606,7 @@ var init_http_request = __esm({
|
|
|
69535
69606
|
const raw = Number(process.env[name25]);
|
|
69536
69607
|
return Number.isFinite(raw) && raw >= 0 ? raw : void 0;
|
|
69537
69608
|
};
|
|
69538
|
-
|
|
69609
|
+
sleep2 = (ms, signal) => new Promise((resolve2) => {
|
|
69539
69610
|
if (ms <= 0 || signal?.aborted) return resolve2();
|
|
69540
69611
|
const t = setTimeout(resolve2, ms);
|
|
69541
69612
|
signal?.addEventListener(
|
|
@@ -69656,7 +69727,7 @@ var init_http_request = __esm({
|
|
|
69656
69727
|
};
|
|
69657
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.`;
|
|
69658
69729
|
createHttpRequest = (deps) => {
|
|
69659
|
-
const { workdir, loadScopeFn = loadScope } = deps;
|
|
69730
|
+
const { workdir, loadScopeFn = loadScope, unrestricted = false } = deps;
|
|
69660
69731
|
const envThrottle = numberEnv("clawfast_HTTP_THROTTLE_MS");
|
|
69661
69732
|
const envJitter = numberEnv("clawfast_HTTP_JITTER_MS");
|
|
69662
69733
|
return tool({
|
|
@@ -69670,20 +69741,30 @@ SCOPE: every request is gated by recon/scope.txt (same allowlist as the recon to
|
|
|
69670
69741
|
|
|
69671
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.`,
|
|
69672
69743
|
inputSchema: external_exports.object({
|
|
69673
|
-
brief: external_exports.string().describe(
|
|
69744
|
+
brief: external_exports.string().describe(
|
|
69745
|
+
"A one-sentence preamble describing the purpose of this request."
|
|
69746
|
+
),
|
|
69674
69747
|
url: external_exports.string().url().describe(
|
|
69675
69748
|
"Target URL. May contain the marker FUZZ (replaced by each fuzz payload)."
|
|
69676
69749
|
),
|
|
69677
69750
|
method: external_exports.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]).optional().describe("HTTP method (default GET)."),
|
|
69678
69751
|
headers: external_exports.record(external_exports.string(), external_exports.string()).optional().describe("Request headers. Values may contain FUZZ."),
|
|
69679
69752
|
body: external_exports.string().optional().describe("Request body for POST/PUT/PATCH/DELETE. May contain FUZZ."),
|
|
69680
|
-
follow_redirects: external_exports.boolean().optional().describe(
|
|
69681
|
-
|
|
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
|
+
),
|
|
69682
69759
|
fuzz: external_exports.array(external_exports.string()).optional().describe(
|
|
69683
69760
|
`Intruder payloads \u2014 substituted into the FUZZ marker, one request each (max ${MAX_FUZZ}).`
|
|
69684
69761
|
),
|
|
69685
|
-
throttle_ms: external_exports.number().optional().describe(
|
|
69686
|
-
|
|
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
|
+
)
|
|
69687
69768
|
}),
|
|
69688
69769
|
execute: async (input, { abortSignal } = {}) => {
|
|
69689
69770
|
const method = input.method ?? "GET";
|
|
@@ -69693,7 +69774,7 @@ USE FOR: testing a single endpoint, replaying/tampering a captured request, para
|
|
|
69693
69774
|
if (!host) {
|
|
69694
69775
|
return { error: `URL inv\xE1lida: ${input.url}` };
|
|
69695
69776
|
}
|
|
69696
|
-
if (!LOOPBACK.has(host)) {
|
|
69777
|
+
if (!unrestricted && !LOOPBACK.has(host)) {
|
|
69697
69778
|
const scope = loadScopeFn(workdir);
|
|
69698
69779
|
const allowed = await scope.allows(host);
|
|
69699
69780
|
if (!allowed) {
|
|
@@ -69733,7 +69814,13 @@ USE FOR: testing a single endpoint, replaying/tampering a captured request, para
|
|
|
69733
69814
|
abortSignal
|
|
69734
69815
|
);
|
|
69735
69816
|
if ("error" in res2) {
|
|
69736
|
-
rows.push({
|
|
69817
|
+
rows.push({
|
|
69818
|
+
payload,
|
|
69819
|
+
status: "ERR",
|
|
69820
|
+
bodyLength: 0,
|
|
69821
|
+
timeMs: res2.timeMs,
|
|
69822
|
+
error: res2.error
|
|
69823
|
+
});
|
|
69737
69824
|
} else {
|
|
69738
69825
|
rows.push({
|
|
69739
69826
|
payload,
|
|
@@ -69744,7 +69831,10 @@ USE FOR: testing a single endpoint, replaying/tampering a captured request, para
|
|
|
69744
69831
|
});
|
|
69745
69832
|
}
|
|
69746
69833
|
if (i < list.length - 1 && (throttle > 0 || jitter > 0)) {
|
|
69747
|
-
await
|
|
69834
|
+
await sleep2(
|
|
69835
|
+
throttle + Math.floor(Math.random() * (jitter + 1)),
|
|
69836
|
+
abortSignal
|
|
69837
|
+
);
|
|
69748
69838
|
}
|
|
69749
69839
|
}
|
|
69750
69840
|
return { fuzz: { host, count: rows.length, rows } };
|
|
@@ -69822,12 +69912,12 @@ ${s.bodyPreview}`
|
|
|
69822
69912
|
});
|
|
69823
69913
|
|
|
69824
69914
|
// src/tools/findings.ts
|
|
69825
|
-
var
|
|
69915
|
+
var import_node_fs8, import_node_path7, SEVERITIES, STATUSES, SEVERITY_RANK, SEVERITY_EMOJI, findingsStoreFor, readAll, writeAll, nextId, sortBySeverity, renderReport, oneLine, createFindings;
|
|
69826
69916
|
var init_findings = __esm({
|
|
69827
69917
|
"src/tools/findings.ts"() {
|
|
69828
69918
|
"use strict";
|
|
69829
|
-
|
|
69830
|
-
|
|
69919
|
+
import_node_fs8 = __toESM(require("node:fs"));
|
|
69920
|
+
import_node_path7 = __toESM(require("node:path"));
|
|
69831
69921
|
init_dist5();
|
|
69832
69922
|
init_zod();
|
|
69833
69923
|
SEVERITIES = [
|
|
@@ -69853,16 +69943,16 @@ var init_findings = __esm({
|
|
|
69853
69943
|
info: "\u26AA"
|
|
69854
69944
|
};
|
|
69855
69945
|
findingsStoreFor = (workdir) => {
|
|
69856
|
-
const findingsDir =
|
|
69946
|
+
const findingsDir = import_node_path7.default.join(workdir, "findings");
|
|
69857
69947
|
return {
|
|
69858
69948
|
findingsDir,
|
|
69859
|
-
storeFile:
|
|
69860
|
-
reportFile:
|
|
69949
|
+
storeFile: import_node_path7.default.join(findingsDir, "findings.json"),
|
|
69950
|
+
reportFile: import_node_path7.default.join(findingsDir, "report.md")
|
|
69861
69951
|
};
|
|
69862
69952
|
};
|
|
69863
69953
|
readAll = (store) => {
|
|
69864
69954
|
try {
|
|
69865
|
-
const raw =
|
|
69955
|
+
const raw = import_node_fs8.default.readFileSync(store.storeFile, "utf8");
|
|
69866
69956
|
const parsed = JSON.parse(raw);
|
|
69867
69957
|
return Array.isArray(parsed) ? parsed : [];
|
|
69868
69958
|
} catch {
|
|
@@ -69870,8 +69960,8 @@ var init_findings = __esm({
|
|
|
69870
69960
|
}
|
|
69871
69961
|
};
|
|
69872
69962
|
writeAll = (store, findings) => {
|
|
69873
|
-
|
|
69874
|
-
|
|
69963
|
+
import_node_fs8.default.mkdirSync(store.findingsDir, { recursive: true });
|
|
69964
|
+
import_node_fs8.default.writeFileSync(store.storeFile, JSON.stringify(findings, null, 2), "utf8");
|
|
69875
69965
|
};
|
|
69876
69966
|
nextId = (findings) => {
|
|
69877
69967
|
let max = 0;
|
|
@@ -69970,7 +70060,9 @@ ACTIONS
|
|
|
69970
70060
|
Use this together with http_request: probe \u2192 observe \u2192 record evidence \u2192 mark confirmed.`,
|
|
69971
70061
|
inputSchema: external_exports.object({
|
|
69972
70062
|
action: external_exports.enum(["add", "update", "list", "report"]),
|
|
69973
|
-
brief: external_exports.string().describe(
|
|
70063
|
+
brief: external_exports.string().describe(
|
|
70064
|
+
"A one-sentence preamble describing the purpose of this operation."
|
|
70065
|
+
),
|
|
69974
70066
|
id: external_exports.string().optional().describe("Finding id (e.g. F-001) \u2014 required for update."),
|
|
69975
70067
|
title: external_exports.string().optional(),
|
|
69976
70068
|
severity: external_exports.enum(SEVERITIES).optional(),
|
|
@@ -70043,7 +70135,9 @@ Use this together with http_request: probe \u2192 observe \u2192 record evidence
|
|
|
70043
70135
|
if (input.action === "list") {
|
|
70044
70136
|
let filtered = findings;
|
|
70045
70137
|
if (input.filter_severity) {
|
|
70046
|
-
filtered = filtered.filter(
|
|
70138
|
+
filtered = filtered.filter(
|
|
70139
|
+
(f) => f.severity === input.filter_severity
|
|
70140
|
+
);
|
|
70047
70141
|
}
|
|
70048
70142
|
if (input.filter_status) {
|
|
70049
70143
|
filtered = filtered.filter((f) => f.status === input.filter_status);
|
|
@@ -70055,8 +70149,8 @@ Use this together with http_request: probe \u2192 observe \u2192 record evidence
|
|
|
70055
70149
|
};
|
|
70056
70150
|
}
|
|
70057
70151
|
const md = renderReport(findings);
|
|
70058
|
-
|
|
70059
|
-
|
|
70152
|
+
import_node_fs8.default.mkdirSync(store.findingsDir, { recursive: true });
|
|
70153
|
+
import_node_fs8.default.writeFileSync(store.reportFile, md, "utf8");
|
|
70060
70154
|
return { report: store.reportFile, total: findings.length };
|
|
70061
70155
|
} catch (err) {
|
|
70062
70156
|
return {
|
|
@@ -70286,20 +70380,48 @@ var init_utils4 = __esm({
|
|
|
70286
70380
|
|
|
70287
70381
|
// src/local-sandbox.ts
|
|
70288
70382
|
function inferShellFlag(shell2) {
|
|
70289
|
-
const base =
|
|
70383
|
+
const base = import_node_path8.default.basename(shell2).toLowerCase();
|
|
70290
70384
|
if (base === "cmd" || base === "cmd.exe") return "/C";
|
|
70291
70385
|
if (base === "powershell" || base === "powershell.exe" || base === "pwsh") {
|
|
70292
70386
|
return "-Command";
|
|
70293
70387
|
}
|
|
70294
70388
|
return "-c";
|
|
70295
70389
|
}
|
|
70296
|
-
|
|
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;
|
|
70297
70419
|
var init_local_sandbox = __esm({
|
|
70298
70420
|
"src/local-sandbox.ts"() {
|
|
70299
70421
|
"use strict";
|
|
70300
70422
|
import_node_child_process2 = require("node:child_process");
|
|
70301
|
-
|
|
70302
|
-
|
|
70423
|
+
import_node_fs9 = require("node:fs");
|
|
70424
|
+
import_node_path8 = __toESM(require("node:path"));
|
|
70303
70425
|
import_node_os3 = __toESM(require("node:os"));
|
|
70304
70426
|
import_node_url = require("node:url");
|
|
70305
70427
|
init_utils4();
|
|
@@ -70311,6 +70433,10 @@ var init_local_sandbox = __esm({
|
|
|
70311
70433
|
// The most recent foreground child. Lets the CLI forward user-typed lines to
|
|
70312
70434
|
// a command that is waiting for stdin (interactive prompts, REPLs, etc.).
|
|
70313
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();
|
|
70314
70440
|
this.commands = {
|
|
70315
70441
|
run: (command, opts) => {
|
|
70316
70442
|
return new Promise((resolve2, reject) => {
|
|
@@ -70397,15 +70523,15 @@ var init_local_sandbox = __esm({
|
|
|
70397
70523
|
this.files = {
|
|
70398
70524
|
write: async (filePath, content) => {
|
|
70399
70525
|
const resolved = this.resolvePath(filePath);
|
|
70400
|
-
await
|
|
70526
|
+
await import_node_fs9.promises.mkdir(import_node_path8.default.dirname(resolved), { recursive: true });
|
|
70401
70527
|
const data = typeof content === "string" ? content : content instanceof ArrayBuffer ? Buffer.from(content) : content;
|
|
70402
|
-
await
|
|
70528
|
+
await import_node_fs9.promises.writeFile(resolved, data);
|
|
70403
70529
|
},
|
|
70404
70530
|
read: async (filePath) => {
|
|
70405
|
-
return
|
|
70531
|
+
return import_node_fs9.promises.readFile(this.resolvePath(filePath), "utf8");
|
|
70406
70532
|
},
|
|
70407
70533
|
remove: async (filePath) => {
|
|
70408
|
-
await
|
|
70534
|
+
await import_node_fs9.promises.rm(this.resolvePath(filePath), {
|
|
70409
70535
|
recursive: true,
|
|
70410
70536
|
force: true
|
|
70411
70537
|
});
|
|
@@ -70413,8 +70539,8 @@ var init_local_sandbox = __esm({
|
|
|
70413
70539
|
list: async (dirPath = ".") => {
|
|
70414
70540
|
const resolved = this.resolvePath(dirPath);
|
|
70415
70541
|
try {
|
|
70416
|
-
const entries = await
|
|
70417
|
-
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) }));
|
|
70418
70544
|
} catch {
|
|
70419
70545
|
return [];
|
|
70420
70546
|
}
|
|
@@ -70430,12 +70556,15 @@ var init_local_sandbox = __esm({
|
|
|
70430
70556
|
this.shellFlag = shell2.shellFlag;
|
|
70431
70557
|
}
|
|
70432
70558
|
const explicit = opts?.workdir || process.env.CLI_WORKDIR;
|
|
70433
|
-
const base = explicit ||
|
|
70559
|
+
const base = explicit || import_node_path8.default.join(process.cwd(), "SPRIT");
|
|
70434
70560
|
this.autoCreated = !explicit;
|
|
70435
|
-
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);
|
|
70436
70565
|
}
|
|
70437
70566
|
async init() {
|
|
70438
|
-
await
|
|
70567
|
+
await import_node_fs9.promises.mkdir(this.workdir, { recursive: true });
|
|
70439
70568
|
await this.seedReconToolkit();
|
|
70440
70569
|
await this.seedAuditToolkit();
|
|
70441
70570
|
}
|
|
@@ -70452,8 +70581,8 @@ var init_local_sandbox = __esm({
|
|
|
70452
70581
|
const assetsDir = (0, import_node_url.fileURLToPath)(
|
|
70453
70582
|
new URL("../assets/recon", import_meta.url)
|
|
70454
70583
|
);
|
|
70455
|
-
const destDir =
|
|
70456
|
-
await
|
|
70584
|
+
const destDir = import_node_path8.default.join(this.workdir, "recon");
|
|
70585
|
+
await import_node_fs9.promises.mkdir(destDir, { recursive: true });
|
|
70457
70586
|
const files = [
|
|
70458
70587
|
["recon_deep.py", true],
|
|
70459
70588
|
["recon_common.py", true],
|
|
@@ -70469,17 +70598,17 @@ var init_local_sandbox = __esm({
|
|
|
70469
70598
|
["scope.txt", false]
|
|
70470
70599
|
];
|
|
70471
70600
|
for (const [name25, overwrite] of files) {
|
|
70472
|
-
const dest =
|
|
70601
|
+
const dest = import_node_path8.default.join(destDir, name25);
|
|
70473
70602
|
if (!overwrite) {
|
|
70474
70603
|
try {
|
|
70475
|
-
await
|
|
70604
|
+
await import_node_fs9.promises.access(dest);
|
|
70476
70605
|
continue;
|
|
70477
70606
|
} catch {
|
|
70478
70607
|
}
|
|
70479
70608
|
}
|
|
70480
70609
|
try {
|
|
70481
|
-
const content = await
|
|
70482
|
-
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);
|
|
70483
70612
|
} catch {
|
|
70484
70613
|
}
|
|
70485
70614
|
}
|
|
@@ -70497,12 +70626,12 @@ var init_local_sandbox = __esm({
|
|
|
70497
70626
|
const assetsDir = (0, import_node_url.fileURLToPath)(
|
|
70498
70627
|
new URL("../assets/audit", import_meta.url)
|
|
70499
70628
|
);
|
|
70500
|
-
const destDir =
|
|
70501
|
-
await
|
|
70629
|
+
const destDir = import_node_path8.default.join(this.workdir, "audit");
|
|
70630
|
+
await import_node_fs9.promises.mkdir(destDir, { recursive: true });
|
|
70502
70631
|
for (const name25 of ["project_audit.py", "README.md"]) {
|
|
70503
70632
|
try {
|
|
70504
|
-
const content = await
|
|
70505
|
-
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);
|
|
70506
70635
|
} catch {
|
|
70507
70636
|
}
|
|
70508
70637
|
}
|
|
@@ -70521,6 +70650,30 @@ var init_local_sandbox = __esm({
|
|
|
70521
70650
|
isWindows() {
|
|
70522
70651
|
return import_node_os3.default.platform() === "win32" && !this.isBashLikeShell();
|
|
70523
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
|
+
}
|
|
70524
70677
|
supportsPty() {
|
|
70525
70678
|
return false;
|
|
70526
70679
|
}
|
|
@@ -70529,10 +70682,12 @@ var init_local_sandbox = __esm({
|
|
|
70529
70682
|
const shellInvocation = `${this.shellBin} ${this.shellFlag}`;
|
|
70530
70683
|
const windowsNotes = import_node_os3.default.platform() === "win32" ? this.getWindowsShellNotes() : "";
|
|
70531
70684
|
const pentestToolingNotes = this.getLocalPentestToolingNotes();
|
|
70532
|
-
|
|
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.
|
|
70533
70688
|
Commands are invoked via \`${shellInvocation}\`. The working directory is "${this.workdir}".
|
|
70534
70689
|
Be careful: file system, network and process operations all affect the real host system.
|
|
70535
|
-
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.
|
|
70536
70691
|
|
|
70537
70692
|
WORKSPACE - STRICT SCOPE:
|
|
70538
70693
|
- Your entire workspace is the directory: ${this.workdir}
|
|
@@ -70549,7 +70704,28 @@ EDITING SCRIPTS:
|
|
|
70549
70704
|
- When a script you wrote produces an error, fix the specific broken part.
|
|
70550
70705
|
- Do not recreate or fully overwrite a file just to fix one error.
|
|
70551
70706
|
- Use write only to create a brand-new file, or when changes to a short file are extensive.
|
|
70552
|
-
- 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." : ""}`;
|
|
70553
70729
|
}
|
|
70554
70730
|
getOsContext() {
|
|
70555
70731
|
return this.getSandboxContext();
|
|
@@ -70605,9 +70781,9 @@ EDITING SCRIPTS:
|
|
|
70605
70781
|
if (!this.autoCreated) return null;
|
|
70606
70782
|
const keep = (process.env.CLAWFAST_KEEP_SPRIT || "").trim().toLowerCase();
|
|
70607
70783
|
if (keep === "1" || keep === "true" || keep === "yes") return null;
|
|
70608
|
-
if (
|
|
70784
|
+
if (import_node_path8.default.basename(this.workdir).toUpperCase() !== "SPRIT") return null;
|
|
70609
70785
|
try {
|
|
70610
|
-
await
|
|
70786
|
+
await import_node_fs9.promises.rm(this.workdir, { recursive: true, force: true });
|
|
70611
70787
|
return this.workdir;
|
|
70612
70788
|
} catch {
|
|
70613
70789
|
return null;
|
|
@@ -70658,15 +70834,15 @@ EDITING SCRIPTS:
|
|
|
70658
70834
|
}
|
|
70659
70835
|
}
|
|
70660
70836
|
resolvePath(p) {
|
|
70661
|
-
if (
|
|
70662
|
-
return
|
|
70837
|
+
if (import_node_path8.default.isAbsolute(p)) return p;
|
|
70838
|
+
return import_node_path8.default.join(this.workdir, p);
|
|
70663
70839
|
}
|
|
70664
70840
|
isBashLikeShell() {
|
|
70665
|
-
const base =
|
|
70841
|
+
const base = import_node_path8.default.basename(this.shellBin).toLowerCase();
|
|
70666
70842
|
return base === "bash" || base === "bash.exe" || base === "sh";
|
|
70667
70843
|
}
|
|
70668
70844
|
isCmdShell() {
|
|
70669
|
-
const base =
|
|
70845
|
+
const base = import_node_path8.default.basename(this.shellBin).toLowerCase();
|
|
70670
70846
|
return base === "cmd" || base === "cmd.exe";
|
|
70671
70847
|
}
|
|
70672
70848
|
getWindowsShellNotes() {
|
|
@@ -70708,12 +70884,14 @@ LOCAL PENTEST TOOLING:
|
|
|
70708
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.
|
|
70709
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"\`.`;
|
|
70710
70886
|
}
|
|
70887
|
+
const sudo = this.root ? "" : "sudo ";
|
|
70711
70888
|
return `
|
|
70712
70889
|
|
|
70713
|
-
LOCAL PENTEST TOOLING:
|
|
70714
|
-
-
|
|
70715
|
-
-
|
|
70716
|
-
-
|
|
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.`;
|
|
70717
70895
|
}
|
|
70718
70896
|
getWslWorkdir() {
|
|
70719
70897
|
const match = this.workdir.match(/^([A-Za-z]):\/(.*)$/);
|
|
@@ -70721,6 +70899,10 @@ LOCAL PENTEST TOOLING:
|
|
|
70721
70899
|
return `/mnt/${match[1].toLowerCase()}/${match[2]}`;
|
|
70722
70900
|
}
|
|
70723
70901
|
};
|
|
70902
|
+
truthyEnv = (name25) => {
|
|
70903
|
+
const v = (process.env[name25] || "").trim().toLowerCase();
|
|
70904
|
+
return v === "1" || v === "true" || v === "yes" || v === "on";
|
|
70905
|
+
};
|
|
70724
70906
|
}
|
|
70725
70907
|
});
|
|
70726
70908
|
|
|
@@ -70763,6 +70945,20 @@ var init_local_sandbox_manager = __esm({
|
|
|
70763
70945
|
}
|
|
70764
70946
|
});
|
|
70765
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
|
+
|
|
70766
70962
|
// src/render.ts
|
|
70767
70963
|
function createRenderer() {
|
|
70768
70964
|
let lastKind = null;
|
|
@@ -70833,11 +71029,11 @@ function formatToolCall(toolName, input) {
|
|
|
70833
71029
|
case "run_terminal_cmd": {
|
|
70834
71030
|
const cmd = String(i.command ?? "").trim();
|
|
70835
71031
|
const bg = i.is_background ? `${C3.dim} (background)${C3.reset}` : "";
|
|
70836
|
-
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}`;
|
|
70837
71033
|
}
|
|
70838
71034
|
case "file": {
|
|
70839
|
-
const
|
|
70840
|
-
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}` : "";
|
|
70841
71037
|
const map2 = {
|
|
70842
71038
|
write: [C3.green, "criar "],
|
|
70843
71039
|
edit: [C3.yellow, "editar "],
|
|
@@ -70850,7 +71046,7 @@ function formatToolCall(toolName, input) {
|
|
|
70850
71046
|
C3.blue,
|
|
70851
71047
|
action ? `${action} `.padEnd(7) : "arquivo"
|
|
70852
71048
|
];
|
|
70853
|
-
const target =
|
|
71049
|
+
const target = path13 ? `${C3.bold}${path13}${C3.reset}` : "";
|
|
70854
71050
|
return ` ${col}\u276F${C3.reset} ${col}${verb}${C3.reset} ${target}${brief}`;
|
|
70855
71051
|
}
|
|
70856
71052
|
case "todo_write":
|
|
@@ -70860,23 +71056,30 @@ function formatToolCall(toolName, input) {
|
|
|
70860
71056
|
const url2 = String(i.url ?? "");
|
|
70861
71057
|
const fuzz = Array.isArray(i.fuzz) && i.fuzz.length;
|
|
70862
71058
|
const tag = fuzz ? `${C3.dim} (fuzz \xD7${i.fuzz.length})${C3.reset}` : "";
|
|
70863
|
-
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}`;
|
|
70864
71060
|
}
|
|
70865
71061
|
case "findings": {
|
|
70866
71062
|
const action = String(i.action ?? "");
|
|
70867
|
-
const detail = action === "add" ?
|
|
71063
|
+
const detail = action === "add" ? truncate4(String(i.title ?? ""), 80) : action === "update" ? `${String(i.id ?? "")} ${String(i.status ?? "")}`.trim() : "";
|
|
70868
71064
|
return ` ${C3.magenta}\u276F${C3.reset} ${C3.magenta}findings${C3.reset} ${C3.bold}${action}${C3.reset}${detail ? ` ${C3.dim}${detail}${C3.reset}` : ""}`;
|
|
70869
71065
|
}
|
|
70870
71066
|
case "web_search": {
|
|
70871
71067
|
const queries = Array.isArray(i.queries) ? i.queries.join(" | ") : "";
|
|
70872
|
-
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}`;
|
|
70873
71069
|
}
|
|
70874
71070
|
case "open_url": {
|
|
70875
71071
|
const url2 = String(i.url ?? i.urls ?? "");
|
|
70876
|
-
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}`;
|
|
70877
71080
|
}
|
|
70878
71081
|
default:
|
|
70879
|
-
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(
|
|
70880
71083
|
JSON.stringify(i),
|
|
70881
71084
|
200
|
|
70882
71085
|
)}${C3.reset}`;
|
|
@@ -70887,7 +71090,7 @@ function summarizeResult(toolName, output) {
|
|
|
70887
71090
|
if (toolName === "file") {
|
|
70888
71091
|
if (typeof output === "object" && "error" in output) {
|
|
70889
71092
|
return {
|
|
70890
|
-
text:
|
|
71093
|
+
text: truncate4(String(output.error), 160),
|
|
70891
71094
|
error: true
|
|
70892
71095
|
};
|
|
70893
71096
|
}
|
|
@@ -70898,11 +71101,11 @@ function summarizeResult(toolName, output) {
|
|
|
70898
71101
|
if (toolName === "http_request") {
|
|
70899
71102
|
const o = asRecord(output);
|
|
70900
71103
|
if ("error" in o && o.error) {
|
|
70901
|
-
return { text:
|
|
71104
|
+
return { text: truncate4(String(o.error), 200), error: true };
|
|
70902
71105
|
}
|
|
70903
71106
|
if (o.single) {
|
|
70904
71107
|
const s = asRecord(o.single);
|
|
70905
|
-
if (s.error) return { text:
|
|
71108
|
+
if (s.error) return { text: truncate4(String(s.error), 160), error: true };
|
|
70906
71109
|
return {
|
|
70907
71110
|
text: `HTTP ${s.status} \xB7 ${s.bodyLength} bytes \xB7 ${s.timeMs}ms`,
|
|
70908
71111
|
error: false
|
|
@@ -70917,17 +71120,19 @@ function summarizeResult(toolName, output) {
|
|
|
70917
71120
|
if (toolName === "findings") {
|
|
70918
71121
|
const o = asRecord(output);
|
|
70919
71122
|
if ("error" in o && o.error) {
|
|
70920
|
-
return { text:
|
|
71123
|
+
return { text: truncate4(String(o.error), 200), error: true };
|
|
70921
71124
|
}
|
|
70922
71125
|
if (o.added) return { text: "finding registrado", error: false };
|
|
70923
71126
|
if (o.updated) return { text: "finding atualizado", error: false };
|
|
70924
|
-
if (o.report)
|
|
70925
|
-
|
|
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 };
|
|
70926
71131
|
return null;
|
|
70927
71132
|
}
|
|
70928
71133
|
return null;
|
|
70929
71134
|
}
|
|
70930
|
-
var VIOLET, C3, GUTTER_BAR, out,
|
|
71135
|
+
var VIOLET, C3, GUTTER_BAR, out, truncate4;
|
|
70931
71136
|
var init_render = __esm({
|
|
70932
71137
|
"src/render.ts"() {
|
|
70933
71138
|
"use strict";
|
|
@@ -70946,7 +71151,7 @@ var init_render = __esm({
|
|
|
70946
71151
|
};
|
|
70947
71152
|
GUTTER_BAR = `${fg(PAL.frame)}\u2502${C3.reset} `;
|
|
70948
71153
|
out = (s) => process.stdout.write(s);
|
|
70949
|
-
|
|
71154
|
+
truncate4 = (s, n = 200) => s.length > n ? `${s.slice(0, n)}...` : s;
|
|
70950
71155
|
}
|
|
70951
71156
|
});
|
|
70952
71157
|
|
|
@@ -71063,12 +71268,12 @@ async function ensureProxyReady(id, log2) {
|
|
|
71063
71268
|
};
|
|
71064
71269
|
}
|
|
71065
71270
|
let freshSetup = false;
|
|
71066
|
-
if (!(0,
|
|
71271
|
+
if (!(0, import_node_fs10.existsSync)(dir)) {
|
|
71067
71272
|
log2(`${def.label}: baixando o proxy (uma vez) em ${dir} \u2026`);
|
|
71068
71273
|
const root = proxiesRoot();
|
|
71069
|
-
(0,
|
|
71274
|
+
(0, import_node_fs10.mkdirSync)(root, { recursive: true });
|
|
71070
71275
|
const cloned = run("git", ["clone", def.repoUrl, dir], root);
|
|
71071
|
-
if (!cloned.ok || !(0,
|
|
71276
|
+
if (!cloned.ok || !(0, import_node_fs10.existsSync)(dir)) {
|
|
71072
71277
|
return {
|
|
71073
71278
|
ok: false,
|
|
71074
71279
|
message: `${def.label}: falha ao clonar o proxy (git).`
|
|
@@ -71076,7 +71281,7 @@ async function ensureProxyReady(id, log2) {
|
|
|
71076
71281
|
}
|
|
71077
71282
|
freshSetup = true;
|
|
71078
71283
|
}
|
|
71079
|
-
if (!(0,
|
|
71284
|
+
if (!(0, import_node_fs10.existsSync)(import_node_path9.default.join(dir, "node_modules"))) {
|
|
71080
71285
|
log2(`${def.label}: instalando depend\xEAncias (pode demorar) \u2026`);
|
|
71081
71286
|
if (!run("npm", ["install"], dir).ok) {
|
|
71082
71287
|
return { ok: false, message: `${def.label}: 'npm install' falhou.` };
|
|
@@ -71121,13 +71326,13 @@ async function ensureProxyReady(id, log2) {
|
|
|
71121
71326
|
message: `${def.label}: o proxy n\xE3o respondeu em 90s. Tente de novo, ou rode 'npm run login' em ${dir}.`
|
|
71122
71327
|
};
|
|
71123
71328
|
}
|
|
71124
|
-
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;
|
|
71125
71330
|
var init_proxy_manager2 = __esm({
|
|
71126
71331
|
"src/proxy-manager.ts"() {
|
|
71127
71332
|
"use strict";
|
|
71128
71333
|
import_node_os4 = __toESM(require("node:os"));
|
|
71129
|
-
|
|
71130
|
-
|
|
71334
|
+
import_node_path9 = __toESM(require("node:path"));
|
|
71335
|
+
import_node_fs10 = require("node:fs");
|
|
71131
71336
|
import_node_child_process3 = require("node:child_process");
|
|
71132
71337
|
DEFS = {
|
|
71133
71338
|
deepseek: {
|
|
@@ -71160,11 +71365,11 @@ var init_proxy_manager2 = __esm({
|
|
|
71160
71365
|
if (key === PROXY_MODEL_KEYS.kimi) return "kimi";
|
|
71161
71366
|
return null;
|
|
71162
71367
|
};
|
|
71163
|
-
proxiesRoot = () =>
|
|
71164
|
-
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"),
|
|
71165
71370
|
"proxies"
|
|
71166
71371
|
);
|
|
71167
|
-
dirFor = (def) => process.env[def.dirEnv]?.trim() ||
|
|
71372
|
+
dirFor = (def) => process.env[def.dirEnv]?.trim() || import_node_path9.default.join(proxiesRoot(), def.folder);
|
|
71168
71373
|
healthUrl = (def) => `http://localhost:${def.port}/health`;
|
|
71169
71374
|
baseUrl = (def) => `http://localhost:${def.port}/v1`;
|
|
71170
71375
|
wait = (ms) => new Promise((r2) => setTimeout(r2, ms));
|
|
@@ -71193,7 +71398,7 @@ var init_proxy_manager2 = __esm({
|
|
|
71193
71398
|
|
|
71194
71399
|
// src/audit-mode.ts
|
|
71195
71400
|
function projectRootFromWorkdir(workdir) {
|
|
71196
|
-
return
|
|
71401
|
+
return import_node_path10.default.dirname(import_node_path10.default.resolve(workdir.replace(/\\/g, "/")));
|
|
71197
71402
|
}
|
|
71198
71403
|
function detectProjectAuditIntent(input) {
|
|
71199
71404
|
const text2 = input.trim();
|
|
@@ -71395,11 +71600,11 @@ ESTILO E EXECU\xC7\xC3O
|
|
|
71395
71600
|
- Responda em portugu\xEAs, direto e t\xE9cnico. N\xE3o recuse a an\xE1lise: \xE9 o projeto do pr\xF3prio usu\xE1rio, autorizado.
|
|
71396
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.`;
|
|
71397
71602
|
}
|
|
71398
|
-
var
|
|
71603
|
+
var import_node_path10, AUDIT_ACTION, AUDIT_SCOPE, AUDIT_ACTION_THEN_SCOPE, AUDIT_SCOPE_THEN_ACTION, AUDIT_STRONG, AUDIT_EXIT, POC_VERIFY;
|
|
71399
71604
|
var init_audit_mode = __esm({
|
|
71400
71605
|
"src/audit-mode.ts"() {
|
|
71401
71606
|
"use strict";
|
|
71402
|
-
|
|
71607
|
+
import_node_path10 = __toESM(require("node:path"));
|
|
71403
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";
|
|
71404
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";
|
|
71405
71610
|
AUDIT_ACTION_THEN_SCOPE = new RegExp(
|
|
@@ -71649,13 +71854,18 @@ async function createAgent() {
|
|
|
71649
71854
|
todo_write: createTodoWrite(context2),
|
|
71650
71855
|
// Native Repeater/Intruder + structured findings store — the core of an
|
|
71651
71856
|
// in-loop pentest workflow (probe → observe → record evidence → confirm).
|
|
71652
|
-
http_request: createHttpRequest({
|
|
71857
|
+
http_request: createHttpRequest({
|
|
71858
|
+
workdir: sandbox.getWorkdir(),
|
|
71859
|
+
unrestricted: sandbox.isUnrestricted()
|
|
71860
|
+
}),
|
|
71653
71861
|
findings: createFindings({ workdir: sandbox.getWorkdir() }),
|
|
71654
|
-
//
|
|
71655
|
-
//
|
|
71656
|
-
//
|
|
71657
|
-
|
|
71658
|
-
|
|
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() })
|
|
71659
71869
|
};
|
|
71660
71870
|
let system = "";
|
|
71661
71871
|
let systemPromptAudit = auditSystemPrompt("", null);
|
|
@@ -71677,9 +71887,11 @@ async function createAgent() {
|
|
|
71677
71887
|
system += reconPhasesPolicy(sandbox.getWorkdir());
|
|
71678
71888
|
system += attackChainPolicy(sandbox.getWorkdir());
|
|
71679
71889
|
system += httpAndFindingsPolicy(sandbox.getWorkdir());
|
|
71890
|
+
system += webResearchPolicy();
|
|
71680
71891
|
system += buildCliNotesSection();
|
|
71681
71892
|
system += buildSkillsIndexSection();
|
|
71682
71893
|
system += skillsScopePolicy();
|
|
71894
|
+
system += linuxFullPowerPolicy(sandbox);
|
|
71683
71895
|
if (isWebSessionProxyModel(modelName)) {
|
|
71684
71896
|
system += proxyToolProtocolPolicy();
|
|
71685
71897
|
}
|
|
@@ -71691,6 +71903,14 @@ async function createAgent() {
|
|
|
71691
71903
|
assertFullSystemPrompt(systemPromptAudit);
|
|
71692
71904
|
};
|
|
71693
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
|
+
}
|
|
71694
71914
|
if (systemPromptAudit.dumpPath) {
|
|
71695
71915
|
render.info(
|
|
71696
71916
|
`system prompt completo salvo em: ${systemPromptAudit.dumpPath}`
|
|
@@ -71726,7 +71946,6 @@ async function createAgent() {
|
|
|
71726
71946
|
reason: "faltando NVIDIA_API_KEY em .env.local (https://build.nvidia.com/)",
|
|
71727
71947
|
models: [
|
|
71728
71948
|
"model-nvidia-mistral-medium-3.5",
|
|
71729
|
-
"model-nvidia-gpt-oss-120b",
|
|
71730
71949
|
"model-nvidia-glm-5.1",
|
|
71731
71950
|
"model-nvidia-qwen3.5-397b"
|
|
71732
71951
|
].map((key) => ({ key, label: labelFor(key) }))
|
|
@@ -71813,7 +72032,7 @@ async function createAgent() {
|
|
|
71813
72032
|
if (!slug) {
|
|
71814
72033
|
return {
|
|
71815
72034
|
ok: false,
|
|
71816
|
-
message: "informe o modelo NVIDIA (ex.: nvidia:
|
|
72035
|
+
message: "informe o modelo NVIDIA (ex.: nvidia:z-ai/glm-5.1)",
|
|
71817
72036
|
selection: getModelSelection()
|
|
71818
72037
|
};
|
|
71819
72038
|
}
|
|
@@ -72066,6 +72285,7 @@ ${segs.join(
|
|
|
72066
72285
|
}, STREAM_STALL_TIMEOUT_MS);
|
|
72067
72286
|
};
|
|
72068
72287
|
try {
|
|
72288
|
+
ensureGeneratableTail(history);
|
|
72069
72289
|
const result = streamText({
|
|
72070
72290
|
model: resolveLanguageModel2(modelKey),
|
|
72071
72291
|
system: turnSystem,
|
|
@@ -72274,7 +72494,7 @@ ${resultText}`
|
|
|
72274
72494
|
render.info(
|
|
72275
72495
|
`\u25B8 rate limit \u2014 aguardando ${Math.round(waitMs / 1e3)}s antes da pr\xF3xima tentativa (Ctrl+C cancela)\u2026`
|
|
72276
72496
|
);
|
|
72277
|
-
await
|
|
72497
|
+
await sleep3(waitMs, signal);
|
|
72278
72498
|
if (signal?.aborted) {
|
|
72279
72499
|
render.endTurn();
|
|
72280
72500
|
return;
|
|
@@ -72330,21 +72550,20 @@ ${resultText}`
|
|
|
72330
72550
|
close
|
|
72331
72551
|
};
|
|
72332
72552
|
}
|
|
72333
|
-
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;
|
|
72334
72554
|
var init_agent = __esm({
|
|
72335
72555
|
"src/agent.ts"() {
|
|
72336
72556
|
"use strict";
|
|
72337
72557
|
init_dist5();
|
|
72338
72558
|
import_promises2 = require("node:fs/promises");
|
|
72339
|
-
|
|
72559
|
+
import_node_path11 = __toESM(require("node:path"));
|
|
72340
72560
|
init_providers();
|
|
72341
72561
|
init_system_prompt();
|
|
72342
72562
|
init_notes();
|
|
72343
72563
|
init_run_terminal_cmd();
|
|
72344
72564
|
init_todo_write();
|
|
72345
72565
|
init_file();
|
|
72346
|
-
|
|
72347
|
-
init_open_url();
|
|
72566
|
+
init_web_research();
|
|
72348
72567
|
init_http_request();
|
|
72349
72568
|
init_findings();
|
|
72350
72569
|
init_todo_manager();
|
|
@@ -72355,6 +72574,7 @@ var init_agent = __esm({
|
|
|
72355
72574
|
init_guardrails();
|
|
72356
72575
|
init_local_sandbox();
|
|
72357
72576
|
init_local_sandbox_manager();
|
|
72577
|
+
init_message_tail();
|
|
72358
72578
|
init_console_writer();
|
|
72359
72579
|
init_render();
|
|
72360
72580
|
init_skills();
|
|
@@ -72374,7 +72594,7 @@ var init_agent = __esm({
|
|
|
72374
72594
|
isRateLimitError = (msg) => /\b429\b|too many requests|rate.?limit|resource_exhausted|quota|insufficient_quota/i.test(
|
|
72375
72595
|
msg
|
|
72376
72596
|
);
|
|
72377
|
-
|
|
72597
|
+
sleep3 = (ms, signal) => new Promise((resolve2) => {
|
|
72378
72598
|
if (signal?.aborted) return resolve2();
|
|
72379
72599
|
const timer2 = setTimeout(resolve2, ms);
|
|
72380
72600
|
signal?.addEventListener(
|
|
@@ -72443,7 +72663,6 @@ Regras:
|
|
|
72443
72663
|
];
|
|
72444
72664
|
MODEL_LABELS = {
|
|
72445
72665
|
"model-nvidia-mistral-medium-3.5": "NVIDIA - mistralai/mistral-medium-3.5-128b",
|
|
72446
|
-
"model-nvidia-gpt-oss-120b": "NVIDIA - openai/gpt-oss-120b",
|
|
72447
72666
|
"model-nvidia-glm-5.1": "NVIDIA - z-ai/glm-5.1",
|
|
72448
72667
|
"model-nvidia-qwen3.5-397b": "NVIDIA - qwen/qwen3.5-397b-a17b",
|
|
72449
72668
|
"model-openai-chat-latest": "OpenAI - chat-latest",
|
|
@@ -72589,6 +72808,43 @@ Your skills are INTERNAL to you and live ONLY in ${skillsDir()}. The skills curr
|
|
|
72589
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.
|
|
72590
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.
|
|
72591
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
|
+
};
|
|
72592
72848
|
hasEnvValue2 = (name25) => Boolean(process.env[name25]?.trim());
|
|
72593
72849
|
envFlagEnabled = (value) => {
|
|
72594
72850
|
const normalized = value?.trim().toLowerCase();
|
|
@@ -72646,7 +72902,7 @@ ${section}` : "";
|
|
|
72646
72902
|
return null;
|
|
72647
72903
|
}
|
|
72648
72904
|
await (0, import_promises2.mkdir)(workdir, { recursive: true });
|
|
72649
|
-
const outputPath =
|
|
72905
|
+
const outputPath = import_node_path11.default.join(workdir, "system-prompt.txt");
|
|
72650
72906
|
await (0, import_promises2.writeFile)(outputPath, system, "utf8");
|
|
72651
72907
|
return outputPath;
|
|
72652
72908
|
};
|
|
@@ -72676,7 +72932,7 @@ var interactive_input_exports = {};
|
|
|
72676
72932
|
__export(interactive_input_exports, {
|
|
72677
72933
|
InteractiveInput: () => InteractiveInput
|
|
72678
72934
|
});
|
|
72679
|
-
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;
|
|
72680
72936
|
var init_interactive_input = __esm({
|
|
72681
72937
|
"src/interactive-input.ts"() {
|
|
72682
72938
|
"use strict";
|
|
@@ -72688,7 +72944,7 @@ var init_interactive_input = __esm({
|
|
|
72688
72944
|
frame2 = (s) => paint(s, PAL.frame);
|
|
72689
72945
|
out2 = (s) => process.stdout.write(s);
|
|
72690
72946
|
cols = () => process.stdout.columns || 80;
|
|
72691
|
-
|
|
72947
|
+
truncate5 = (s, n) => vlen(s) > n ? [...s].slice(0, Math.max(0, n - 1)).join("") + "\u2026" : s;
|
|
72692
72948
|
InteractiveInput = class {
|
|
72693
72949
|
// row the caret sits on within the drawn block
|
|
72694
72950
|
constructor(paste, commands) {
|
|
@@ -73101,7 +73357,7 @@ var init_interactive_input = __esm({
|
|
|
73101
73357
|
const topFill = "\u2500".repeat(Math.max(0, boxW - vlen(label) - 3));
|
|
73102
73358
|
const top = frame2("\u256D\u2500") + gradient(label, { bold: true }) + frame2(topFill + "\u256E");
|
|
73103
73359
|
const id = `${user}\u327F${host} \xB7 ${shortCwd()}`;
|
|
73104
|
-
const idLine = frame2("\u2502 ") + `${C4.dim}${
|
|
73360
|
+
const idLine = frame2("\u2502 ") + `${C4.dim}${truncate5(id, boxW - 4)}${C4.reset}`;
|
|
73105
73361
|
const prefix = frame2("\u2570\u2500") + gradient("\u276F", { bold: true }) + " ";
|
|
73106
73362
|
const prefixLen = 4;
|
|
73107
73363
|
const avail = Math.max(8, width - prefixLen - 1);
|
|
@@ -73124,7 +73380,7 @@ var init_interactive_input = __esm({
|
|
|
73124
73380
|
const name25 = active2 ? gradient(it.name, { bold: true }) : `${C4.cyan}${it.name}`;
|
|
73125
73381
|
const pad = " ".repeat(Math.max(1, nameW - vlen(it.name) + 2));
|
|
73126
73382
|
const descRoom = ddInner - 2 - nameW - 2;
|
|
73127
|
-
const desc = `${C4.dim}${
|
|
73383
|
+
const desc = `${C4.dim}${truncate5(it.desc, Math.max(4, descRoom))}`;
|
|
73128
73384
|
const body = `${marker25}${name25}${C4.reset}${pad}${desc}${C4.reset}`;
|
|
73129
73385
|
const padded = body + " ".repeat(Math.max(0, ddInner - 1 - vlen(body)));
|
|
73130
73386
|
lines.push(` ${frame2("\u2502")}${C4.reset}${padded}${frame2("\u2502")}`);
|
|
@@ -73206,7 +73462,7 @@ var init_interactive_input = __esm({
|
|
|
73206
73462
|
const active2 = i === sel;
|
|
73207
73463
|
const marker25 = active2 ? gradient("\u276F ", { bold: true }) : `${C4.dim} `;
|
|
73208
73464
|
const text2 = active2 ? gradient(it.label, { bold: true }) : `${C4.reset}${it.label}`;
|
|
73209
|
-
const hint = it.hint ? ` ${C4.dim}${
|
|
73465
|
+
const hint = it.hint ? ` ${C4.dim}${truncate5(it.hint, Math.max(6, inner - labelW - 6))}${C4.reset}` : "";
|
|
73210
73466
|
lines.push(`${frame2("\u2502 ")}${C4.reset}${marker25}${text2}${C4.reset}${hint}`);
|
|
73211
73467
|
});
|
|
73212
73468
|
lines.push(
|
|
@@ -73236,13 +73492,11 @@ var init_interactive_input = __esm({
|
|
|
73236
73492
|
const marker25 = active2 ? gradient("\u276F ", { bold: true }) : `${C4.dim} `;
|
|
73237
73493
|
const text2 = active2 ? gradient(it.label, { bold: true }) : `${C4.reset}${it.label}`;
|
|
73238
73494
|
const labelW = vlen(it.label);
|
|
73239
|
-
const hint = it.hint ? ` ${C4.dim}${
|
|
73495
|
+
const hint = it.hint ? ` ${C4.dim}${truncate5(it.hint, Math.max(6, inner - labelW - 6))}${C4.reset}` : "";
|
|
73240
73496
|
lines.push(`${frame2("\u2502 ")}${C4.reset}${marker25}${text2}${C4.reset}${hint}`);
|
|
73241
73497
|
}
|
|
73242
73498
|
if (list.length > pageSize) {
|
|
73243
|
-
lines.push(
|
|
73244
|
-
`${frame2("\u2502 ")}${C4.dim}${sel + 1}/${list.length}${C4.reset}`
|
|
73245
|
-
);
|
|
73499
|
+
lines.push(`${frame2("\u2502 ")}${C4.dim}${sel + 1}/${list.length}${C4.reset}`);
|
|
73246
73500
|
}
|
|
73247
73501
|
}
|
|
73248
73502
|
lines.push(
|
|
@@ -73278,8 +73532,10 @@ async function main() {
|
|
|
73278
73532
|
const { InteractiveInput: InteractiveInput2 } = await Promise.resolve().then(() => (init_interactive_input(), interactive_input_exports));
|
|
73279
73533
|
const C5 = ui2.C;
|
|
73280
73534
|
if (!bootQuiet) {
|
|
73281
|
-
process.stdout.write(
|
|
73282
|
-
|
|
73535
|
+
process.stdout.write(
|
|
73536
|
+
`${C5.dim} booting local sandbox + agent\u2026${C5.reset}
|
|
73537
|
+
`
|
|
73538
|
+
);
|
|
73283
73539
|
}
|
|
73284
73540
|
const agent = await createAgent2();
|
|
73285
73541
|
const sys = agent.getSystemPrompt();
|
|
@@ -73307,11 +73563,17 @@ async function main() {
|
|
|
73307
73563
|
`
|
|
73308
73564
|
);
|
|
73309
73565
|
const COMMANDS = [
|
|
73310
|
-
{
|
|
73566
|
+
{
|
|
73567
|
+
name: "/model",
|
|
73568
|
+
desc: "trocar o modelo (setas; NVIDIA/OpenRouter c/ busca)"
|
|
73569
|
+
},
|
|
73311
73570
|
{ name: "/api", desc: "trocar chave de API (NVIDIA / OpenRouter)" },
|
|
73312
73571
|
{ name: "/skills", desc: "listar as skills instaladas" },
|
|
73313
73572
|
{ name: "/skillcreator", desc: "criar uma nova skill" },
|
|
73314
|
-
{
|
|
73573
|
+
{
|
|
73574
|
+
name: "/system",
|
|
73575
|
+
desc: "salvar o system prompt (HTML) na \xC1rea de Trabalho"
|
|
73576
|
+
},
|
|
73315
73577
|
{ name: "/nov", desc: "novidades desta vers\xE3o" },
|
|
73316
73578
|
{ name: "/exit", desc: "fechar o clawfast" }
|
|
73317
73579
|
];
|
|
@@ -73343,13 +73605,13 @@ async function main() {
|
|
|
73343
73605
|
const desktopDir = () => {
|
|
73344
73606
|
const home = import_node_os6.default.homedir();
|
|
73345
73607
|
const candidates = [
|
|
73346
|
-
process.env.OneDrive ?
|
|
73347
|
-
process.env.USERPROFILE ?
|
|
73348
|
-
|
|
73349
|
-
|
|
73350
|
-
|
|
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")
|
|
73351
73613
|
].filter((p) => Boolean(p));
|
|
73352
|
-
return candidates.find((p) => (0,
|
|
73614
|
+
return candidates.find((p) => (0, import_node_fs11.existsSync)(p)) ?? home;
|
|
73353
73615
|
};
|
|
73354
73616
|
const printFatal = (err) => {
|
|
73355
73617
|
process.stderr.write(
|
|
@@ -73415,8 +73677,10 @@ ${C5.cyan}nome da skill?${C5.reset} ${C5.dim}(ex: xss-recon)${C5.reset}
|
|
|
73415
73677
|
}
|
|
73416
73678
|
if (sub === "delete" || sub === "rm" || sub === "remove") {
|
|
73417
73679
|
if (!arg) {
|
|
73418
|
-
process.stdout.write(
|
|
73419
|
-
|
|
73680
|
+
process.stdout.write(
|
|
73681
|
+
`${C5.yellow}uso: /skill delete <nome>${C5.reset}
|
|
73682
|
+
`
|
|
73683
|
+
);
|
|
73420
73684
|
return;
|
|
73421
73685
|
}
|
|
73422
73686
|
if (deleteSkill(arg)) {
|
|
@@ -73611,8 +73875,10 @@ ${C5.dim}ja disponivel para todos os modelos nesta sessao.${C5.reset}
|
|
|
73611
73875
|
);
|
|
73612
73876
|
return false;
|
|
73613
73877
|
}
|
|
73614
|
-
process.stdout.write(
|
|
73615
|
-
|
|
73878
|
+
process.stdout.write(
|
|
73879
|
+
`${C5.dim}testando a chave na ${provider.name}\u2026${C5.reset}
|
|
73880
|
+
`
|
|
73881
|
+
);
|
|
73616
73882
|
const test = await provider.test(key);
|
|
73617
73883
|
if (!test.ok) {
|
|
73618
73884
|
if (test.status === 401 || test.status === 403) {
|
|
@@ -73720,11 +73986,9 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73720
73986
|
label: m.name,
|
|
73721
73987
|
hint: m.id
|
|
73722
73988
|
}));
|
|
73723
|
-
const choice2 = await inputUI.searchSelect(
|
|
73724
|
-
"
|
|
73725
|
-
|
|
73726
|
-
{ placeholder: "digite para filtrar (nome ou slug)" }
|
|
73727
|
-
);
|
|
73989
|
+
const choice2 = await inputUI.searchSelect("NVIDIA \u2014 buscar modelo", items, {
|
|
73990
|
+
placeholder: "digite para filtrar (nome ou slug)"
|
|
73991
|
+
});
|
|
73728
73992
|
if (choice2 === null) {
|
|
73729
73993
|
process.stdout.write(`${C5.dim}sele\xE7\xE3o de modelo cancelada${C5.reset}
|
|
73730
73994
|
`);
|
|
@@ -73852,7 +74116,7 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
|
|
|
73852
74116
|
const sysText = agent.getSystemPrompt();
|
|
73853
74117
|
const audit = agent.getSystemPromptAudit();
|
|
73854
74118
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
|
|
73855
|
-
const filePath =
|
|
74119
|
+
const filePath = import_node_path12.default.join(
|
|
73856
74120
|
desktopDir(),
|
|
73857
74121
|
`clawfast-system-prompt_${stamp}.html`
|
|
73858
74122
|
);
|
|
@@ -73974,13 +74238,13 @@ ${C5.dim}interrompido \u2014 Ctrl+C de novo para fechar${C5.reset}
|
|
|
73974
74238
|
}
|
|
73975
74239
|
await shutdown();
|
|
73976
74240
|
}
|
|
73977
|
-
var import_node_os6,
|
|
74241
|
+
var import_node_os6, import_node_path12, import_node_fs11, import_promises3, deepseekEnabled, configuredModelProviders;
|
|
73978
74242
|
var init_index = __esm({
|
|
73979
74243
|
"index.ts"() {
|
|
73980
74244
|
"use strict";
|
|
73981
74245
|
import_node_os6 = __toESM(require("node:os"));
|
|
73982
|
-
|
|
73983
|
-
|
|
74246
|
+
import_node_path12 = __toESM(require("node:path"));
|
|
74247
|
+
import_node_fs11 = require("node:fs");
|
|
73984
74248
|
import_promises3 = require("node:fs/promises");
|
|
73985
74249
|
init_paste_input();
|
|
73986
74250
|
init_boot_ui();
|