clawfast 2.4.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/clawfast.cjs +825 -199
  2. package/package.json +1 -1
package/dist/clawfast.cjs CHANGED
@@ -199,10 +199,10 @@ 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 fs9 = require("fs");
203
- var path13 = require("path");
204
- var os7 = require("os");
205
- var crypto2 = require("crypto");
202
+ var fs10 = require("fs");
203
+ var path14 = require("path");
204
+ var os8 = require("os");
205
+ var crypto3 = require("crypto");
206
206
  var TIPS = [
207
207
  "\u25C8 encrypted .env [www.dotenvx.com]",
208
208
  "\u25C8 secrets for agents [www.dotenvx.com]",
@@ -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 (fs9.existsSync(filepath)) {
334
+ if (fs10.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 = path13.resolve(process.cwd(), ".env.vault");
342
+ possibleVaultPath = path14.resolve(process.cwd(), ".env.vault");
343
343
  }
344
- if (fs9.existsSync(possibleVaultPath)) {
344
+ if (fs10.existsSync(possibleVaultPath)) {
345
345
  return possibleVaultPath;
346
346
  }
347
347
  return null;
348
348
  }
349
349
  function _resolveHome(envPath) {
350
- return envPath[0] === "~" ? path13.join(os7.homedir(), envPath.slice(1)) : envPath;
350
+ return envPath[0] === "~" ? path14.join(os8.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 = path13.resolve(process.cwd(), ".env");
367
+ const dotenvPath = path14.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 path14 of optionPaths) {
395
+ for (const path15 of optionPaths) {
396
396
  try {
397
- const parsed = DotenvModule.parse(fs9.readFileSync(path14, { encoding }));
397
+ const parsed = DotenvModule.parse(fs10.readFileSync(path15, { encoding }));
398
398
  DotenvModule.populate(parsedAll, parsed, options);
399
399
  } catch (e) {
400
400
  if (debug) {
401
- _debug(`failed to load ${path14} ${e.message}`);
401
+ _debug(`failed to load ${path15} ${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 = path13.relative(process.cwd(), filePath);
414
+ const relative2 = path14.relative(process.cwd(), filePath);
415
415
  shortPaths.push(relative2);
416
416
  } catch (e) {
417
417
  if (debug) {
@@ -446,7 +446,7 @@ var require_main = __commonJS({
446
446
  const authTag = ciphertext.subarray(-16);
447
447
  ciphertext = ciphertext.subarray(12, -16);
448
448
  try {
449
- const aesgcm = crypto2.createDecipheriv("aes-256-gcm", key, nonce);
449
+ const aesgcm = crypto3.createDecipheriv("aes-256-gcm", key, nonce);
450
450
  aesgcm.setAuthTag(authTag);
451
451
  return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
452
452
  } catch (error51) {
@@ -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.4.0" : devVersionFromPackageJson();
692
+ clawfastVersion = () => true ? "2.4.1" : 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);
@@ -1949,10 +1949,10 @@ function mergeDefs(...defs) {
1949
1949
  function cloneDef(schema) {
1950
1950
  return mergeDefs(schema._zod.def);
1951
1951
  }
1952
- function getElementAtPath(obj, path13) {
1953
- if (!path13)
1952
+ function getElementAtPath(obj, path14) {
1953
+ if (!path14)
1954
1954
  return obj;
1955
- return path13.reduce((acc, key) => acc?.[key], obj);
1955
+ return path14.reduce((acc, key) => acc?.[key], obj);
1956
1956
  }
1957
1957
  function promiseAllObject(promisesObj) {
1958
1958
  const keys = Object.keys(promisesObj);
@@ -2280,11 +2280,11 @@ function explicitlyAborted(x, startIndex = 0) {
2280
2280
  }
2281
2281
  return false;
2282
2282
  }
2283
- function prefixIssues(path13, issues) {
2283
+ function prefixIssues(path14, issues) {
2284
2284
  return issues.map((iss) => {
2285
2285
  var _a25;
2286
2286
  (_a25 = iss).path ?? (_a25.path = []);
2287
- iss.path.unshift(path13);
2287
+ iss.path.unshift(path14);
2288
2288
  return iss;
2289
2289
  });
2290
2290
  }
@@ -2502,16 +2502,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
2502
2502
  }
2503
2503
  function formatError(error51, mapper = (issue2) => issue2.message) {
2504
2504
  const fieldErrors = { _errors: [] };
2505
- const processError = (error52, path13 = []) => {
2505
+ const processError = (error52, path14 = []) => {
2506
2506
  for (const issue2 of error52.issues) {
2507
2507
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2508
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
2508
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
2509
2509
  } else if (issue2.code === "invalid_key") {
2510
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
2510
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
2511
2511
  } else if (issue2.code === "invalid_element") {
2512
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
2512
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
2513
2513
  } else {
2514
- const fullpath = [...path13, ...issue2.path];
2514
+ const fullpath = [...path14, ...issue2.path];
2515
2515
  if (fullpath.length === 0) {
2516
2516
  fieldErrors._errors.push(mapper(issue2));
2517
2517
  } else {
@@ -2538,17 +2538,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
2538
2538
  }
2539
2539
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
2540
2540
  const result = { errors: [] };
2541
- const processError = (error52, path13 = []) => {
2541
+ const processError = (error52, path14 = []) => {
2542
2542
  var _a25, _b18;
2543
2543
  for (const issue2 of error52.issues) {
2544
2544
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2545
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
2545
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
2546
2546
  } else if (issue2.code === "invalid_key") {
2547
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
2547
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
2548
2548
  } else if (issue2.code === "invalid_element") {
2549
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
2549
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
2550
2550
  } else {
2551
- const fullpath = [...path13, ...issue2.path];
2551
+ const fullpath = [...path14, ...issue2.path];
2552
2552
  if (fullpath.length === 0) {
2553
2553
  result.errors.push(mapper(issue2));
2554
2554
  continue;
@@ -2580,8 +2580,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
2580
2580
  }
2581
2581
  function toDotPath(_path) {
2582
2582
  const segs = [];
2583
- const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2584
- for (const seg of path13) {
2583
+ const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2584
+ for (const seg of path14) {
2585
2585
  if (typeof seg === "number")
2586
2586
  segs.push(`[${seg}]`);
2587
2587
  else if (typeof seg === "symbol")
@@ -16084,13 +16084,13 @@ function resolveRef(ref, ctx) {
16084
16084
  if (!ref.startsWith("#")) {
16085
16085
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
16086
16086
  }
16087
- const path13 = ref.slice(1).split("/").filter(Boolean);
16088
- if (path13.length === 0) {
16087
+ const path14 = ref.slice(1).split("/").filter(Boolean);
16088
+ if (path14.length === 0) {
16089
16089
  return ctx.rootSchema;
16090
16090
  }
16091
16091
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
16092
- if (path13[0] === defsKey) {
16093
- const key = path13[1];
16092
+ if (path14[0] === defsKey) {
16093
+ const key = path14[1];
16094
16094
  if (!key || !ctx.defs[key]) {
16095
16095
  throw new Error(`Reference not found: ${ref}`);
16096
16096
  }
@@ -17279,8 +17279,8 @@ var init_parseUtil = __esm({
17279
17279
  init_errors3();
17280
17280
  init_en2();
17281
17281
  makeIssue = (params) => {
17282
- const { data, path: path13, errorMaps, issueData } = params;
17283
- const fullPath = [...path13, ...issueData.path || []];
17282
+ const { data, path: path14, errorMaps, issueData } = params;
17283
+ const fullPath = [...path14, ...issueData.path || []];
17284
17284
  const fullIssue = {
17285
17285
  ...issueData,
17286
17286
  path: fullPath
@@ -17563,11 +17563,11 @@ var init_types = __esm({
17563
17563
  init_parseUtil();
17564
17564
  init_util2();
17565
17565
  ParseInputLazyPath = class {
17566
- constructor(parent, value, path13, key) {
17566
+ constructor(parent, value, path14, key) {
17567
17567
  this._cachedPath = [];
17568
17568
  this.parent = parent;
17569
17569
  this.data = value;
17570
- this._path = path13;
17570
+ this._path = path14;
17571
17571
  this._key = key;
17572
17572
  }
17573
17573
  get path() {
@@ -23606,8 +23606,8 @@ var require_auth_config = __commonJS({
23606
23606
  writeAuthConfig: () => writeAuthConfig
23607
23607
  });
23608
23608
  module2.exports = __toCommonJS(auth_config_exports);
23609
- var fs9 = __toESM2(require("fs"));
23610
- var path13 = __toESM2(require("path"));
23609
+ var fs10 = __toESM2(require("fs"));
23610
+ var path14 = __toESM2(require("path"));
23611
23611
  var import_token_util = require_token_util();
23612
23612
  function getAuthConfigPath() {
23613
23613
  const dataDir = (0, import_token_util.getVercelDataDir)();
@@ -23616,15 +23616,15 @@ var require_auth_config = __commonJS({
23616
23616
  `Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`
23617
23617
  );
23618
23618
  }
23619
- return path13.join(dataDir, "auth.json");
23619
+ return path14.join(dataDir, "auth.json");
23620
23620
  }
23621
23621
  function readAuthConfig() {
23622
23622
  try {
23623
23623
  const authPath = getAuthConfigPath();
23624
- if (!fs9.existsSync(authPath)) {
23624
+ if (!fs10.existsSync(authPath)) {
23625
23625
  return null;
23626
23626
  }
23627
- const content = fs9.readFileSync(authPath, "utf8");
23627
+ const content = fs10.readFileSync(authPath, "utf8");
23628
23628
  if (!content) {
23629
23629
  return null;
23630
23630
  }
@@ -23635,11 +23635,11 @@ var require_auth_config = __commonJS({
23635
23635
  }
23636
23636
  function writeAuthConfig(config3) {
23637
23637
  const authPath = getAuthConfigPath();
23638
- const authDir = path13.dirname(authPath);
23639
- if (!fs9.existsSync(authDir)) {
23640
- fs9.mkdirSync(authDir, { mode: 504, recursive: true });
23638
+ const authDir = path14.dirname(authPath);
23639
+ if (!fs10.existsSync(authDir)) {
23640
+ fs10.mkdirSync(authDir, { mode: 504, recursive: true });
23641
23641
  }
23642
- fs9.writeFileSync(authPath, JSON.stringify(config3, null, 2), { mode: 384 });
23642
+ fs10.writeFileSync(authPath, JSON.stringify(config3, null, 2), { mode: 384 });
23643
23643
  }
23644
23644
  function isValidAccessToken(authConfig, expirationBufferMs = 0) {
23645
23645
  if (!authConfig.token)
@@ -23830,8 +23830,8 @@ var require_token_util = __commonJS({
23830
23830
  saveToken: () => saveToken
23831
23831
  });
23832
23832
  module2.exports = __toCommonJS(token_util_exports);
23833
- var path13 = __toESM2(require("path"));
23834
- var fs9 = __toESM2(require("fs"));
23833
+ var path14 = __toESM2(require("path"));
23834
+ var fs10 = __toESM2(require("fs"));
23835
23835
  var import_token_error = require_token_error();
23836
23836
  var import_token_io = require_token_io();
23837
23837
  var import_auth_config = require_auth_config();
@@ -23843,7 +23843,7 @@ var require_token_util = __commonJS({
23843
23843
  if (!dataDir) {
23844
23844
  return null;
23845
23845
  }
23846
- return path13.join(dataDir, vercelFolder);
23846
+ return path14.join(dataDir, vercelFolder);
23847
23847
  }
23848
23848
  async function getVercelToken2(options) {
23849
23849
  const authConfig = (0, import_auth_config.readAuthConfig)();
@@ -23919,13 +23919,13 @@ var require_token_util = __commonJS({
23919
23919
  "Unable to find project root directory. Have you linked your project with `vc link?`"
23920
23920
  );
23921
23921
  }
23922
- const prjPath = path13.join(dir, ".vercel", "project.json");
23923
- if (!fs9.existsSync(prjPath)) {
23922
+ const prjPath = path14.join(dir, ".vercel", "project.json");
23923
+ if (!fs10.existsSync(prjPath)) {
23924
23924
  throw new import_token_error.VercelOidcTokenError(
23925
23925
  "project.json not found, have you linked your project with `vc link?`"
23926
23926
  );
23927
23927
  }
23928
- const prj = JSON.parse(fs9.readFileSync(prjPath, "utf8"));
23928
+ const prj = JSON.parse(fs10.readFileSync(prjPath, "utf8"));
23929
23929
  if (typeof prj.projectId !== "string" && typeof prj.orgId !== "string") {
23930
23930
  throw new TypeError(
23931
23931
  "Expected a string-valued projectId property. Try running `vc link` to re-link your project."
@@ -23940,11 +23940,11 @@ var require_token_util = __commonJS({
23940
23940
  "Unable to find user data directory. Please reach out to Vercel support."
23941
23941
  );
23942
23942
  }
23943
- const tokenPath = path13.join(dir, "com.vercel.token", `${projectId}.json`);
23943
+ const tokenPath = path14.join(dir, "com.vercel.token", `${projectId}.json`);
23944
23944
  const tokenJson = JSON.stringify(token);
23945
- fs9.mkdirSync(path13.dirname(tokenPath), { mode: 504, recursive: true });
23946
- fs9.writeFileSync(tokenPath, tokenJson);
23947
- fs9.chmodSync(tokenPath, 432);
23945
+ fs10.mkdirSync(path14.dirname(tokenPath), { mode: 504, recursive: true });
23946
+ fs10.writeFileSync(tokenPath, tokenJson);
23947
+ fs10.chmodSync(tokenPath, 432);
23948
23948
  return;
23949
23949
  }
23950
23950
  function loadToken(projectId) {
@@ -23954,11 +23954,11 @@ var require_token_util = __commonJS({
23954
23954
  "Unable to find user data directory. Please reach out to Vercel support."
23955
23955
  );
23956
23956
  }
23957
- const tokenPath = path13.join(dir, "com.vercel.token", `${projectId}.json`);
23958
- if (!fs9.existsSync(tokenPath)) {
23957
+ const tokenPath = path14.join(dir, "com.vercel.token", `${projectId}.json`);
23958
+ if (!fs10.existsSync(tokenPath)) {
23959
23959
  return null;
23960
23960
  }
23961
- const token = JSON.parse(fs9.readFileSync(tokenPath, "utf8"));
23961
+ const token = JSON.parse(fs10.readFileSync(tokenPath, "utf8"));
23962
23962
  assertVercelOidcTokenResponse(token);
23963
23963
  return token;
23964
23964
  }
@@ -35984,7 +35984,7 @@ function createOpenRouter(options = {}) {
35984
35984
  );
35985
35985
  const createChatModel = (modelId, settings = {}) => new OpenRouterChatLanguageModel(modelId, settings, {
35986
35986
  provider: "openrouter.chat",
35987
- url: ({ path: path13 }) => `${baseURL}${path13}`,
35987
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
35988
35988
  headers: getHeaders,
35989
35989
  compatibility,
35990
35990
  fetch: options.fetch,
@@ -35992,7 +35992,7 @@ function createOpenRouter(options = {}) {
35992
35992
  });
35993
35993
  const createCompletionModel = (modelId, settings = {}) => new OpenRouterCompletionLanguageModel(modelId, settings, {
35994
35994
  provider: "openrouter.completion",
35995
- url: ({ path: path13 }) => `${baseURL}${path13}`,
35995
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
35996
35996
  headers: getHeaders,
35997
35997
  compatibility,
35998
35998
  fetch: options.fetch,
@@ -36000,21 +36000,21 @@ function createOpenRouter(options = {}) {
36000
36000
  });
36001
36001
  const createEmbeddingModel = (modelId, settings = {}) => new OpenRouterEmbeddingModel(modelId, settings, {
36002
36002
  provider: "openrouter.embedding",
36003
- url: ({ path: path13 }) => `${baseURL}${path13}`,
36003
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
36004
36004
  headers: getHeaders,
36005
36005
  fetch: options.fetch,
36006
36006
  extraBody: options.extraBody
36007
36007
  });
36008
36008
  const createImageModel = (modelId, settings = {}) => new OpenRouterImageModel(modelId, settings, {
36009
36009
  provider: "openrouter.image",
36010
- url: ({ path: path13 }) => `${baseURL}${path13}`,
36010
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
36011
36011
  headers: getHeaders,
36012
36012
  fetch: options.fetch,
36013
36013
  extraBody: options.extraBody
36014
36014
  });
36015
36015
  const createVideoModel = (modelId, settings = {}) => new OpenRouterVideoModel(modelId, settings, {
36016
36016
  provider: "openrouter.video",
36017
- url: ({ path: path13 }) => `${baseURL}${path13}`,
36017
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
36018
36018
  headers: getHeaders,
36019
36019
  fetch: options.fetch,
36020
36020
  extraBody: options.extraBody
@@ -40550,37 +40550,37 @@ function createOpenAI(options = {}) {
40550
40550
  );
40551
40551
  const createChatModel = (modelId) => new OpenAIChatLanguageModel(modelId, {
40552
40552
  provider: `${providerName}.chat`,
40553
- url: ({ path: path13 }) => `${baseURL}${path13}`,
40553
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
40554
40554
  headers: getHeaders,
40555
40555
  fetch: options.fetch
40556
40556
  });
40557
40557
  const createCompletionModel = (modelId) => new OpenAICompletionLanguageModel(modelId, {
40558
40558
  provider: `${providerName}.completion`,
40559
- url: ({ path: path13 }) => `${baseURL}${path13}`,
40559
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
40560
40560
  headers: getHeaders,
40561
40561
  fetch: options.fetch
40562
40562
  });
40563
40563
  const createEmbeddingModel = (modelId) => new OpenAIEmbeddingModel(modelId, {
40564
40564
  provider: `${providerName}.embedding`,
40565
- url: ({ path: path13 }) => `${baseURL}${path13}`,
40565
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
40566
40566
  headers: getHeaders,
40567
40567
  fetch: options.fetch
40568
40568
  });
40569
40569
  const createImageModel = (modelId) => new OpenAIImageModel(modelId, {
40570
40570
  provider: `${providerName}.image`,
40571
- url: ({ path: path13 }) => `${baseURL}${path13}`,
40571
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
40572
40572
  headers: getHeaders,
40573
40573
  fetch: options.fetch
40574
40574
  });
40575
40575
  const createTranscriptionModel = (modelId) => new OpenAITranscriptionModel(modelId, {
40576
40576
  provider: `${providerName}.transcription`,
40577
- url: ({ path: path13 }) => `${baseURL}${path13}`,
40577
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
40578
40578
  headers: getHeaders,
40579
40579
  fetch: options.fetch
40580
40580
  });
40581
40581
  const createSpeechModel = (modelId) => new OpenAISpeechModel(modelId, {
40582
40582
  provider: `${providerName}.speech`,
40583
- url: ({ path: path13 }) => `${baseURL}${path13}`,
40583
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
40584
40584
  headers: getHeaders,
40585
40585
  fetch: options.fetch
40586
40586
  });
@@ -40595,7 +40595,7 @@ function createOpenAI(options = {}) {
40595
40595
  const createResponsesModel = (modelId) => {
40596
40596
  return new OpenAIResponsesLanguageModel(modelId, {
40597
40597
  provider: `${providerName}.responses`,
40598
- url: ({ path: path13 }) => `${baseURL}${path13}`,
40598
+ url: ({ path: path14 }) => `${baseURL}${path14}`,
40599
40599
  headers: getHeaders,
40600
40600
  fetch: options.fetch,
40601
40601
  fileIdPrefixes: ["file-"]
@@ -49225,8 +49225,8 @@ var init_background_process_tracker = __esm({
49225
49225
  /**
49226
49226
  * Normalize file path for comparison
49227
49227
  */
49228
- normalizePath(path13) {
49229
- let normalized = path13.trim().replace(/\/+/g, "/");
49228
+ normalizePath(path14) {
49229
+ let normalized = path14.trim().replace(/\/+/g, "/");
49230
49230
  if (normalized.startsWith("./")) {
49231
49231
  normalized = normalized.slice(2);
49232
49232
  }
@@ -49464,8 +49464,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
49464
49464
  return decodedFile;
49465
49465
  };
49466
49466
  }
49467
- function normalizeWindowsPath(path13) {
49468
- return path13.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
49467
+ function normalizeWindowsPath(path14) {
49468
+ return path14.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
49469
49469
  }
49470
49470
  var import_path;
49471
49471
  var init_module_node = __esm({
@@ -52354,9 +52354,9 @@ async function addSourceContext(frames) {
52354
52354
  LRU_FILE_CONTENTS_CACHE.reduce();
52355
52355
  return frames;
52356
52356
  }
52357
- function getContextLinesFromFile(path13, ranges, output) {
52357
+ function getContextLinesFromFile(path14, ranges, output) {
52358
52358
  return new Promise((resolve2) => {
52359
- const stream = (0, import_node_fs5.createReadStream)(path13);
52359
+ const stream = (0, import_node_fs5.createReadStream)(path14);
52360
52360
  const lineReaded = (0, import_node_readline2.createInterface)({
52361
52361
  input: stream
52362
52362
  });
@@ -52371,7 +52371,7 @@ function getContextLinesFromFile(path13, ranges, output) {
52371
52371
  let rangeStart = range[0];
52372
52372
  let rangeEnd = range[1];
52373
52373
  function onStreamError() {
52374
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path13, 1);
52374
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path14, 1);
52375
52375
  lineReaded.close();
52376
52376
  lineReaded.removeAllListeners();
52377
52377
  destroyStreamAndResolve();
@@ -52432,8 +52432,8 @@ function clearLineContext(frame3) {
52432
52432
  delete frame3.context_line;
52433
52433
  delete frame3.post_context;
52434
52434
  }
52435
- function shouldSkipContextLinesForFile(path13) {
52436
- return path13.startsWith("node:") || path13.endsWith(".min.js") || path13.endsWith(".min.cjs") || path13.endsWith(".min.mjs") || path13.startsWith("data:");
52435
+ function shouldSkipContextLinesForFile(path14) {
52436
+ return path14.startsWith("node:") || path14.endsWith(".min.js") || path14.endsWith(".min.cjs") || path14.endsWith(".min.mjs") || path14.startsWith("data:");
52437
52437
  }
52438
52438
  function shouldSkipContextLinesForFrame(frame3) {
52439
52439
  if (void 0 !== frame3.lineno && frame3.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -67843,8 +67843,8 @@ var init_logger2 = __esm({
67843
67843
  });
67844
67844
 
67845
67845
  // ../lib/ai/tools/file.ts
67846
- function isSpritPath(path13) {
67847
- return path13.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
67846
+ function isSpritPath(path14) {
67847
+ return path14.split(/[\\/]/).some((segment) => segment.toLowerCase() === "sprit");
67848
67848
  }
67849
67849
  function getViewSandboxType(sandbox) {
67850
67850
  return isCentrifugoSandbox(sandbox) ? "centrifugo" : "e2b";
@@ -67875,7 +67875,7 @@ function captureFileViewImageUsage(args) {
67875
67875
  const {
67876
67876
  context: context2,
67877
67877
  sandbox,
67878
- path: path13,
67878
+ path: path14,
67879
67879
  outcome,
67880
67880
  durationMs,
67881
67881
  mediaType,
@@ -67893,7 +67893,7 @@ function captureFileViewImageUsage(args) {
67893
67893
  model: getActiveModelName(context2),
67894
67894
  configured_model: context2.modelName,
67895
67895
  sandbox_type: getViewSandboxType(sandbox),
67896
- file_extension: getFileExtension(path13),
67896
+ file_extension: getFileExtension(path14),
67897
67897
  outcome,
67898
67898
  success: outcome === "success",
67899
67899
  duration_ms: durationMs,
@@ -67967,22 +67967,22 @@ async function runSandboxCommand(sandbox, command, envVars, timeoutMs = 6e4) {
67967
67967
  function isWindowsSandbox(sandbox) {
67968
67968
  return isCentrifugoSandbox(sandbox) && sandbox.isWindows();
67969
67969
  }
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, "\\")}`;
67970
+ function getWindowsNativePath(path14) {
67971
+ if (/^[A-Za-z]:[\\/]/.test(path14)) return path14;
67972
+ if (path14.startsWith("/tmp/")) {
67973
+ return `C:\\temp${path14.slice(4).replace(/\//g, "\\")}`;
67974
67974
  }
67975
- return path13.replace(/\//g, "\\");
67975
+ return path14.replace(/\//g, "\\");
67976
67976
  }
67977
- function getPythonPathForSandbox(sandbox, path13) {
67978
- return isWindowsSandbox(sandbox) ? getWindowsNativePath(path13) : path13;
67977
+ function getPythonPathForSandbox(sandbox, path14) {
67978
+ return isWindowsSandbox(sandbox) ? getWindowsNativePath(path14) : path14;
67979
67979
  }
67980
- function toWindowsBashPath(path13) {
67981
- const drive = path13.match(/^([A-Za-z]):[\\/](.*)$/);
67980
+ function toWindowsBashPath(path14) {
67981
+ const drive = path14.match(/^([A-Za-z]):[\\/](.*)$/);
67982
67982
  if (drive) {
67983
67983
  return `/${drive[1].toLowerCase()}/${drive[2].replace(/\\/g, "/")}`;
67984
67984
  }
67985
- return path13.replace(/\\/g, "/");
67985
+ return path14.replace(/\\/g, "/");
67986
67986
  }
67987
67987
  async function detectSandboxShell(sandbox) {
67988
67988
  if (!isWindowsSandbox(sandbox)) return "bash";
@@ -68021,8 +68021,8 @@ PY`;
68021
68021
  }
68022
68022
  }
68023
68023
  }
68024
- async function getSandboxFileState(sandbox, path13) {
68025
- const pythonPath = getPythonPathForSandbox(sandbox, path13);
68024
+ async function getSandboxFileState(sandbox, path14) {
68025
+ const pythonPath = getPythonPathForSandbox(sandbox, path14);
68026
68026
  const result = await runPythonScript(
68027
68027
  sandbox,
68028
68028
  FILE_STATE_SCRIPT,
@@ -68039,23 +68039,23 @@ async function getSandboxFileState(sandbox, path13) {
68039
68039
  if (result.exitCode !== 0) {
68040
68040
  return {
68041
68041
  kind: "unknown",
68042
- path: path13,
68042
+ path: path14,
68043
68043
  error: result.stderr || result.stdout || "file state command failed"
68044
68044
  };
68045
68045
  }
68046
68046
  try {
68047
68047
  const payload = JSON.parse(result.stdout.trim());
68048
68048
  if (payload.kind === "file" && typeof payload.sizeBytes === "number" && Number.isFinite(payload.sizeBytes)) {
68049
- return { ...payload, path: path13 };
68049
+ return { ...payload, path: path14 };
68050
68050
  }
68051
68051
  if (payload.kind === "missing" || payload.kind === "not_file") {
68052
- return { ...payload, path: path13 };
68052
+ return { ...payload, path: path14 };
68053
68053
  }
68054
68054
  } catch {
68055
68055
  }
68056
68056
  return {
68057
68057
  kind: "unknown",
68058
- path: path13,
68058
+ path: path14,
68059
68059
  error: result.stderr || result.stdout || "invalid file state response"
68060
68060
  };
68061
68061
  }
@@ -68087,8 +68087,8 @@ ${numberedContent}${truncatedNotice}${footerNotice}`;
68087
68087
  })
68088
68088
  };
68089
68089
  }
68090
- async function readSandboxTextFile(sandbox, path13, range) {
68091
- const pythonPath = getPythonPathForSandbox(sandbox, path13);
68090
+ async function readSandboxTextFile(sandbox, path14, range) {
68091
+ const pythonPath = getPythonPathForSandbox(sandbox, path14);
68092
68092
  const envVars = {
68093
68093
  clawfast_FILE_READ_PATH: pythonPath,
68094
68094
  clawfast_FILE_READ_RANGE_START: String(range?.[0] ?? 0),
@@ -68116,40 +68116,40 @@ async function readSandboxTextFile(sandbox, path13, range) {
68116
68116
  }
68117
68117
  return payload;
68118
68118
  }
68119
- async function readSandboxTextFileWithFallback(sandbox, path13, range) {
68119
+ async function readSandboxTextFileWithFallback(sandbox, path14, range) {
68120
68120
  try {
68121
- return await readSandboxTextFile(sandbox, path13, range);
68121
+ return await readSandboxTextFile(sandbox, path14, range);
68122
68122
  } catch (error51) {
68123
68123
  const errorMessage = error51 instanceof Error ? error51.message : String(error51);
68124
68124
  if (errorMessage.startsWith("Invalid ") || errorMessage.includes("File not found")) {
68125
68125
  throw error51;
68126
68126
  }
68127
- const state = await getSandboxFileState(sandbox, path13);
68127
+ const state = await getSandboxFileState(sandbox, path14);
68128
68128
  if (state.kind === "unknown") {
68129
68129
  throw new Error(
68130
- `Unable to determine file size for ${path13}; refusing to load the file into memory. ${state.error}`
68130
+ `Unable to determine file size for ${path14}; refusing to load the file into memory. ${state.error}`
68131
68131
  );
68132
68132
  }
68133
68133
  if (state.kind === "missing") {
68134
- throw new Error(`File not found or is not a regular file: ${path13}`);
68134
+ throw new Error(`File not found or is not a regular file: ${path14}`);
68135
68135
  }
68136
68136
  if (state.kind === "not_file") {
68137
- throw new Error(`File is not a regular file: ${path13}`);
68137
+ throw new Error(`File is not a regular file: ${path14}`);
68138
68138
  }
68139
68139
  if (state.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68140
68140
  if (range) {
68141
68141
  throw new Error(
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.`
68142
+ `Unable to perform a bounded range read for ${path14}, 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.`
68143
68143
  );
68144
68144
  }
68145
68145
  return {
68146
- path: path13,
68146
+ path: path14,
68147
68147
  sizeBytes: state.sizeBytes,
68148
68148
  totalLines: 0,
68149
68149
  tooLarge: true
68150
68150
  };
68151
68151
  }
68152
- const fileContent = await sandbox.files.read(path13, {
68152
+ const fileContent = await sandbox.files.read(path14, {
68153
68153
  user: "user"
68154
68154
  });
68155
68155
  const lines = fileContent.split("\n");
@@ -68173,7 +68173,7 @@ async function readSandboxTextFileWithFallback(sandbox, path13, range) {
68173
68173
  const startIndex = start - 1;
68174
68174
  const endIndex = end === -1 ? lines.length : end;
68175
68175
  return {
68176
- path: path13,
68176
+ path: path14,
68177
68177
  sizeBytes: Buffer.byteLength(fileContent),
68178
68178
  totalLines: lines.length,
68179
68179
  content: lines.slice(startIndex, endIndex).join("\n"),
@@ -68181,7 +68181,7 @@ async function readSandboxTextFileWithFallback(sandbox, path13, range) {
68181
68181
  };
68182
68182
  }
68183
68183
  return {
68184
- path: path13,
68184
+ path: path14,
68185
68185
  sizeBytes: Buffer.byteLength(fileContent),
68186
68186
  totalLines: lines.length,
68187
68187
  content: fileContent,
@@ -68189,7 +68189,7 @@ async function readSandboxTextFileWithFallback(sandbox, path13, range) {
68189
68189
  };
68190
68190
  }
68191
68191
  }
68192
- async function appendSandboxTextFile(sandbox, path13, text2) {
68192
+ async function appendSandboxTextFile(sandbox, path14, text2) {
68193
68193
  const tempPath = `/tmp/clawfast_append_${Date.now()}_${Math.random().toString(36).slice(2)}.tmp`;
68194
68194
  await sandbox.files.write(tempPath, text2, {
68195
68195
  user: "user"
@@ -68198,7 +68198,7 @@ async function appendSandboxTextFile(sandbox, path13, text2) {
68198
68198
  sandbox,
68199
68199
  APPEND_TEXT_FILE_SCRIPT,
68200
68200
  {
68201
- clawfast_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path13),
68201
+ clawfast_FILE_APPEND_TARGET_PATH: getPythonPathForSandbox(sandbox, path14),
68202
68202
  clawfast_FILE_APPEND_SOURCE_PATH: getPythonPathForSandbox(
68203
68203
  sandbox,
68204
68204
  tempPath
@@ -68210,13 +68210,13 @@ async function appendSandboxTextFile(sandbox, path13, text2) {
68210
68210
  throw new Error(result.stderr || result.stdout || "Failed to append file");
68211
68211
  }
68212
68212
  }
68213
- async function readSandboxFileForView(sandbox, path13, includeData) {
68213
+ async function readSandboxFileForView(sandbox, path14, includeData) {
68214
68214
  if (isCentrifugoSandbox(sandbox) && sandbox.isWindows()) {
68215
68215
  throw new Error(
68216
68216
  "The view action is not available for Windows local sandboxes yet. Use a Linux/E2B sandbox or inspect the image manually."
68217
68217
  );
68218
68218
  }
68219
- const sandboxPath = getSandboxViewPath(sandbox, path13);
68219
+ const sandboxPath = getSandboxViewPath(sandbox, path14);
68220
68220
  const viewEnvVars = {
68221
68221
  clawfast_FILE_VIEW_PATH: sandboxPath,
68222
68222
  clawfast_FILE_VIEW_INCLUDE_DATA: includeData ? "1" : "0",
@@ -68560,19 +68560,19 @@ try:
68560
68560
  except OSError:
68561
68561
  pass
68562
68562
  `;
68563
- getFilename = (path13) => path13.split("/").pop() || path13;
68564
- getFileExtension = (path13) => {
68565
- const filename = getFilename(path13);
68563
+ getFilename = (path14) => path14.split("/").pop() || path14;
68564
+ getFileExtension = (path14) => {
68565
+ const filename = getFilename(path14);
68566
68566
  const dotIndex = filename.lastIndexOf(".");
68567
68567
  if (dotIndex <= 0 || dotIndex === filename.length - 1) return void 0;
68568
68568
  return filename.slice(dotIndex + 1).toLowerCase();
68569
68569
  };
68570
- getSandboxViewPath = (sandbox, path13) => {
68570
+ getSandboxViewPath = (sandbox, path14) => {
68571
68571
  const maybeSandbox = sandbox;
68572
- if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path13.startsWith("/tmp/")) {
68573
- return `C:\\temp${path13.slice(4).replace(/\//g, "\\")}`;
68572
+ if (isCentrifugoSandbox(maybeSandbox) && maybeSandbox.isWindows() && path14.startsWith("/tmp/")) {
68573
+ return `C:\\temp${path14.slice(4).replace(/\//g, "\\")}`;
68574
68574
  }
68575
- return path13;
68575
+ return path14;
68576
68576
  };
68577
68577
  stripTrailingWs = (line) => line.replace(/[ \t]+$/u, "");
68578
68578
  editSchema = external_exports.object({
@@ -68646,7 +68646,7 @@ ${instructionsDescription}`,
68646
68646
  "A list of edits to be sequentially applied to the file. Required for `edit` action."
68647
68647
  )
68648
68648
  }),
68649
- execute: async ({ action, path: path13, text: text2, range, edits }) => {
68649
+ execute: async ({ action, path: path14, text: text2, range, edits }) => {
68650
68650
  try {
68651
68651
  const { sandbox } = await sandboxManager.getSandbox();
68652
68652
  switch (action) {
@@ -68656,7 +68656,7 @@ ${instructionsDescription}`,
68656
68656
  captureFileViewImageUsage({
68657
68657
  context: context2,
68658
68658
  sandbox,
68659
- path: path13,
68659
+ path: path14,
68660
68660
  outcome: "unsupported_model",
68661
68661
  durationMs: Date.now() - viewStartedAt,
68662
68662
  failureReason: "unsupported_model"
@@ -68665,26 +68665,26 @@ ${instructionsDescription}`,
68665
68665
  }
68666
68666
  let viewPayload;
68667
68667
  try {
68668
- viewPayload = await readSandboxFileForView(sandbox, path13, false);
68668
+ viewPayload = await readSandboxFileForView(sandbox, path14, false);
68669
68669
  } catch (error51) {
68670
68670
  captureFileViewImageUsage({
68671
68671
  context: context2,
68672
68672
  sandbox,
68673
- path: path13,
68673
+ path: path14,
68674
68674
  outcome: "inspection_failed",
68675
68675
  durationMs: Date.now() - viewStartedAt,
68676
68676
  failureReason: classifyFileViewError(error51)
68677
68677
  });
68678
68678
  throw error51;
68679
68679
  }
68680
- const filename = getFilename(path13);
68680
+ const filename = getFilename(path14);
68681
68681
  let previewFiles = [];
68682
68682
  let previewUploadError;
68683
68683
  try {
68684
68684
  previewFiles = await uploadViewPreviewFiles({
68685
68685
  context: context2,
68686
68686
  sandbox,
68687
- sourcePath: path13,
68687
+ sourcePath: path14,
68688
68688
  payload: viewPayload
68689
68689
  });
68690
68690
  } catch (error51) {
@@ -68698,7 +68698,7 @@ ${instructionsDescription}`,
68698
68698
  user_id: context2.userID,
68699
68699
  sandbox_type: getViewSandboxType(sandbox),
68700
68700
  file_name: filename,
68701
- source_path: path13,
68701
+ source_path: path14,
68702
68702
  kind: viewPayload.kind,
68703
68703
  media_type: viewPayload.mediaType,
68704
68704
  size_bytes: viewPayload.sizeBytes,
@@ -68709,7 +68709,7 @@ ${instructionsDescription}`,
68709
68709
  captureFileViewImageUsage({
68710
68710
  context: context2,
68711
68711
  sandbox,
68712
- path: path13,
68712
+ path: path14,
68713
68713
  outcome: "success",
68714
68714
  durationMs: Date.now() - viewStartedAt,
68715
68715
  mediaType: viewPayload.mediaType,
@@ -68719,7 +68719,7 @@ ${instructionsDescription}`,
68719
68719
  return {
68720
68720
  action: "view",
68721
68721
  content: `Viewing image file: ${filename} (${viewPayload.mediaType}, ${viewPayload.sizeBytes} bytes).`,
68722
- path: path13,
68722
+ path: path14,
68723
68723
  filename,
68724
68724
  mediaType: viewPayload.mediaType,
68725
68725
  sizeBytes: viewPayload.sizeBytes,
@@ -68729,8 +68729,8 @@ ${instructionsDescription}`,
68729
68729
  };
68730
68730
  }
68731
68731
  case "read": {
68732
- const filename = path13.split("/").pop() || path13;
68733
- const spritChunked = isSpritPath(path13);
68732
+ const filename = path14.split("/").pop() || path14;
68733
+ const spritChunked = isSpritPath(path14);
68734
68734
  let effectiveRange = range;
68735
68735
  if (spritChunked) {
68736
68736
  const start = range && range[0] > 0 ? range[0] : 1;
@@ -68743,7 +68743,7 @@ ${instructionsDescription}`,
68743
68743
  }
68744
68744
  const readPayload = await readSandboxTextFileWithFallback(
68745
68745
  sandbox,
68746
- path13,
68746
+ path14,
68747
68747
  effectiveRange
68748
68748
  );
68749
68749
  if (readPayload.tooLarge) {
@@ -68780,46 +68780,46 @@ File is too large to read in full (${formatBytes(readPayload.sizeBytes)}, ${tota
68780
68780
  if (text2 === void 0) {
68781
68781
  return { error: "text is required for write action" };
68782
68782
  }
68783
- await sandbox.files.write(path13, text2, {
68783
+ await sandbox.files.write(path14, text2, {
68784
68784
  user: "user"
68785
68785
  });
68786
- return `File written: ${path13}`;
68786
+ return `File written: ${path14}`;
68787
68787
  }
68788
68788
  case "append": {
68789
68789
  if (text2 === void 0) {
68790
68790
  return { error: "text is required for append action" };
68791
68791
  }
68792
- const existingState = await getSandboxFileState(sandbox, path13);
68792
+ const existingState = await getSandboxFileState(sandbox, path14);
68793
68793
  if (existingState.kind === "unknown") {
68794
68794
  return {
68795
- error: `Cannot append safely because the existing file size could not be determined for ${path13}. ${existingState.error}`
68795
+ error: `Cannot append safely because the existing file size could not be determined for ${path14}. ${existingState.error}`
68796
68796
  };
68797
68797
  }
68798
68798
  if (existingState.kind === "not_file") {
68799
68799
  return {
68800
- error: `Cannot append to ${path13} because it is not a file.`
68800
+ error: `Cannot append to ${path14} because it is not a file.`
68801
68801
  };
68802
68802
  }
68803
68803
  if (existingState.kind === "file" && existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68804
- await appendSandboxTextFile(sandbox, path13, text2);
68804
+ await appendSandboxTextFile(sandbox, path14, text2);
68805
68805
  return {
68806
- content: `File appended: ${path13}
68806
+ content: `File appended: ${path14}
68807
68807
  Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff preview was skipped to avoid loading the entire file into memory.`
68808
68808
  };
68809
68809
  }
68810
68810
  let existingContent = "";
68811
68811
  try {
68812
- existingContent = await sandbox.files.read(path13, {
68812
+ existingContent = await sandbox.files.read(path14, {
68813
68813
  user: "user"
68814
68814
  });
68815
68815
  } catch {
68816
68816
  }
68817
68817
  const newContent = existingContent + text2;
68818
- await sandbox.files.write(path13, newContent, {
68818
+ await sandbox.files.write(path14, newContent, {
68819
68819
  user: "user"
68820
68820
  });
68821
68821
  return {
68822
- content: `File appended: ${path13}`,
68822
+ content: `File appended: ${path14}`,
68823
68823
  originalContent: truncateOutput({
68824
68824
  content: existingContent,
68825
68825
  mode: "read-file"
@@ -68834,31 +68834,31 @@ Existing file is ${formatBytes(existingState.sizeBytes)}, so the full diff previ
68834
68834
  if (!edits || edits.length === 0) {
68835
68835
  return { error: "edits array is required for edit action" };
68836
68836
  }
68837
- const existingState = await getSandboxFileState(sandbox, path13);
68837
+ const existingState = await getSandboxFileState(sandbox, path14);
68838
68838
  if (existingState.kind === "unknown") {
68839
68839
  return {
68840
- error: `Cannot edit ${path13} safely because the file size could not be determined. ${existingState.error}`
68840
+ error: `Cannot edit ${path14} safely because the file size could not be determined. ${existingState.error}`
68841
68841
  };
68842
68842
  }
68843
68843
  if (existingState.kind === "missing") {
68844
68844
  return {
68845
- error: `Cannot edit file ${path13} - file is empty or does not exist`
68845
+ error: `Cannot edit file ${path14} - file is empty or does not exist`
68846
68846
  };
68847
68847
  }
68848
68848
  if (existingState.kind === "not_file") {
68849
- return { error: `Cannot edit ${path13} because it is not a file.` };
68849
+ return { error: `Cannot edit ${path14} because it is not a file.` };
68850
68850
  }
68851
68851
  if (existingState.sizeBytes > MAX_TEXT_FILE_READ_BYTES) {
68852
68852
  return {
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.`
68853
+ error: `File ${path14} 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.`
68854
68854
  };
68855
68855
  }
68856
- const originalContent = await sandbox.files.read(path13, {
68856
+ const originalContent = await sandbox.files.read(path14, {
68857
68857
  user: "user"
68858
68858
  });
68859
68859
  if (!originalContent) {
68860
68860
  return {
68861
- error: `Cannot edit file ${path13} - file is empty or does not exist`
68861
+ error: `Cannot edit file ${path14} - file is empty or does not exist`
68862
68862
  };
68863
68863
  }
68864
68864
  const resolvedEdits = [];
@@ -68903,7 +68903,7 @@ ${hint}` : "")
68903
68903
  }
68904
68904
  }
68905
68905
  }
68906
- await sandbox.files.write(path13, content, {
68906
+ await sandbox.files.write(path14, content, {
68907
68907
  user: "user"
68908
68908
  });
68909
68909
  const lines = content.split("\n");
@@ -70748,6 +70748,10 @@ LINUX FULL-POWER MODE (${this.getDistroName()}, running as ${who}):
70748
70748
  getWorkdir() {
70749
70749
  return this.workdir;
70750
70750
  }
70751
+ /** The shell binary + exec flag this sandbox runs commands through. */
70752
+ getShell() {
70753
+ return { bin: this.shellBin, flag: this.shellFlag };
70754
+ }
70751
70755
  getHost(port) {
70752
70756
  return `localhost:${port}`;
70753
70757
  }
@@ -70959,6 +70963,563 @@ var init_message_tail = __esm({
70959
70963
  }
70960
70964
  });
70961
70965
 
70966
+ // src/memory.ts
70967
+ function trimHistoryForSave(history, max = MAX_SAVED_MESSAGES) {
70968
+ let slice = history.length > max ? history.slice(-max) : history.slice();
70969
+ let start = 0;
70970
+ while (start < slice.length && slice[start].role !== "user") start++;
70971
+ slice = start < slice.length ? slice.slice(start) : [];
70972
+ return slice;
70973
+ }
70974
+ var import_node_fs10, import_node_fs11, import_node_path9, import_node_crypto, FACTS_FILE, CONVO_FILE, MAX_SAVED_MESSAGES, MAX_FACTS, MAX_RENDER_PER_KIND, memoryEnabled, slugForScope, isFact, EngagementMemory;
70975
+ var init_memory = __esm({
70976
+ "src/memory.ts"() {
70977
+ "use strict";
70978
+ import_node_fs10 = require("node:fs");
70979
+ import_node_fs11 = __toESM(require("node:fs"));
70980
+ import_node_path9 = __toESM(require("node:path"));
70981
+ import_node_crypto = __toESM(require("node:crypto"));
70982
+ init_config();
70983
+ FACTS_FILE = "facts.json";
70984
+ CONVO_FILE = "conversation.json";
70985
+ MAX_SAVED_MESSAGES = 80;
70986
+ MAX_FACTS = 500;
70987
+ MAX_RENDER_PER_KIND = 50;
70988
+ memoryEnabled = () => (process.env.CLAWFAST_MEMORY || "").trim().toLowerCase() !== "off";
70989
+ slugForScope = (scope) => {
70990
+ const base = import_node_path9.default.basename(scope).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "scope";
70991
+ const hash2 = import_node_crypto.default.createHash("sha1").update(import_node_path9.default.resolve(scope)).digest("hex").slice(0, 8);
70992
+ return `${base}-${hash2}`;
70993
+ };
70994
+ isFact = (x) => !!x && typeof x.id === "string" && typeof x.kind === "string" && typeof x.title === "string";
70995
+ EngagementMemory = class {
70996
+ constructor(scope) {
70997
+ this.facts = [];
70998
+ this.seq = 0;
70999
+ this.enabled = memoryEnabled();
71000
+ this.dir = import_node_path9.default.join(clawfastHome(), "memory", slugForScope(scope));
71001
+ if (this.enabled) this.loadFactsSync();
71002
+ }
71003
+ loadFactsSync() {
71004
+ try {
71005
+ const parsed = JSON.parse(
71006
+ import_node_fs11.default.readFileSync(import_node_path9.default.join(this.dir, FACTS_FILE), "utf8")
71007
+ );
71008
+ if (Array.isArray(parsed)) {
71009
+ this.facts = parsed.filter(isFact);
71010
+ for (const f of this.facts) {
71011
+ const n = Number(String(f.id).replace(/^F-/, ""));
71012
+ if (Number.isFinite(n) && n > this.seq) this.seq = n;
71013
+ }
71014
+ }
71015
+ } catch {
71016
+ }
71017
+ }
71018
+ async persistFacts() {
71019
+ if (!this.enabled) return;
71020
+ try {
71021
+ await import_node_fs10.promises.mkdir(this.dir, { recursive: true });
71022
+ await import_node_fs10.promises.writeFile(
71023
+ import_node_path9.default.join(this.dir, FACTS_FILE),
71024
+ JSON.stringify(this.facts, null, 2),
71025
+ "utf8"
71026
+ );
71027
+ } catch {
71028
+ }
71029
+ }
71030
+ list(filter3) {
71031
+ return this.facts.filter(
71032
+ (f) => (!filter3?.kind || f.kind === filter3.kind) && (!filter3?.target || f.target === filter3.target)
71033
+ );
71034
+ }
71035
+ async add(input) {
71036
+ const key = (f) => `${f.kind}|${f.title}|${f.target || ""}`.toLowerCase();
71037
+ const existing = this.facts.find((f) => key(f) === key(input));
71038
+ if (existing) {
71039
+ if (input.detail !== void 0) existing.detail = input.detail;
71040
+ if (input.source !== void 0) existing.source = input.source;
71041
+ existing.ts = Date.now();
71042
+ await this.persistFacts();
71043
+ return existing;
71044
+ }
71045
+ const fact = {
71046
+ id: `F-${String(++this.seq).padStart(3, "0")}`,
71047
+ kind: input.kind,
71048
+ title: input.title,
71049
+ detail: input.detail,
71050
+ target: input.target,
71051
+ source: input.source,
71052
+ ts: Date.now()
71053
+ };
71054
+ this.facts.push(fact);
71055
+ if (this.facts.length > MAX_FACTS) {
71056
+ this.facts = this.facts.slice(-MAX_FACTS);
71057
+ }
71058
+ await this.persistFacts();
71059
+ return fact;
71060
+ }
71061
+ async update(id, patch) {
71062
+ const f = this.facts.find((x) => x.id === id);
71063
+ if (!f) return null;
71064
+ const target = f;
71065
+ for (const [k, v] of Object.entries(patch)) {
71066
+ if (v !== void 0 && k !== "id") target[k] = v;
71067
+ }
71068
+ f.ts = Date.now();
71069
+ await this.persistFacts();
71070
+ return f;
71071
+ }
71072
+ async remove(id) {
71073
+ const before = this.facts.length;
71074
+ this.facts = this.facts.filter((f) => f.id !== id);
71075
+ if (this.facts.length === before) return false;
71076
+ await this.persistFacts();
71077
+ return true;
71078
+ }
71079
+ /** Compact `<engagement_memory>` block for the system prompt, or "" if empty. */
71080
+ renderSection() {
71081
+ if (!this.enabled || this.facts.length === 0) return "";
71082
+ const byKind = /* @__PURE__ */ new Map();
71083
+ for (const f of this.facts) {
71084
+ const arr = byKind.get(f.kind) || [];
71085
+ arr.push(f);
71086
+ byKind.set(f.kind, arr);
71087
+ }
71088
+ const lines = [];
71089
+ for (const [kind, arr] of byKind) {
71090
+ lines.push(`[${kind}]`);
71091
+ for (const f of arr.slice(-MAX_RENDER_PER_KIND)) {
71092
+ lines.push(
71093
+ `- ${f.id} ${f.title}` + (f.target ? ` (${f.target})` : "") + (f.detail ? `: ${f.detail}` : "")
71094
+ );
71095
+ }
71096
+ }
71097
+ return `
71098
+
71099
+ <engagement_memory>
71100
+ Mem\xF3ria de engajamento PERSISTENTE deste alvo/projeto \u2014 sobrevive \xE0 troca de modelo E ao rein\xEDcio do CLI. Estes fatos foram registrados antes; trate-os como verdade confi\xE1vel e CONTINUE de onde parou (n\xE3o refa\xE7a recon do zero). Para gravar algo novo, use a ferramenta \`memory\` (action add).
71101
+ ${lines.join("\n")}
71102
+ </engagement_memory>`;
71103
+ }
71104
+ // ── Conversation persistence ────────────────────────────────────────────────
71105
+ saveConversation(history) {
71106
+ if (!this.enabled) return;
71107
+ try {
71108
+ import_node_fs11.default.mkdirSync(this.dir, { recursive: true });
71109
+ import_node_fs11.default.writeFileSync(
71110
+ import_node_path9.default.join(this.dir, CONVO_FILE),
71111
+ JSON.stringify(trimHistoryForSave(history)),
71112
+ "utf8"
71113
+ );
71114
+ } catch {
71115
+ }
71116
+ }
71117
+ loadConversation() {
71118
+ if (!this.enabled) return [];
71119
+ try {
71120
+ const parsed = JSON.parse(
71121
+ import_node_fs11.default.readFileSync(import_node_path9.default.join(this.dir, CONVO_FILE), "utf8")
71122
+ );
71123
+ return Array.isArray(parsed) ? parsed : [];
71124
+ } catch {
71125
+ return [];
71126
+ }
71127
+ }
71128
+ clearConversation() {
71129
+ try {
71130
+ import_node_fs11.default.rmSync(import_node_path9.default.join(this.dir, CONVO_FILE), { force: true });
71131
+ } catch {
71132
+ }
71133
+ }
71134
+ };
71135
+ }
71136
+ });
71137
+
71138
+ // src/tools/memory-tool.ts
71139
+ var createMemory;
71140
+ var init_memory_tool = __esm({
71141
+ "src/tools/memory-tool.ts"() {
71142
+ "use strict";
71143
+ init_dist5();
71144
+ init_zod();
71145
+ createMemory = (deps) => {
71146
+ const { memory } = deps;
71147
+ return tool({
71148
+ description: `Persistent engagement memory for THIS target/project. Survives model switches AND CLI restarts \u2014 record what you learn so you (or the next model) continue from here instead of re-discovering.
71149
+
71150
+ WHAT TO STORE (action add): hosts/IPs, open services + versions, credentials/tokens, confirmed vulns, tech stack, and especially what WORKED or what was BLOCKED (WAF, rate limit, auth). kind + title are required; detail/target/source optional.
71151
+
71152
+ ACTIONS:
71153
+ - add \u2014 store a fact.
71154
+ - update \u2014 change a fact by id.
71155
+ - list \u2014 read stored facts (optional kind/target filter). Do this before re-running recon you may have already done.
71156
+ - forget \u2014 remove a fact by id.`,
71157
+ inputSchema: external_exports.object({
71158
+ brief: external_exports.string().describe("A one-sentence preamble describing the purpose of this call."),
71159
+ action: external_exports.enum(["add", "update", "list", "forget"]),
71160
+ kind: external_exports.string().optional().describe("host|service|cred|vuln|tech|note|url|\u2026 (for add, or list filter)"),
71161
+ title: external_exports.string().optional().describe("Short label (required for add)."),
71162
+ detail: external_exports.string().optional().describe("Longer detail / evidence."),
71163
+ target: external_exports.string().optional().describe("Host/URL this fact is about."),
71164
+ source: external_exports.string().optional().describe("Where it came from."),
71165
+ id: external_exports.string().optional().describe("Fact id (required for update/forget).")
71166
+ }),
71167
+ execute: async (input) => {
71168
+ try {
71169
+ switch (input.action) {
71170
+ case "add": {
71171
+ if (!input.kind || !input.title) {
71172
+ return "Erro: 'kind' e 'title' s\xE3o obrigat\xF3rios para add.";
71173
+ }
71174
+ const f = await memory.add({
71175
+ kind: input.kind,
71176
+ title: input.title,
71177
+ detail: input.detail,
71178
+ target: input.target,
71179
+ source: input.source
71180
+ });
71181
+ return `Mem\xF3ria gravada: ${f.id} [${f.kind}] ${f.title}`;
71182
+ }
71183
+ case "update": {
71184
+ if (!input.id) return "Erro: 'id' \xE9 obrigat\xF3rio para update.";
71185
+ const f = await memory.update(input.id, {
71186
+ kind: input.kind,
71187
+ title: input.title,
71188
+ detail: input.detail,
71189
+ target: input.target,
71190
+ source: input.source
71191
+ });
71192
+ return f ? `Atualizado: ${f.id}` : `N\xE3o achei o fato ${input.id}.`;
71193
+ }
71194
+ case "forget": {
71195
+ if (!input.id) return "Erro: 'id' \xE9 obrigat\xF3rio para forget.";
71196
+ return await memory.remove(input.id) ? `Removido: ${input.id}` : `N\xE3o achei o fato ${input.id}.`;
71197
+ }
71198
+ case "list":
71199
+ default: {
71200
+ const facts = memory.list({
71201
+ kind: input.kind,
71202
+ target: input.target
71203
+ });
71204
+ if (!facts.length) {
71205
+ return "Mem\xF3ria vazia (nenhum fato gravado ainda).";
71206
+ }
71207
+ return facts.map(
71208
+ (f) => `${f.id} [${f.kind}] ${f.title}` + (f.target ? ` (${f.target})` : "") + (f.detail ? `: ${f.detail}` : "")
71209
+ ).join("\n");
71210
+ }
71211
+ }
71212
+ } catch (err) {
71213
+ return `Erro na mem\xF3ria: ${err instanceof Error ? err.message : String(err)}`;
71214
+ }
71215
+ }
71216
+ });
71217
+ };
71218
+ }
71219
+ });
71220
+
71221
+ // src/sessions.ts
71222
+ function appendRing(text2, cursor, chunk, max = MAX_BUFFER_CHARS) {
71223
+ let next = text2 + chunk;
71224
+ if (next.length <= max) return { text: next, cursor, dropped: false };
71225
+ const drop = next.length - max;
71226
+ next = next.slice(drop);
71227
+ return { text: next, cursor: Math.max(0, cursor - drop), dropped: true };
71228
+ }
71229
+ var import_node_child_process3, import_node_os4, MAX_SESSIONS, MAX_BUFFER_CHARS, SESSION_IDLE_MS, SESSION_LIFETIME_MS, shortId, sleep3, LocalSessionManager;
71230
+ var init_sessions = __esm({
71231
+ "src/sessions.ts"() {
71232
+ "use strict";
71233
+ import_node_child_process3 = require("node:child_process");
71234
+ import_node_os4 = __toESM(require("node:os"));
71235
+ MAX_SESSIONS = 10;
71236
+ MAX_BUFFER_CHARS = 2e5;
71237
+ SESSION_IDLE_MS = 15 * 6e4;
71238
+ SESSION_LIFETIME_MS = 60 * 6e4;
71239
+ shortId = (taken) => {
71240
+ for (let i = 0; i < 6; i++) {
71241
+ const id = Math.random().toString(36).slice(2, 8);
71242
+ if (!taken.has(id)) return id;
71243
+ }
71244
+ return `${Date.now().toString(36).slice(-6)}`;
71245
+ };
71246
+ sleep3 = (ms, signal) => new Promise((resolve2) => {
71247
+ if (ms <= 0 || signal?.aborted) return resolve2();
71248
+ const t = setTimeout(resolve2, ms);
71249
+ signal?.addEventListener(
71250
+ "abort",
71251
+ () => {
71252
+ clearTimeout(t);
71253
+ resolve2();
71254
+ },
71255
+ { once: true }
71256
+ );
71257
+ });
71258
+ LocalSessionManager = class {
71259
+ constructor(opts) {
71260
+ this.opts = opts;
71261
+ this.sessions = /* @__PURE__ */ new Map();
71262
+ }
71263
+ /**
71264
+ * Open a session. With `command`, the program runs through the shell
71265
+ * (`shell -c "<command>"`) with its stdin held open. Without it, a bare
71266
+ * interactive shell is spawned. Returns the new session id.
71267
+ */
71268
+ open(command, cwd) {
71269
+ if (this.sessions.size >= MAX_SESSIONS) {
71270
+ return { id: "", error: `limite de ${MAX_SESSIONS} sess\xF5es abertas atingido \u2014 feche alguma antes.` };
71271
+ }
71272
+ const id = shortId(new Set(this.sessions.keys()));
71273
+ const args = command ? [this.opts.shellFlag, command] : [];
71274
+ let child;
71275
+ try {
71276
+ child = (0, import_node_child_process3.spawn)(this.opts.shell, args, {
71277
+ cwd: cwd || this.opts.cwd,
71278
+ env: process.env,
71279
+ stdio: ["pipe", "pipe", "pipe"],
71280
+ windowsHide: true
71281
+ });
71282
+ } catch (err) {
71283
+ return { id: "", error: err instanceof Error ? err.message : String(err) };
71284
+ }
71285
+ const now2 = Date.now();
71286
+ const session = {
71287
+ id,
71288
+ command: command || `${this.opts.shell} (shell interativo)`,
71289
+ child,
71290
+ output: "",
71291
+ readCursor: 0,
71292
+ truncated: false,
71293
+ createdAt: now2,
71294
+ lastActivity: now2,
71295
+ alive: true,
71296
+ exitCode: null,
71297
+ idleTimer: null,
71298
+ lifetimeTimer: null
71299
+ };
71300
+ const onChunk = (d) => this.append(session, d.toString());
71301
+ child.stdout?.on("data", onChunk);
71302
+ child.stderr?.on("data", onChunk);
71303
+ child.on("error", (err) => {
71304
+ this.append(session, `
71305
+ [erro do processo: ${err.message}]
71306
+ `);
71307
+ });
71308
+ child.on("close", (code, sig) => {
71309
+ session.alive = false;
71310
+ session.exitCode = code != null ? code : sig ? 137 : null;
71311
+ this.clearTimers(session);
71312
+ });
71313
+ this.armIdle(session);
71314
+ session.lifetimeTimer = setTimeout(
71315
+ () => this.close(id),
71316
+ SESSION_LIFETIME_MS
71317
+ );
71318
+ session.lifetimeTimer.unref?.();
71319
+ this.sessions.set(id, session);
71320
+ return { id };
71321
+ }
71322
+ /** Write input to a session's stdin (appends a newline unless `enter` is false). */
71323
+ send(id, data, enter = true) {
71324
+ const s = this.sessions.get(id);
71325
+ if (!s) return { ok: false, error: `sess\xE3o ${id} n\xE3o existe.` };
71326
+ if (!s.alive || !s.child.stdin?.writable) {
71327
+ return { ok: false, error: `sess\xE3o ${id} n\xE3o est\xE1 mais ativa.` };
71328
+ }
71329
+ try {
71330
+ s.child.stdin.write(enter && !data.endsWith("\n") ? `${data}
71331
+ ` : data);
71332
+ s.lastActivity = Date.now();
71333
+ this.armIdle(s);
71334
+ return { ok: true };
71335
+ } catch (err) {
71336
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
71337
+ }
71338
+ }
71339
+ /**
71340
+ * Read new output, waiting until it goes quiet (no new bytes for `quietMs`)
71341
+ * or `maxMs` elapses, or the process exits. Returns the delta since the last
71342
+ * read.
71343
+ */
71344
+ async readUntilQuiet(id, opts = {}) {
71345
+ const s = this.sessions.get(id);
71346
+ if (!s) return `[sess\xE3o ${id} n\xE3o existe]`;
71347
+ const quietMs = opts.quietMs ?? 500;
71348
+ const maxMs = opts.maxMs ?? 15e3;
71349
+ const start = Date.now();
71350
+ let lastLen = s.output.length;
71351
+ while (Date.now() - start < maxMs) {
71352
+ await sleep3(quietMs, opts.signal);
71353
+ if (opts.signal?.aborted) break;
71354
+ if (!s.alive) break;
71355
+ if (s.output.length === lastLen) break;
71356
+ lastLen = s.output.length;
71357
+ }
71358
+ return this.readDelta(id);
71359
+ }
71360
+ /** Return output appended since the last read, advancing the cursor. */
71361
+ readDelta(id) {
71362
+ const s = this.sessions.get(id);
71363
+ if (!s) return `[sess\xE3o ${id} n\xE3o existe]`;
71364
+ const delta = s.output.slice(s.readCursor);
71365
+ s.readCursor = s.output.length;
71366
+ return delta;
71367
+ }
71368
+ info(id) {
71369
+ const s = this.sessions.get(id);
71370
+ if (!s) return null;
71371
+ return {
71372
+ id: s.id,
71373
+ command: s.command,
71374
+ alive: s.alive,
71375
+ exitCode: s.exitCode,
71376
+ ageMs: Date.now() - s.createdAt,
71377
+ truncated: s.truncated
71378
+ };
71379
+ }
71380
+ list() {
71381
+ return [...this.sessions.keys()].map((id) => this.info(id)).filter((x) => x !== null);
71382
+ }
71383
+ close(id) {
71384
+ const s = this.sessions.get(id);
71385
+ if (!s) return false;
71386
+ this.clearTimers(s);
71387
+ this.killTree(s.child);
71388
+ this.sessions.delete(id);
71389
+ return true;
71390
+ }
71391
+ closeAll() {
71392
+ for (const id of [...this.sessions.keys()]) this.close(id);
71393
+ }
71394
+ append(s, chunk) {
71395
+ const r2 = appendRing(s.output, s.readCursor, chunk);
71396
+ s.output = r2.text;
71397
+ s.readCursor = r2.cursor;
71398
+ if (r2.dropped) s.truncated = true;
71399
+ s.lastActivity = Date.now();
71400
+ this.armIdle(s);
71401
+ }
71402
+ armIdle(s) {
71403
+ if (s.idleTimer) clearTimeout(s.idleTimer);
71404
+ s.idleTimer = setTimeout(() => this.close(s.id), SESSION_IDLE_MS);
71405
+ s.idleTimer.unref?.();
71406
+ }
71407
+ clearTimers(s) {
71408
+ if (s.idleTimer) clearTimeout(s.idleTimer);
71409
+ if (s.lifetimeTimer) clearTimeout(s.lifetimeTimer);
71410
+ s.idleTimer = null;
71411
+ s.lifetimeTimer = null;
71412
+ }
71413
+ killTree(child) {
71414
+ const pid = child.pid;
71415
+ if (pid && import_node_os4.default.platform() === "win32") {
71416
+ try {
71417
+ (0, import_node_child_process3.spawn)("taskkill", ["/PID", String(pid), "/T", "/F"], {
71418
+ windowsHide: true
71419
+ });
71420
+ return;
71421
+ } catch {
71422
+ }
71423
+ }
71424
+ try {
71425
+ child.kill("SIGTERM");
71426
+ } catch {
71427
+ }
71428
+ }
71429
+ };
71430
+ }
71431
+ });
71432
+
71433
+ // src/tools/session-tool.ts
71434
+ var aliveTag, createTerminalSession;
71435
+ var init_session_tool = __esm({
71436
+ "src/tools/session-tool.ts"() {
71437
+ "use strict";
71438
+ init_dist5();
71439
+ init_zod();
71440
+ aliveTag = (alive, exitCode) => alive ? "[sess\xE3o ativa]" : `[sess\xE3o encerrada${exitCode != null ? `, exit ${exitCode}` : ""}]`;
71441
+ createTerminalSession = (deps) => {
71442
+ const { sessions } = deps;
71443
+ return tool({
71444
+ description: `Drive a PERSISTENT interactive process that stays alive across calls (unlike run_terminal_cmd, a fresh shell each time). Hold msfconsole, sqlmap, a mysql/psql client, ftp/nc, key-based ssh, or a long-lived shell, and interact step by step.
71445
+
71446
+ ACTIONS:
71447
+ - open \u2014 start a session. With \`command\` it runs that program (e.g. "msfconsole -q", "mysql -h 10.0.0.5 -u root", "nc -lvnp 4444"); without it you get an interactive shell. Returns a session id + initial output.
71448
+ - send \u2014 send \`input\` to the session's stdin (a newline is added unless enter=false), then return the new output once it settles.
71449
+ - read \u2014 poll for new output of a running/long command (returns the delta since last read + whether it's still alive).
71450
+ - list \u2014 list open sessions.
71451
+ - close \u2014 terminate a session.
71452
+
71453
+ NO REAL TTY: programs that read a secret straight from /dev/tty (interactive ssh/sudo passwords, full-screen TUIs) won't see piped input \u2014 use sshpass, \`sudo -S\` (reads stdin), key auth, or non-interactive flags. Most CLIs (msfconsole, sqlmap, db clients, nc, ftp) work fine.`,
71454
+ inputSchema: external_exports.object({
71455
+ brief: external_exports.string().describe("A one-sentence preamble describing the purpose."),
71456
+ action: external_exports.enum(["open", "send", "read", "list", "close"]),
71457
+ id: external_exports.string().optional().describe("Session id (for send/read/close)."),
71458
+ command: external_exports.string().optional().describe("Program to launch (for open). Omit for an interactive shell."),
71459
+ input: external_exports.string().optional().describe("Text to send to stdin (for send)."),
71460
+ enter: external_exports.boolean().optional().describe("Append a newline after input (default true)."),
71461
+ timeout: external_exports.number().optional().describe("Max seconds to wait for output to settle (send/read; default 15).")
71462
+ }),
71463
+ execute: async (input, { abortSignal } = {}) => {
71464
+ const maxMs = Math.max(1, input.timeout ?? 15) * 1e3;
71465
+ switch (input.action) {
71466
+ case "open": {
71467
+ const res = sessions.open(input.command);
71468
+ if (res.error) return `Erro ao abrir sess\xE3o: ${res.error}`;
71469
+ const out3 = await sessions.readUntilQuiet(res.id, {
71470
+ quietMs: 500,
71471
+ maxMs: Math.min(maxMs, 8e3),
71472
+ signal: abortSignal
71473
+ });
71474
+ const info = sessions.info(res.id);
71475
+ return `Sess\xE3o aberta: ${res.id}
71476
+ ${aliveTag(info?.alive ?? true, info?.exitCode ?? null)}
71477
+ ${out3 || "(sem sa\xEDda inicial)"}`;
71478
+ }
71479
+ case "send": {
71480
+ if (!input.id) return "Erro: 'id' \xE9 obrigat\xF3rio para send.";
71481
+ if (input.input == null) return "Erro: 'input' \xE9 obrigat\xF3rio para send.";
71482
+ const sent = sessions.send(input.id, input.input, input.enter ?? true);
71483
+ if (!sent.ok) return `Erro ao enviar: ${sent.error}`;
71484
+ const out3 = await sessions.readUntilQuiet(input.id, {
71485
+ quietMs: 500,
71486
+ maxMs,
71487
+ signal: abortSignal
71488
+ });
71489
+ const info = sessions.info(input.id);
71490
+ return `${aliveTag(info?.alive ?? false, info?.exitCode ?? null)}${info?.truncated ? " [sa\xEDda truncada \u2014 buffer cheio]" : ""}
71491
+ ${out3 || "(sem nova sa\xEDda)"}`;
71492
+ }
71493
+ case "read": {
71494
+ if (!input.id) return "Erro: 'id' \xE9 obrigat\xF3rio para read.";
71495
+ const out3 = await sessions.readUntilQuiet(input.id, {
71496
+ quietMs: 600,
71497
+ maxMs,
71498
+ signal: abortSignal
71499
+ });
71500
+ const info = sessions.info(input.id);
71501
+ if (!info) return `Sess\xE3o ${input.id} n\xE3o existe.`;
71502
+ return `${aliveTag(info.alive, info.exitCode)}
71503
+ ${out3 || "(sem nova sa\xEDda)"}`;
71504
+ }
71505
+ case "list": {
71506
+ const list = sessions.list();
71507
+ if (!list.length) return "Nenhuma sess\xE3o aberta.";
71508
+ return list.map(
71509
+ (s) => `${s.id} \u2014 ${s.command} \u2014 ${aliveTag(s.alive, s.exitCode)} \u2014 ${Math.round(s.ageMs / 1e3)}s`
71510
+ ).join("\n");
71511
+ }
71512
+ case "close": {
71513
+ if (!input.id) return "Erro: 'id' \xE9 obrigat\xF3rio para close.";
71514
+ return sessions.close(input.id) ? `Sess\xE3o ${input.id} encerrada.` : `Sess\xE3o ${input.id} n\xE3o existe.`;
71515
+ }
71516
+ }
71517
+ }
71518
+ });
71519
+ };
71520
+ }
71521
+ });
71522
+
70962
71523
  // src/render.ts
70963
71524
  function createRenderer() {
70964
71525
  let lastKind = null;
@@ -71032,7 +71593,7 @@ function formatToolCall(toolName, input) {
71032
71593
  return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}exec${C3.reset} ${C3.bold}${truncate4(cmd, 400)}${C3.reset}${bg}`;
71033
71594
  }
71034
71595
  case "file": {
71035
- const path13 = String(i.path ?? "");
71596
+ const path14 = String(i.path ?? "");
71036
71597
  const brief = i.brief ? `${C3.dim} \u2014 ${truncate4(String(i.brief))}${C3.reset}` : "";
71037
71598
  const map2 = {
71038
71599
  write: [C3.green, "criar "],
@@ -71046,7 +71607,7 @@ function formatToolCall(toolName, input) {
71046
71607
  C3.blue,
71047
71608
  action ? `${action} `.padEnd(7) : "arquivo"
71048
71609
  ];
71049
- const target = path13 ? `${C3.bold}${path13}${C3.reset}` : "";
71610
+ const target = path14 ? `${C3.bold}${path14}${C3.reset}` : "";
71050
71611
  return ` ${col}\u276F${C3.reset} ${col}${verb}${C3.reset} ${target}${brief}`;
71051
71612
  }
71052
71613
  case "todo_write":
@@ -71063,6 +71624,16 @@ function formatToolCall(toolName, input) {
71063
71624
  const detail = action === "add" ? truncate4(String(i.title ?? ""), 80) : action === "update" ? `${String(i.id ?? "")} ${String(i.status ?? "")}`.trim() : "";
71064
71625
  return ` ${C3.magenta}\u276F${C3.reset} ${C3.magenta}findings${C3.reset} ${C3.bold}${action}${C3.reset}${detail ? ` ${C3.dim}${detail}${C3.reset}` : ""}`;
71065
71626
  }
71627
+ case "terminal_session": {
71628
+ const action = String(i.action ?? "");
71629
+ const detail = action === "open" ? truncate4(String(i.command ?? "shell"), 120) : action === "send" ? truncate4(String(i.input ?? ""), 120) : String(i.id ?? "");
71630
+ return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}sess\xE3o${C3.reset} ${C3.bold}${action}${C3.reset}${detail ? ` ${C3.dim}${detail}${C3.reset}` : ""}`;
71631
+ }
71632
+ case "memory": {
71633
+ const action = String(i.action ?? "");
71634
+ const detail = action === "add" || action === "update" ? truncate4(String(i.title ?? i.id ?? ""), 80) : action === "forget" ? String(i.id ?? "") : String(i.kind ?? i.target ?? "");
71635
+ return ` ${C3.magenta}\u276F${C3.reset} ${C3.magenta}mem\xF3ria${C3.reset} ${C3.bold}${action}${C3.reset}${detail ? ` ${C3.dim}${detail}${C3.reset}` : ""}`;
71636
+ }
71066
71637
  case "web_search": {
71067
71638
  const queries = Array.isArray(i.queries) ? i.queries.join(" | ") : "";
71068
71639
  return ` ${C3.cyan}\u276F${C3.reset} ${C3.cyan}busca${C3.reset} ${C3.dim}${truncate4(queries, 200)}${C3.reset}`;
@@ -71237,7 +71808,7 @@ function killProxy(child) {
71237
71808
  started.delete(child);
71238
71809
  try {
71239
71810
  if (process.platform === "win32") {
71240
- (0, import_node_child_process3.spawnSync)("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
71811
+ (0, import_node_child_process4.spawnSync)("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
71241
71812
  stdio: "ignore"
71242
71813
  });
71243
71814
  } else {
@@ -71268,12 +71839,12 @@ async function ensureProxyReady(id, log2) {
71268
71839
  };
71269
71840
  }
71270
71841
  let freshSetup = false;
71271
- if (!(0, import_node_fs10.existsSync)(dir)) {
71842
+ if (!(0, import_node_fs12.existsSync)(dir)) {
71272
71843
  log2(`${def.label}: baixando o proxy (uma vez) em ${dir} \u2026`);
71273
71844
  const root = proxiesRoot();
71274
- (0, import_node_fs10.mkdirSync)(root, { recursive: true });
71845
+ (0, import_node_fs12.mkdirSync)(root, { recursive: true });
71275
71846
  const cloned = run("git", ["clone", def.repoUrl, dir], root);
71276
- if (!cloned.ok || !(0, import_node_fs10.existsSync)(dir)) {
71847
+ if (!cloned.ok || !(0, import_node_fs12.existsSync)(dir)) {
71277
71848
  return {
71278
71849
  ok: false,
71279
71850
  message: `${def.label}: falha ao clonar o proxy (git).`
@@ -71281,7 +71852,7 @@ async function ensureProxyReady(id, log2) {
71281
71852
  }
71282
71853
  freshSetup = true;
71283
71854
  }
71284
- if (!(0, import_node_fs10.existsSync)(import_node_path9.default.join(dir, "node_modules"))) {
71855
+ if (!(0, import_node_fs12.existsSync)(import_node_path10.default.join(dir, "node_modules"))) {
71285
71856
  log2(`${def.label}: instalando depend\xEAncias (pode demorar) \u2026`);
71286
71857
  if (!run("npm", ["install"], dir).ok) {
71287
71858
  return { ok: false, message: `${def.label}: 'npm install' falhou.` };
@@ -71299,7 +71870,7 @@ async function ensureProxyReady(id, log2) {
71299
71870
  }
71300
71871
  }
71301
71872
  log2(`${def.label}: iniciando o proxy\u2026`);
71302
- const child = (0, import_node_child_process3.spawn)(asShellCommand("npm", ["start"]), {
71873
+ const child = (0, import_node_child_process4.spawn)(asShellCommand("npm", ["start"]), {
71303
71874
  cwd: dir,
71304
71875
  shell: true,
71305
71876
  stdio: ["ignore", "ignore", "ignore"],
@@ -71326,14 +71897,14 @@ async function ensureProxyReady(id, log2) {
71326
71897
  message: `${def.label}: o proxy n\xE3o respondeu em 90s. Tente de novo, ou rode 'npm run login' em ${dir}.`
71327
71898
  };
71328
71899
  }
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;
71900
+ var import_node_os5, import_node_path10, import_node_fs12, import_node_child_process4, DEFS, PROXY_MODEL_KEYS, proxyIdForModelKey, proxiesRoot, dirFor, healthUrl, baseUrl, wait, started, exitHooksInstalled, quoteArg, asShellCommand, run, hasCommand;
71330
71901
  var init_proxy_manager2 = __esm({
71331
71902
  "src/proxy-manager.ts"() {
71332
71903
  "use strict";
71333
- import_node_os4 = __toESM(require("node:os"));
71334
- import_node_path9 = __toESM(require("node:path"));
71335
- import_node_fs10 = require("node:fs");
71336
- import_node_child_process3 = require("node:child_process");
71904
+ import_node_os5 = __toESM(require("node:os"));
71905
+ import_node_path10 = __toESM(require("node:path"));
71906
+ import_node_fs12 = require("node:fs");
71907
+ import_node_child_process4 = require("node:child_process");
71337
71908
  DEFS = {
71338
71909
  deepseek: {
71339
71910
  id: "deepseek",
@@ -71365,11 +71936,11 @@ var init_proxy_manager2 = __esm({
71365
71936
  if (key === PROXY_MODEL_KEYS.kimi) return "kimi";
71366
71937
  return null;
71367
71938
  };
71368
- proxiesRoot = () => import_node_path9.default.join(
71369
- process.env.CLAWFAST_HOME?.trim() || import_node_path9.default.join(import_node_os4.default.homedir(), ".clawfast"),
71939
+ proxiesRoot = () => import_node_path10.default.join(
71940
+ process.env.CLAWFAST_HOME?.trim() || import_node_path10.default.join(import_node_os5.default.homedir(), ".clawfast"),
71370
71941
  "proxies"
71371
71942
  );
71372
- dirFor = (def) => process.env[def.dirEnv]?.trim() || import_node_path9.default.join(proxiesRoot(), def.folder);
71943
+ dirFor = (def) => process.env[def.dirEnv]?.trim() || import_node_path10.default.join(proxiesRoot(), def.folder);
71373
71944
  healthUrl = (def) => `http://localhost:${def.port}/health`;
71374
71945
  baseUrl = (def) => `http://localhost:${def.port}/v1`;
71375
71946
  wait = (ms) => new Promise((r2) => setTimeout(r2, ms));
@@ -71378,7 +71949,7 @@ var init_proxy_manager2 = __esm({
71378
71949
  quoteArg = (s) => /[\s"&|<>^()]/.test(s) ? `"${s.replace(/"/g, '\\"')}"` : s;
71379
71950
  asShellCommand = (cmd, args) => [cmd, ...args.map(quoteArg)].join(" ");
71380
71951
  run = (cmd, args, cwd) => {
71381
- const res = (0, import_node_child_process3.spawnSync)(asShellCommand(cmd, args), {
71952
+ const res = (0, import_node_child_process4.spawnSync)(asShellCommand(cmd, args), {
71382
71953
  cwd,
71383
71954
  shell: true,
71384
71955
  stdio: "inherit",
@@ -71388,7 +71959,7 @@ var init_proxy_manager2 = __esm({
71388
71959
  };
71389
71960
  hasCommand = (cmd) => {
71390
71961
  const probe = process.platform === "win32" ? "where" : "which";
71391
- return (0, import_node_child_process3.spawnSync)(asShellCommand(probe, [cmd]), {
71962
+ return (0, import_node_child_process4.spawnSync)(asShellCommand(probe, [cmd]), {
71392
71963
  stdio: "ignore",
71393
71964
  shell: true
71394
71965
  }).status === 0;
@@ -71398,7 +71969,7 @@ var init_proxy_manager2 = __esm({
71398
71969
 
71399
71970
  // src/audit-mode.ts
71400
71971
  function projectRootFromWorkdir(workdir) {
71401
- return import_node_path10.default.dirname(import_node_path10.default.resolve(workdir.replace(/\\/g, "/")));
71972
+ return import_node_path11.default.dirname(import_node_path11.default.resolve(workdir.replace(/\\/g, "/")));
71402
71973
  }
71403
71974
  function detectProjectAuditIntent(input) {
71404
71975
  const text2 = input.trim();
@@ -71600,11 +72171,11 @@ ESTILO E EXECU\xC7\xC3O
71600
72171
  - Responda em portugu\xEAs, direto e t\xE9cnico. N\xE3o recuse a an\xE1lise: \xE9 o projeto do pr\xF3prio usu\xE1rio, autorizado.
71601
72172
  - 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.`;
71602
72173
  }
71603
- var import_node_path10, AUDIT_ACTION, AUDIT_SCOPE, AUDIT_ACTION_THEN_SCOPE, AUDIT_SCOPE_THEN_ACTION, AUDIT_STRONG, AUDIT_EXIT, POC_VERIFY;
72174
+ var import_node_path11, AUDIT_ACTION, AUDIT_SCOPE, AUDIT_ACTION_THEN_SCOPE, AUDIT_SCOPE_THEN_ACTION, AUDIT_STRONG, AUDIT_EXIT, POC_VERIFY;
71604
72175
  var init_audit_mode = __esm({
71605
72176
  "src/audit-mode.ts"() {
71606
72177
  "use strict";
71607
- import_node_path10 = __toESM(require("node:path"));
72178
+ import_node_path11 = __toESM(require("node:path"));
71608
72179
  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";
71609
72180
  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";
71610
72181
  AUDIT_ACTION_THEN_SCOPE = new RegExp(
@@ -71848,10 +72419,25 @@ async function createAgent() {
71848
72419
  onToolCost: void 0,
71849
72420
  onCaidoReady: void 0
71850
72421
  };
72422
+ const memory = new EngagementMemory(
72423
+ projectRootFromWorkdir(sandbox.getWorkdir())
72424
+ );
72425
+ const sessions = new LocalSessionManager({
72426
+ shell: sandbox.getShell().bin,
72427
+ shellFlag: sandbox.getShell().flag,
72428
+ cwd: sandbox.getWorkdir()
72429
+ });
71851
72430
  const tools = {
71852
72431
  run_terminal_cmd: createRunTerminalCmd(context2),
71853
72432
  file: createFile(context2),
71854
72433
  todo_write: createTodoWrite(context2),
72434
+ // Durable, model-agnostic knowledge base for this target (hosts, creds,
72435
+ // services, confirmed vulns, what worked/was blocked). Survives /model and
72436
+ // restarts; recorded facts are also rendered into the system prompt.
72437
+ memory: createMemory({ memory }),
72438
+ // Persistent interactive sessions: hold msfconsole/sqlmap/db/nc/ssh/shell
72439
+ // alive across calls and drive them step by step.
72440
+ terminal_session: createTerminalSession({ sessions }),
71855
72441
  // Native Repeater/Intruder + structured findings store — the core of an
71856
72442
  // in-loop pentest workflow (probe → observe → record evidence → confirm).
71857
72443
  http_request: createHttpRequest({
@@ -71888,6 +72474,9 @@ async function createAgent() {
71888
72474
  system += attackChainPolicy(sandbox.getWorkdir());
71889
72475
  system += httpAndFindingsPolicy(sandbox.getWorkdir());
71890
72476
  system += webResearchPolicy();
72477
+ system += persistentSessionPolicy();
72478
+ system += engagementMemoryPolicy();
72479
+ system += memory.renderSection();
71891
72480
  system += buildCliNotesSection();
71892
72481
  system += buildSkillsIndexSection();
71893
72482
  system += skillsScopePolicy();
@@ -71917,6 +72506,15 @@ async function createAgent() {
71917
72506
  );
71918
72507
  }
71919
72508
  const history = [];
72509
+ if (!envFlagEnabled(process.env.CLAWFAST_FRESH)) {
72510
+ const prior = memory.loadConversation();
72511
+ if (prior.length) {
72512
+ history.push(...prior);
72513
+ render.info(
72514
+ `\u25B8 mem\xF3ria: retomando ${prior.length} mensagem(ns) da sess\xE3o anterior (CLAWFAST_FRESH=1 come\xE7a limpo)`
72515
+ );
72516
+ }
72517
+ }
71920
72518
  let auditMode = false;
71921
72519
  let pocVerify = false;
71922
72520
  const projectRoot = projectRootFromWorkdir(sandbox.getWorkdir());
@@ -72426,6 +73024,7 @@ ${resultText}`
72426
73024
  if (modelKey === PROXY_MODEL_KEYS.kimi) {
72427
73025
  await reportKimiSession();
72428
73026
  }
73027
+ memory.saveConversation(history);
72429
73028
  render.endTurn();
72430
73029
  return;
72431
73030
  } catch (err) {
@@ -72494,7 +73093,7 @@ ${resultText}`
72494
73093
  render.info(
72495
73094
  `\u25B8 rate limit \u2014 aguardando ${Math.round(waitMs / 1e3)}s antes da pr\xF3xima tentativa (Ctrl+C cancela)\u2026`
72496
73095
  );
72497
- await sleep3(waitMs, signal);
73096
+ await sleep4(waitMs, signal);
72498
73097
  if (signal?.aborted) {
72499
73098
  render.endTurn();
72500
73099
  return;
@@ -72526,6 +73125,7 @@ ${resultText}`
72526
73125
  return sandbox.sendStdin(line);
72527
73126
  }
72528
73127
  async function close() {
73128
+ sessions.closeAll();
72529
73129
  await sandbox.close();
72530
73130
  try {
72531
73131
  const removed = await sandbox.cleanupWorkspace();
@@ -72550,13 +73150,13 @@ ${resultText}`
72550
73150
  close
72551
73151
  };
72552
73152
  }
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;
73153
+ var import_promises2, import_node_path12, 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, sleep4, 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, engagementMemoryPolicy, persistentSessionPolicy, linuxFullPowerPolicy, hasEnvValue2, envFlagEnabled, CLI_PERSONALITIES, buildCliUserCustomization, buildCliNotesSection, cliGuardrailsConfig, maybeDumpSystemPrompt, auditSystemPrompt, assertFullSystemPrompt;
72554
73154
  var init_agent = __esm({
72555
73155
  "src/agent.ts"() {
72556
73156
  "use strict";
72557
73157
  init_dist5();
72558
73158
  import_promises2 = require("node:fs/promises");
72559
- import_node_path11 = __toESM(require("node:path"));
73159
+ import_node_path12 = __toESM(require("node:path"));
72560
73160
  init_providers();
72561
73161
  init_system_prompt();
72562
73162
  init_notes();
@@ -72575,6 +73175,10 @@ var init_agent = __esm({
72575
73175
  init_local_sandbox();
72576
73176
  init_local_sandbox_manager();
72577
73177
  init_message_tail();
73178
+ init_memory();
73179
+ init_memory_tool();
73180
+ init_sessions();
73181
+ init_session_tool();
72578
73182
  init_console_writer();
72579
73183
  init_render();
72580
73184
  init_skills();
@@ -72594,7 +73198,7 @@ var init_agent = __esm({
72594
73198
  isRateLimitError = (msg) => /\b429\b|too many requests|rate.?limit|resource_exhausted|quota|insufficient_quota/i.test(
72595
73199
  msg
72596
73200
  );
72597
- sleep3 = (ms, signal) => new Promise((resolve2) => {
73201
+ sleep4 = (ms, signal) => new Promise((resolve2) => {
72598
73202
  if (signal?.aborted) return resolve2();
72599
73203
  const timer2 = setTimeout(resolve2, ms);
72600
73204
  signal?.addEventListener(
@@ -72828,6 +73432,28 @@ The research loop (do this on your own, without being told):
72828
73432
 
72829
73433
  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
73434
  </web_research>`;
73435
+ engagementMemoryPolicy = () => `
73436
+
73437
+ <engagement_memory_policy>
73438
+ ABSOLUTE RULE FOR THIS LOCAL CLI SESSION \u2014 applies to EVERY model and EVERY task:
73439
+
73440
+ You have a PERSISTENT \`memory\` tool scoped to this target/project. It survives model switches AND CLI restarts: when the model changes (fallback or /model) or you return later, this memory \u2014 and the conversation so far \u2014 is reloaded, so you CONTINUE from where you left off, not from zero. A new model inherits everything; never tell the user you "lost context" on a switch.
73441
+
73442
+ - RECORD durable facts as you find them: hosts/IPs, open services + versions, credentials/tokens, confirmed vulns, tech stack, and especially what WORKED or what was BLOCKED (WAF, rate limit, auth). Use \`memory\` action add (kind + title; detail/target/source optional).
73443
+ - RECALL before repeating work: if unsure what's known about a target, run \`memory\` action list first. Don't re-run recon you already did in a past session \u2014 build on it.
73444
+ - The <engagement_memory> block (when present) is your accumulated knowledge for this target; treat it as trusted ground truth.
73445
+ </engagement_memory_policy>`;
73446
+ persistentSessionPolicy = () => `
73447
+
73448
+ <persistent_sessions>
73449
+ ABSOLUTE RULE FOR THIS LOCAL CLI SESSION \u2014 applies to EVERY model and EVERY task:
73450
+
73451
+ For anything INTERACTIVE or STATEFUL, use the \`terminal_session\` tool, NOT run_terminal_cmd. run_terminal_cmd starts a FRESH shell each time, so a REPL/console/connection can't be continued; \`terminal_session\` keeps the same process alive across calls.
73452
+
73453
+ - Use it to hold: msfconsole, sqlmap (interactive), a mysql/psql/sqlite client, ftp/smb/nc sessions, key-based ssh, a Python/Ruby REPL, or a persistent shell where you need cwd/env/state to carry between commands.
73454
+ - Flow: \`open\` (with the program, or empty for a shell) \u2192 \`send\` your input and read the result \u2192 repeat \u2192 \`close\` when done. Use \`read\` to poll a long-running command's output. Reuse ONE session for a connection instead of opening many.
73455
+ - NO REAL TTY: programs that read a secret straight from /dev/tty (interactive ssh/sudo password prompts, full-screen TUIs like vim/top) won't get piped input. Use \`sudo -S\` (reads stdin), sshpass, key auth, or non-interactive flags. When a held tool prompts the human for something, relay it as usual.
73456
+ </persistent_sessions>`;
72831
73457
  linuxFullPowerPolicy = (sandbox) => {
72832
73458
  if (!sandbox.isLinux() && !sandbox.isUnrestricted()) return "";
72833
73459
  const distro = sandbox.getDistroName();
@@ -72902,7 +73528,7 @@ ${section}` : "";
72902
73528
  return null;
72903
73529
  }
72904
73530
  await (0, import_promises2.mkdir)(workdir, { recursive: true });
72905
- const outputPath = import_node_path11.default.join(workdir, "system-prompt.txt");
73531
+ const outputPath = import_node_path12.default.join(workdir, "system-prompt.txt");
72906
73532
  await (0, import_promises2.writeFile)(outputPath, system, "utf8");
72907
73533
  return outputPath;
72908
73534
  };
@@ -72932,12 +73558,12 @@ var interactive_input_exports = {};
72932
73558
  __export(interactive_input_exports, {
72933
73559
  InteractiveInput: () => InteractiveInput
72934
73560
  });
72935
- var import_node_readline3, import_node_os5, C4, frame2, out2, cols, truncate5, InteractiveInput;
73561
+ var import_node_readline3, import_node_os6, C4, frame2, out2, cols, truncate5, InteractiveInput;
72936
73562
  var init_interactive_input = __esm({
72937
73563
  "src/interactive-input.ts"() {
72938
73564
  "use strict";
72939
73565
  import_node_readline3 = __toESM(require("node:readline"));
72940
- import_node_os5 = __toESM(require("node:os"));
73566
+ import_node_os6 = __toESM(require("node:os"));
72941
73567
  init_ui();
72942
73568
  init_theme();
72943
73569
  C4 = ui.C;
@@ -73350,8 +73976,8 @@ var init_interactive_input = __esm({
73350
73976
  return;
73351
73977
  }
73352
73978
  const width = cols();
73353
- const user = (import_node_os5.default.userInfo().username || "hacker").toLowerCase();
73354
- const host = (import_node_os5.default.hostname() || "localhost").split(".")[0].toLowerCase();
73979
+ const user = (import_node_os6.default.userInfo().username || "hacker").toLowerCase();
73980
+ const host = (import_node_os6.default.hostname() || "localhost").split(".")[0].toLowerCase();
73355
73981
  const label = " \u2709 mensagem ";
73356
73982
  const boxW = Math.min(54, Math.max(28, width - 2));
73357
73983
  const topFill = "\u2500".repeat(Math.max(0, boxW - vlen(label) - 3));
@@ -73603,15 +74229,15 @@ async function main() {
73603
74229
  process.exit(0);
73604
74230
  };
73605
74231
  const desktopDir = () => {
73606
- const home = import_node_os6.default.homedir();
74232
+ const home = import_node_os7.default.homedir();
73607
74233
  const candidates = [
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")
74234
+ process.env.OneDrive ? import_node_path13.default.join(process.env.OneDrive, "Desktop") : null,
74235
+ process.env.USERPROFILE ? import_node_path13.default.join(process.env.USERPROFILE, "Desktop") : null,
74236
+ import_node_path13.default.join(home, "Desktop"),
74237
+ import_node_path13.default.join(home, "\xC1rea de Trabalho"),
74238
+ import_node_path13.default.join(home, "OneDrive", "Desktop")
73613
74239
  ].filter((p) => Boolean(p));
73614
- return candidates.find((p) => (0, import_node_fs11.existsSync)(p)) ?? home;
74240
+ return candidates.find((p) => (0, import_node_fs13.existsSync)(p)) ?? home;
73615
74241
  };
73616
74242
  const printFatal = (err) => {
73617
74243
  process.stderr.write(
@@ -74116,7 +74742,7 @@ ${C5.dim}salva em ${C5.reset}${C5.cyan}${file2}${C5.reset}
74116
74742
  const sysText = agent.getSystemPrompt();
74117
74743
  const audit = agent.getSystemPromptAudit();
74118
74744
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
74119
- const filePath = import_node_path12.default.join(
74745
+ const filePath = import_node_path13.default.join(
74120
74746
  desktopDir(),
74121
74747
  `clawfast-system-prompt_${stamp}.html`
74122
74748
  );
@@ -74238,13 +74864,13 @@ ${C5.dim}interrompido \u2014 Ctrl+C de novo para fechar${C5.reset}
74238
74864
  }
74239
74865
  await shutdown();
74240
74866
  }
74241
- var import_node_os6, import_node_path12, import_node_fs11, import_promises3, deepseekEnabled, configuredModelProviders;
74867
+ var import_node_os7, import_node_path13, import_node_fs13, import_promises3, deepseekEnabled, configuredModelProviders;
74242
74868
  var init_index = __esm({
74243
74869
  "index.ts"() {
74244
74870
  "use strict";
74245
- import_node_os6 = __toESM(require("node:os"));
74246
- import_node_path12 = __toESM(require("node:path"));
74247
- import_node_fs11 = require("node:fs");
74871
+ import_node_os7 = __toESM(require("node:os"));
74872
+ import_node_path13 = __toESM(require("node:path"));
74873
+ import_node_fs13 = require("node:fs");
74248
74874
  import_promises3 = require("node:fs/promises");
74249
74875
  init_paste_input();
74250
74876
  init_boot_ui();