pentesting 0.70.2 → 0.70.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +119 -93
- package/package.json +3 -3
package/dist/main.js
CHANGED
|
@@ -120,7 +120,7 @@ var ICONS = {
|
|
|
120
120
|
};
|
|
121
121
|
|
|
122
122
|
// src/shared/utils/debug/debug-logger.ts
|
|
123
|
-
import { appendFileSync, writeFileSync } from "fs";
|
|
123
|
+
import { appendFileSync, writeFileSync, statSync, readFileSync } from "fs";
|
|
124
124
|
import { join } from "path";
|
|
125
125
|
|
|
126
126
|
// src/shared/utils/file-ops/file-utils.ts
|
|
@@ -275,10 +275,14 @@ var FILE_PATTERNS = {
|
|
|
275
275
|
};
|
|
276
276
|
|
|
277
277
|
// src/shared/utils/debug/debug-logger.ts
|
|
278
|
+
var ROTATE_BYTES = 5 * 1024 * 1024;
|
|
279
|
+
var WIPE_BYTES = 20 * 1024 * 1024;
|
|
280
|
+
var ROTATE_CHECK_INTERVAL = 500;
|
|
278
281
|
var DebugLogger = class _DebugLogger {
|
|
279
282
|
static instance;
|
|
280
283
|
logPath;
|
|
281
284
|
initialized = false;
|
|
285
|
+
writeCount = 0;
|
|
282
286
|
constructor(clearOnInit = false) {
|
|
283
287
|
const debugDir = WORKSPACE.DEBUG;
|
|
284
288
|
try {
|
|
@@ -306,6 +310,31 @@ var DebugLogger = class _DebugLogger {
|
|
|
306
310
|
_DebugLogger.instance = new _DebugLogger(clearOnInit);
|
|
307
311
|
return _DebugLogger.instance;
|
|
308
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Rotate or wipe debug.log if it exceeds size thresholds.
|
|
315
|
+
* Called every ROTATE_CHECK_INTERVAL writes to amortize statSync cost.
|
|
316
|
+
*
|
|
317
|
+
* Policy:
|
|
318
|
+
* > 20 MB → wipe entirely (too much data, disk pressure)
|
|
319
|
+
* > 5 MB → keep latest half (recent logs more useful than old ones)
|
|
320
|
+
*/
|
|
321
|
+
rotateIfNeeded() {
|
|
322
|
+
try {
|
|
323
|
+
const size = statSync(this.logPath).size;
|
|
324
|
+
if (size > WIPE_BYTES) {
|
|
325
|
+
writeFileSync(this.logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [GENERAL] === LOG WIPED (exceeded ${Math.round(WIPE_BYTES / 1024 / 1024)}MB) ===
|
|
326
|
+
`);
|
|
327
|
+
} else if (size > ROTATE_BYTES) {
|
|
328
|
+
const content = readFileSync(this.logPath, "utf-8");
|
|
329
|
+
const half = content.slice(Math.floor(content.length / 2));
|
|
330
|
+
const firstNewline = half.indexOf("\n");
|
|
331
|
+
const trimmed = firstNewline >= 0 ? half.slice(firstNewline + 1) : half;
|
|
332
|
+
writeFileSync(this.logPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [GENERAL] === LOG ROTATED (exceeded ${Math.round(ROTATE_BYTES / 1024 / 1024)}MB, kept latest half) ===
|
|
333
|
+
` + trimmed);
|
|
334
|
+
}
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
}
|
|
309
338
|
log(category, message, data) {
|
|
310
339
|
if (!this.initialized || !this.logPath) return;
|
|
311
340
|
try {
|
|
@@ -316,6 +345,9 @@ var DebugLogger = class _DebugLogger {
|
|
|
316
345
|
}
|
|
317
346
|
logLine += "\n";
|
|
318
347
|
appendFileSync(this.logPath, logLine);
|
|
348
|
+
if (++this.writeCount % ROTATE_CHECK_INTERVAL === 0) {
|
|
349
|
+
this.rotateIfNeeded();
|
|
350
|
+
}
|
|
319
351
|
} catch (e) {
|
|
320
352
|
console.error("[DebugLogger] Write error:", e);
|
|
321
353
|
}
|
|
@@ -329,6 +361,9 @@ ${raw}
|
|
|
329
361
|
---
|
|
330
362
|
`;
|
|
331
363
|
appendFileSync(this.logPath, logLine);
|
|
364
|
+
if (++this.writeCount % ROTATE_CHECK_INTERVAL === 0) {
|
|
365
|
+
this.rotateIfNeeded();
|
|
366
|
+
}
|
|
332
367
|
} catch (e) {
|
|
333
368
|
console.error("[DebugLogger] Write error:", e);
|
|
334
369
|
}
|
|
@@ -727,7 +762,7 @@ var INPUT_PROMPT_PATTERNS = [
|
|
|
727
762
|
|
|
728
763
|
// src/shared/constants/agent.ts
|
|
729
764
|
var APP_NAME = "Pentest AI";
|
|
730
|
-
var APP_VERSION = "0.70.
|
|
765
|
+
var APP_VERSION = "0.70.4";
|
|
731
766
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
732
767
|
var LLM_ROLES = {
|
|
733
768
|
SYSTEM: "system",
|
|
@@ -782,7 +817,7 @@ import { render } from "ink";
|
|
|
782
817
|
import chalk from "chalk";
|
|
783
818
|
|
|
784
819
|
// src/platform/tui/app.tsx
|
|
785
|
-
import { useState as
|
|
820
|
+
import { useState as useState8, useCallback as useCallback11, useRef as useRef10 } from "react";
|
|
786
821
|
import { Box as Box19, useApp, useStdout as useStdout4 } from "ink";
|
|
787
822
|
|
|
788
823
|
// src/platform/tui/hooks/useAgent.ts
|
|
@@ -2458,7 +2493,7 @@ var EpisodicMemory = class {
|
|
|
2458
2493
|
};
|
|
2459
2494
|
|
|
2460
2495
|
// src/shared/utils/agent-memory/persistent-memory.ts
|
|
2461
|
-
import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
2496
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
2462
2497
|
import { join as join2 } from "path";
|
|
2463
2498
|
|
|
2464
2499
|
// src/shared/utils/agent-memory/similarity.ts
|
|
@@ -2634,7 +2669,7 @@ var PersistentMemory = class {
|
|
|
2634
2669
|
loadSessionSnapshot() {
|
|
2635
2670
|
try {
|
|
2636
2671
|
if (existsSync2(SNAPSHOT_FILE)) {
|
|
2637
|
-
return JSON.parse(
|
|
2672
|
+
return JSON.parse(readFileSync2(SNAPSHOT_FILE, "utf-8"));
|
|
2638
2673
|
}
|
|
2639
2674
|
} catch {
|
|
2640
2675
|
}
|
|
@@ -2670,7 +2705,7 @@ var PersistentMemory = class {
|
|
|
2670
2705
|
load() {
|
|
2671
2706
|
try {
|
|
2672
2707
|
if (existsSync2(MEMORY_FILE)) {
|
|
2673
|
-
const data = JSON.parse(
|
|
2708
|
+
const data = JSON.parse(readFileSync2(MEMORY_FILE, "utf-8"));
|
|
2674
2709
|
return {
|
|
2675
2710
|
...data,
|
|
2676
2711
|
exploitChains: data.exploitChains ?? []
|
|
@@ -4555,7 +4590,7 @@ Suggestion: ${torLeak.suggestion}`
|
|
|
4555
4590
|
}
|
|
4556
4591
|
|
|
4557
4592
|
// src/engine/tools-base/file-operations.ts
|
|
4558
|
-
import { readFileSync as
|
|
4593
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
4559
4594
|
import { dirname } from "path";
|
|
4560
4595
|
import { join as join3 } from "path";
|
|
4561
4596
|
import { tmpdir } from "os";
|
|
@@ -4575,7 +4610,7 @@ async function readFileContent(filePath) {
|
|
|
4575
4610
|
error: `File not found: ${filePath}`
|
|
4576
4611
|
};
|
|
4577
4612
|
}
|
|
4578
|
-
const content =
|
|
4613
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
4579
4614
|
return {
|
|
4580
4615
|
success: true,
|
|
4581
4616
|
output: content
|
|
@@ -4679,7 +4714,7 @@ function startBackgroundProcess(command, options = {}) {
|
|
|
4679
4714
|
}
|
|
4680
4715
|
|
|
4681
4716
|
// src/engine/process/process-interaction.ts
|
|
4682
|
-
import { existsSync as existsSync4, readFileSync as
|
|
4717
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, appendFileSync as appendFileSync2 } from "fs";
|
|
4683
4718
|
async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WAIT_MS_INTERACT) {
|
|
4684
4719
|
const proc = getProcess(processId);
|
|
4685
4720
|
if (!proc) return { success: false, output: `Process ${processId} not found`, newOutput: "" };
|
|
@@ -4688,7 +4723,7 @@ async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WA
|
|
|
4688
4723
|
let currentLen = 0;
|
|
4689
4724
|
try {
|
|
4690
4725
|
if (existsSync4(proc.stdoutFile)) {
|
|
4691
|
-
currentLen =
|
|
4726
|
+
currentLen = readFileSync4(proc.stdoutFile, "utf-8").length;
|
|
4692
4727
|
}
|
|
4693
4728
|
} catch {
|
|
4694
4729
|
}
|
|
@@ -4702,7 +4737,7 @@ async function sendToProcess(processId, input, waitMs = SYSTEM_LIMITS.DEFAULT_WA
|
|
|
4702
4737
|
let fullStdout = "";
|
|
4703
4738
|
try {
|
|
4704
4739
|
if (existsSync4(proc.stdoutFile)) {
|
|
4705
|
-
fullStdout =
|
|
4740
|
+
fullStdout = readFileSync4(proc.stdoutFile, "utf-8");
|
|
4706
4741
|
}
|
|
4707
4742
|
} catch {
|
|
4708
4743
|
}
|
|
@@ -4724,7 +4759,7 @@ function promoteToShell(processId, description) {
|
|
|
4724
4759
|
}
|
|
4725
4760
|
|
|
4726
4761
|
// src/engine/process/process-monitor.ts
|
|
4727
|
-
import { existsSync as existsSync5, readFileSync as
|
|
4762
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
4728
4763
|
function isProcessRunning(processId) {
|
|
4729
4764
|
const proc = getProcess(processId);
|
|
4730
4765
|
if (!proc) return false;
|
|
@@ -4738,7 +4773,7 @@ function isProcessRunning(processId) {
|
|
|
4738
4773
|
if (proc.role === PROCESS_ROLES.LISTENER) {
|
|
4739
4774
|
try {
|
|
4740
4775
|
if (existsSync5(proc.stdoutFile)) {
|
|
4741
|
-
const stdout =
|
|
4776
|
+
const stdout = readFileSync5(proc.stdoutFile, "utf-8");
|
|
4742
4777
|
if (detectConnection(stdout)) {
|
|
4743
4778
|
promoteToShell(processId, "Reverse shell connected (auto-detected)");
|
|
4744
4779
|
logEvent(processId, PROCESS_EVENTS.CONNECTION_DETECTED, `Connection detected on port ${proc.listeningPort}`);
|
|
@@ -4757,7 +4792,7 @@ function getProcessOutput(processId) {
|
|
|
4757
4792
|
let stderr = "";
|
|
4758
4793
|
try {
|
|
4759
4794
|
if (existsSync5(proc.stdoutFile)) {
|
|
4760
|
-
const content =
|
|
4795
|
+
const content = readFileSync5(proc.stdoutFile, "utf-8");
|
|
4761
4796
|
stdout = content.length > SYSTEM_LIMITS.MAX_STDOUT_SLICE ? `... [truncated ${content.length - SYSTEM_LIMITS.MAX_STDOUT_SLICE} chars] ...
|
|
4762
4797
|
` + content.slice(-SYSTEM_LIMITS.MAX_STDOUT_SLICE) : content;
|
|
4763
4798
|
}
|
|
@@ -4765,7 +4800,7 @@ function getProcessOutput(processId) {
|
|
|
4765
4800
|
}
|
|
4766
4801
|
try {
|
|
4767
4802
|
if (existsSync5(proc.stderrFile)) {
|
|
4768
|
-
const content =
|
|
4803
|
+
const content = readFileSync5(proc.stderrFile, "utf-8");
|
|
4769
4804
|
stderr = content.length > SYSTEM_LIMITS.MAX_STDERR_SLICE ? `... [truncated ${content.length - SYSTEM_LIMITS.MAX_STDERR_SLICE} chars] ...
|
|
4770
4805
|
` + content.slice(-SYSTEM_LIMITS.MAX_STDERR_SLICE) : content;
|
|
4771
4806
|
}
|
|
@@ -4938,7 +4973,7 @@ async function cleanupAllProcesses() {
|
|
|
4938
4973
|
}
|
|
4939
4974
|
|
|
4940
4975
|
// src/engine/process/resource-summary.ts
|
|
4941
|
-
import { existsSync as existsSync6, readFileSync as
|
|
4976
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
4942
4977
|
function getResourceSummary() {
|
|
4943
4978
|
const procs = listBackgroundProcesses();
|
|
4944
4979
|
const running = procs.filter((p) => p.isRunning);
|
|
@@ -4958,7 +4993,7 @@ function getResourceSummary() {
|
|
|
4958
4993
|
let lastOutput = "";
|
|
4959
4994
|
try {
|
|
4960
4995
|
if (p.stdoutFile && existsSync6(p.stdoutFile)) {
|
|
4961
|
-
const content =
|
|
4996
|
+
const content = readFileSync6(p.stdoutFile, "utf-8");
|
|
4962
4997
|
const outputLines = content.trim().split("\n");
|
|
4963
4998
|
lastOutput = outputLines.slice(-SYSTEM_LIMITS.RECENT_OUTPUT_LINES).join(" | ").replace(/\n/g, " ");
|
|
4964
4999
|
}
|
|
@@ -5203,7 +5238,7 @@ BLOCKED (leak real IP): ping, traceroute, dig, nslookup, nmap -sU`
|
|
|
5203
5238
|
};
|
|
5204
5239
|
|
|
5205
5240
|
// src/engine/state/persistence/saver.ts
|
|
5206
|
-
import { writeFileSync as writeFileSync5, readdirSync, statSync, unlinkSync as unlinkSync5 } from "fs";
|
|
5241
|
+
import { writeFileSync as writeFileSync5, readdirSync, statSync as statSync2, unlinkSync as unlinkSync5 } from "fs";
|
|
5207
5242
|
import { join as join4 } from "path";
|
|
5208
5243
|
function saveState(state) {
|
|
5209
5244
|
const sessionsDir = WORKSPACE.SESSIONS;
|
|
@@ -5236,7 +5271,7 @@ function pruneOldSessions(sessionsDir) {
|
|
|
5236
5271
|
return {
|
|
5237
5272
|
name: f,
|
|
5238
5273
|
path: filePath,
|
|
5239
|
-
mtime:
|
|
5274
|
+
mtime: statSync2(filePath).mtimeMs
|
|
5240
5275
|
};
|
|
5241
5276
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
5242
5277
|
const toDelete = sessionFiles.slice(AGENT_LIMITS.MAX_SESSION_FILES);
|
|
@@ -5248,7 +5283,7 @@ function pruneOldSessions(sessionsDir) {
|
|
|
5248
5283
|
}
|
|
5249
5284
|
|
|
5250
5285
|
// src/engine/state/persistence/loader.ts
|
|
5251
|
-
import { readFileSync as
|
|
5286
|
+
import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
|
|
5252
5287
|
import { join as join5 } from "path";
|
|
5253
5288
|
function loadState(state) {
|
|
5254
5289
|
const latestFile = join5(WORKSPACE.SESSIONS, "latest.json");
|
|
@@ -5256,7 +5291,7 @@ function loadState(state) {
|
|
|
5256
5291
|
return false;
|
|
5257
5292
|
}
|
|
5258
5293
|
try {
|
|
5259
|
-
const raw =
|
|
5294
|
+
const raw = readFileSync7(latestFile, "utf-8");
|
|
5260
5295
|
const snapshot = JSON.parse(raw);
|
|
5261
5296
|
if (snapshot.version !== 1) {
|
|
5262
5297
|
debugLog("general", `Unknown snapshot version: ${snapshot.version}`);
|
|
@@ -10357,7 +10392,7 @@ function mutatePayload(request) {
|
|
|
10357
10392
|
}
|
|
10358
10393
|
|
|
10359
10394
|
// src/domains/exploit/tools.ts
|
|
10360
|
-
import { existsSync as existsSync10, statSync as
|
|
10395
|
+
import { existsSync as existsSync10, statSync as statSync3, readdirSync as readdirSync2 } from "fs";
|
|
10361
10396
|
import { join as join10 } from "path";
|
|
10362
10397
|
var hashCrackTool = {
|
|
10363
10398
|
name: TOOL_NAMES.HASH_CRACK,
|
|
@@ -10516,7 +10551,7 @@ Returns: All available wordlists with their paths, sizes, and categories.`,
|
|
|
10516
10551
|
const processFile = (fullPath, fileName) => {
|
|
10517
10552
|
const ext = fileName.split(".").pop()?.toLowerCase();
|
|
10518
10553
|
if (!WORDLIST_EXTENSIONS.has(ext || "")) return;
|
|
10519
|
-
const stats =
|
|
10554
|
+
const stats = statSync3(fullPath);
|
|
10520
10555
|
if (stats.size < minSize) return;
|
|
10521
10556
|
if (!matchesCategory(fullPath)) return;
|
|
10522
10557
|
if (!matchesSearch(fullPath, fileName)) return;
|
|
@@ -11748,19 +11783,19 @@ var LLMClient = class {
|
|
|
11748
11783
|
debugLog("llm", `[${requestId}] Stream request START`, { model: this.model, toolCount: tools?.length, toolNames: tools?.map((t) => t.name), thinking: !!thinking });
|
|
11749
11784
|
const response = await makeRequest(this.baseUrl, this.apiKey, requestBody, callbacks?.abortSignal);
|
|
11750
11785
|
const { context } = createStreamContext(callbacks);
|
|
11751
|
-
|
|
11752
|
-
|
|
11786
|
+
const contentChunks = [];
|
|
11787
|
+
const reasoningChunks = [];
|
|
11753
11788
|
let usage = { input_tokens: 0, output_tokens: 0 };
|
|
11754
11789
|
const currentBlockRef = { value: null };
|
|
11755
11790
|
const toolCallsMap = /* @__PURE__ */ new Map();
|
|
11756
11791
|
let totalChars = 0;
|
|
11757
11792
|
let wasAborted = false;
|
|
11758
11793
|
context.onContent = (text) => {
|
|
11759
|
-
|
|
11794
|
+
contentChunks.push(text);
|
|
11760
11795
|
totalChars += text.length;
|
|
11761
11796
|
};
|
|
11762
11797
|
context.onReasoning = (text) => {
|
|
11763
|
-
|
|
11798
|
+
reasoningChunks.push(text);
|
|
11764
11799
|
totalChars += text.length;
|
|
11765
11800
|
};
|
|
11766
11801
|
context.onUsage = (u) => {
|
|
@@ -11771,7 +11806,7 @@ var LLMClient = class {
|
|
|
11771
11806
|
context.toolCallsMap = toolCallsMap;
|
|
11772
11807
|
wasAborted = await readSSEStream(response, requestId, context, callbacks?.abortSignal);
|
|
11773
11808
|
const toolCalls = resolveToolCalls(toolCallsMap);
|
|
11774
|
-
const stripped = stripThinkTags(
|
|
11809
|
+
const stripped = stripThinkTags(contentChunks.join(""), reasoningChunks.join(""));
|
|
11775
11810
|
return {
|
|
11776
11811
|
content: stripped.cleanText,
|
|
11777
11812
|
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
@@ -12261,7 +12296,7 @@ function handleToolResult(result, call, outputText, progress) {
|
|
|
12261
12296
|
}
|
|
12262
12297
|
|
|
12263
12298
|
// src/shared/utils/context-digest/constants.ts
|
|
12264
|
-
var PASSTHROUGH_THRESHOLD =
|
|
12299
|
+
var PASSTHROUGH_THRESHOLD = 2e3;
|
|
12265
12300
|
var PREPROCESS_THRESHOLD = 3e3;
|
|
12266
12301
|
var MAX_PREPROCESSED_LINES = 800;
|
|
12267
12302
|
var MAX_DUPLICATE_DISPLAY = 3;
|
|
@@ -13135,7 +13170,7 @@ var PHASE_TECHNIQUE_MAP = {
|
|
|
13135
13170
|
};
|
|
13136
13171
|
|
|
13137
13172
|
// src/agents/prompt-builder/prompt-loader.ts
|
|
13138
|
-
import { readFileSync as
|
|
13173
|
+
import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
|
|
13139
13174
|
import { join as join12, dirname as dirname4 } from "path";
|
|
13140
13175
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13141
13176
|
var __dirname2 = dirname4(fileURLToPath2(import.meta.url));
|
|
@@ -13143,13 +13178,13 @@ var PROMPTS_DIR = join12(__dirname2, "../prompts");
|
|
|
13143
13178
|
var TECHNIQUES_DIR = join12(PROMPTS_DIR, PROMPT_PATHS.TECHNIQUES_DIR);
|
|
13144
13179
|
function loadPromptFile(filename) {
|
|
13145
13180
|
const path2 = join12(PROMPTS_DIR, filename);
|
|
13146
|
-
return existsSync11(path2) ?
|
|
13181
|
+
return existsSync11(path2) ? readFileSync8(path2, PROMPT_CONFIG.ENCODING) : "";
|
|
13147
13182
|
}
|
|
13148
13183
|
function loadTechniqueFile(techniqueName) {
|
|
13149
13184
|
const filePath = join12(TECHNIQUES_DIR, `${techniqueName}.md`);
|
|
13150
13185
|
try {
|
|
13151
13186
|
if (!existsSync11(filePath)) return "";
|
|
13152
|
-
return
|
|
13187
|
+
return readFileSync8(filePath, PROMPT_CONFIG.ENCODING);
|
|
13153
13188
|
} catch {
|
|
13154
13189
|
return "";
|
|
13155
13190
|
}
|
|
@@ -13294,11 +13329,11 @@ ${lines.join("\n")}
|
|
|
13294
13329
|
}
|
|
13295
13330
|
|
|
13296
13331
|
// src/shared/utils/journal/reader.ts
|
|
13297
|
-
import { readFileSync as
|
|
13332
|
+
import { readFileSync as readFileSync9, existsSync as existsSync13 } from "fs";
|
|
13298
13333
|
import { join as join14 } from "path";
|
|
13299
13334
|
|
|
13300
13335
|
// src/shared/utils/journal/rotation.ts
|
|
13301
|
-
import { existsSync as existsSync12, readdirSync as readdirSync3, statSync as
|
|
13336
|
+
import { existsSync as existsSync12, readdirSync as readdirSync3, statSync as statSync4, rmSync as rmSync2 } from "fs";
|
|
13302
13337
|
import { join as join13 } from "path";
|
|
13303
13338
|
function parseTurnNumbers(turnsDir) {
|
|
13304
13339
|
if (!existsSync12(turnsDir)) return [];
|
|
@@ -13308,7 +13343,7 @@ function rotateTurnRecords() {
|
|
|
13308
13343
|
try {
|
|
13309
13344
|
const turnsDir = WORKSPACE.TURNS;
|
|
13310
13345
|
if (!existsSync12(turnsDir)) return;
|
|
13311
|
-
const turnDirs = parseTurnNumbers(turnsDir).map((n) => `${TURN_FOLDER_PREFIX}${n}`).filter((e) =>
|
|
13346
|
+
const turnDirs = parseTurnNumbers(turnsDir).map((n) => `${TURN_FOLDER_PREFIX}${n}`).filter((e) => statSync4(join13(turnsDir, e)).isDirectory()).sort((a, b) => Number(a.slice(TURN_FOLDER_PREFIX.length)) - Number(b.slice(TURN_FOLDER_PREFIX.length)));
|
|
13312
13347
|
if (turnDirs.length > MEMORY_LIMITS.MAX_TURN_ENTRIES) {
|
|
13313
13348
|
const dirsToDel = turnDirs.slice(0, turnDirs.length - MEMORY_LIMITS.MAX_TURN_ENTRIES);
|
|
13314
13349
|
for (const dir of dirsToDel) {
|
|
@@ -13334,7 +13369,7 @@ function readJournalSummary() {
|
|
|
13334
13369
|
for (const turn of turnDirs) {
|
|
13335
13370
|
const summaryPath = join14(WORKSPACE.turnPath(turn), TURN_FILES.SUMMARY);
|
|
13336
13371
|
if (existsSync13(summaryPath)) {
|
|
13337
|
-
return
|
|
13372
|
+
return readFileSync9(summaryPath, "utf-8");
|
|
13338
13373
|
}
|
|
13339
13374
|
}
|
|
13340
13375
|
return "";
|
|
@@ -13351,7 +13386,7 @@ function getRecentEntries(count = MEMORY_LIMITS.MAX_TURN_ENTRIES) {
|
|
|
13351
13386
|
try {
|
|
13352
13387
|
const filePath = join14(WORKSPACE.turnPath(turn), TURN_FILES.STRUCTURED);
|
|
13353
13388
|
if (existsSync13(filePath)) {
|
|
13354
|
-
const raw =
|
|
13389
|
+
const raw = readFileSync9(filePath, "utf-8");
|
|
13355
13390
|
entries.push(JSON.parse(raw));
|
|
13356
13391
|
}
|
|
13357
13392
|
} catch {
|
|
@@ -14073,7 +14108,7 @@ function formatForPrompt(directive, isStale = false) {
|
|
|
14073
14108
|
}
|
|
14074
14109
|
|
|
14075
14110
|
// src/agents/strategist/prompt-loader.ts
|
|
14076
|
-
import { readFileSync as
|
|
14111
|
+
import { readFileSync as readFileSync10, existsSync as existsSync14 } from "fs";
|
|
14077
14112
|
import { join as join16, dirname as dirname5 } from "path";
|
|
14078
14113
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
14079
14114
|
var __dirname3 = dirname5(fileURLToPath3(import.meta.url));
|
|
@@ -14081,7 +14116,7 @@ var STRATEGIST_PROMPT_PATH = join16(__dirname3, "../prompts", "strategist-system
|
|
|
14081
14116
|
function loadSystemPrompt() {
|
|
14082
14117
|
try {
|
|
14083
14118
|
if (existsSync14(STRATEGIST_PROMPT_PATH)) {
|
|
14084
|
-
return
|
|
14119
|
+
return readFileSync10(STRATEGIST_PROMPT_PATH, "utf-8");
|
|
14085
14120
|
}
|
|
14086
14121
|
} catch {
|
|
14087
14122
|
}
|
|
@@ -14477,7 +14512,7 @@ async function processReflection(toolJournal, memo14, phase, reflector) {
|
|
|
14477
14512
|
}
|
|
14478
14513
|
|
|
14479
14514
|
// src/agents/main-agent/turn-recorder.ts
|
|
14480
|
-
import { writeFileSync as writeFileSync10, existsSync as existsSync15, readFileSync as
|
|
14515
|
+
import { writeFileSync as writeFileSync10, existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
|
|
14481
14516
|
import { join as join17 } from "path";
|
|
14482
14517
|
async function recordTurn(context) {
|
|
14483
14518
|
const { turnCounter, phase, toolJournal, memo: memo14, reflections, summaryRegenerator } = context;
|
|
@@ -14550,7 +14585,7 @@ async function regenerateSummary(turnCounter, summaryRegenerator, ctx) {
|
|
|
14550
14585
|
if (prevTurn >= 1) {
|
|
14551
14586
|
const prevSummaryPath = join17(WORKSPACE.turnPath(prevTurn), TURN_FILES.SUMMARY);
|
|
14552
14587
|
if (existsSync15(prevSummaryPath)) {
|
|
14553
|
-
existingSummary =
|
|
14588
|
+
existingSummary = readFileSync11(prevSummaryPath, "utf-8");
|
|
14554
14589
|
}
|
|
14555
14590
|
}
|
|
14556
14591
|
const turnData = formatTurnRecord({
|
|
@@ -14888,7 +14923,14 @@ var TUI_DISPLAY_LIMITS = {
|
|
|
14888
14923
|
/** Max chars for thinking block first-line summary */
|
|
14889
14924
|
thinkingSummaryChars: 72,
|
|
14890
14925
|
/** Delay before exit to allow Ink to cleanup */
|
|
14891
|
-
EXIT_DELAY: 100
|
|
14926
|
+
EXIT_DELAY: 100,
|
|
14927
|
+
/**
|
|
14928
|
+
* Maximum number of messages to keep in React state (TUI message list).
|
|
14929
|
+
* WHY: addMessage() uses [...prev, newMsg] spreading — without a cap, long
|
|
14930
|
+
* sessions accumulate thousands of messages and RAM grows without bound.
|
|
14931
|
+
* Oldest messages are pruned first; all content is preserved in the disk archive.
|
|
14932
|
+
*/
|
|
14933
|
+
MAX_MESSAGES: 500
|
|
14892
14934
|
};
|
|
14893
14935
|
|
|
14894
14936
|
// src/platform/tui/hooks/useAgentState.ts
|
|
@@ -14912,7 +14954,13 @@ var useAgentState = () => {
|
|
|
14912
14954
|
const toolStartedAtRef = useRef(0);
|
|
14913
14955
|
const addMessage = useCallback((type, content) => {
|
|
14914
14956
|
const id = generateId();
|
|
14915
|
-
setMessages((prev) =>
|
|
14957
|
+
setMessages((prev) => {
|
|
14958
|
+
const next = [...prev, { id, type, content, timestamp: /* @__PURE__ */ new Date() }];
|
|
14959
|
+
if (next.length > TUI_DISPLAY_LIMITS.MAX_MESSAGES) {
|
|
14960
|
+
return next.slice(next.length - TUI_DISPLAY_LIMITS.MAX_MESSAGES);
|
|
14961
|
+
}
|
|
14962
|
+
return next;
|
|
14963
|
+
});
|
|
14916
14964
|
}, []);
|
|
14917
14965
|
const resetCumulativeCounters = useCallback(() => {
|
|
14918
14966
|
setCurrentTokens(0);
|
|
@@ -16110,7 +16158,7 @@ var useKeyboardShortcuts = ({
|
|
|
16110
16158
|
};
|
|
16111
16159
|
|
|
16112
16160
|
// src/platform/tui/components/MessageList.tsx
|
|
16113
|
-
import { memo as memo7, useState as
|
|
16161
|
+
import { memo as memo7, useState as useState3, useCallback as useCallback8, useRef as useRef6 } from "react";
|
|
16114
16162
|
import { Box as Box8, Text as Text8, useInput as useInput2 } from "ink";
|
|
16115
16163
|
|
|
16116
16164
|
// src/platform/tui/components/messages/ThinkingBlock.tsx
|
|
@@ -16646,34 +16694,12 @@ import { memo as memo6 } from "react";
|
|
|
16646
16694
|
import { Box as Box7, Text as Text7 } from "ink";
|
|
16647
16695
|
|
|
16648
16696
|
// src/platform/tui/components/ShimmerBanner.tsx
|
|
16649
|
-
import {
|
|
16697
|
+
import { memo as memo5 } from "react";
|
|
16650
16698
|
import { Box as Box6, Text as Text6 } from "ink";
|
|
16651
16699
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
16652
|
-
var FRAME_INTERVAL = 60;
|
|
16653
|
-
var WAVE_SPEED = 0.22;
|
|
16654
|
-
var CHAR_GAP = 0.18;
|
|
16655
|
-
var ROW_GAP = 1.6;
|
|
16656
|
-
function waveColor(sin) {
|
|
16657
|
-
const t = (sin + 1) / 2;
|
|
16658
|
-
const r = Math.round(36 + t * (255 - 36));
|
|
16659
|
-
const g = Math.round(150 + t * (255 - 150));
|
|
16660
|
-
const b = Math.round(237 + t * (255 - 237));
|
|
16661
|
-
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
16662
|
-
}
|
|
16663
16700
|
var ShimmerBanner = memo5(({ banner }) => {
|
|
16664
|
-
const [tick, setTick] = useState3(0);
|
|
16665
|
-
useEffect5(() => {
|
|
16666
|
-
const timer = setInterval(() => setTick((t) => t + 1), FRAME_INTERVAL);
|
|
16667
|
-
return () => clearInterval(timer);
|
|
16668
|
-
}, []);
|
|
16669
|
-
const globalPhase = tick * WAVE_SPEED;
|
|
16670
16701
|
const lines = banner.split("\n").filter((l) => l.length > 0);
|
|
16671
|
-
return /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: lines.map((line, row) => /* @__PURE__ */ jsx6(Text6, { children:
|
|
16672
|
-
const phase = globalPhase - col * CHAR_GAP - row * ROW_GAP;
|
|
16673
|
-
const sin = Math.sin(phase);
|
|
16674
|
-
const color = char.trim() === "" ? HEX.primary : waveColor(sin);
|
|
16675
|
-
return /* @__PURE__ */ jsx6(Text6, { color, children: char }, col);
|
|
16676
|
-
}) }, row)) });
|
|
16702
|
+
return /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: lines.map((line, row) => /* @__PURE__ */ jsx6(Text6, { color: HEX.primary, children: line }, row)) });
|
|
16677
16703
|
});
|
|
16678
16704
|
|
|
16679
16705
|
// src/platform/tui/components/messages/EmptyState.tsx
|
|
@@ -16739,7 +16765,7 @@ function computeSlidingWindow(messages, scrollOffset) {
|
|
|
16739
16765
|
// src/platform/tui/components/MessageList.tsx
|
|
16740
16766
|
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
16741
16767
|
var MessageList = memo7(({ messages, isModalOpen, modelName, autoApproveMode, version, scrollOffset = 0 }) => {
|
|
16742
|
-
const [expandedIds, setExpandedIds] =
|
|
16768
|
+
const [expandedIds, setExpandedIds] = useState3(/* @__PURE__ */ new Set());
|
|
16743
16769
|
const messagesRef = useRef6(messages);
|
|
16744
16770
|
messagesRef.current = messages;
|
|
16745
16771
|
const isModalOpenRef = useRef6(isModalOpen);
|
|
@@ -16821,12 +16847,12 @@ import { memo as memo10 } from "react";
|
|
|
16821
16847
|
import { Box as Box11, Text as Text13 } from "ink";
|
|
16822
16848
|
|
|
16823
16849
|
// src/platform/tui/hooks/useStatusTimer.ts
|
|
16824
|
-
import { useState as
|
|
16850
|
+
import { useState as useState4, useEffect as useEffect5, useRef as useRef7 } from "react";
|
|
16825
16851
|
var useStatusTimer = (currentStatus, isProcessing) => {
|
|
16826
|
-
const [statusElapsed, setStatusElapsed] =
|
|
16852
|
+
const [statusElapsed, setStatusElapsed] = useState4(0);
|
|
16827
16853
|
const statusTimerRef = useRef7(null);
|
|
16828
16854
|
const statusStartRef = useRef7(Date.now());
|
|
16829
|
-
|
|
16855
|
+
useEffect5(() => {
|
|
16830
16856
|
if (statusTimerRef.current) clearInterval(statusTimerRef.current);
|
|
16831
16857
|
if (isProcessing && currentStatus) {
|
|
16832
16858
|
statusStartRef.current = Date.now();
|
|
@@ -16849,7 +16875,7 @@ var useStatusTimer = (currentStatus, isProcessing) => {
|
|
|
16849
16875
|
import { Box as Box9, Text as Text10 } from "ink";
|
|
16850
16876
|
|
|
16851
16877
|
// src/platform/tui/components/MusicSpinner.tsx
|
|
16852
|
-
import { useState as
|
|
16878
|
+
import { useState as useState5, useEffect as useEffect6, memo as memo8 } from "react";
|
|
16853
16879
|
import { Text as Text9 } from "ink";
|
|
16854
16880
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
16855
16881
|
var FRAMES = [
|
|
@@ -16868,10 +16894,10 @@ var FRAMES = [
|
|
|
16868
16894
|
"\u2727",
|
|
16869
16895
|
"\u2726"
|
|
16870
16896
|
];
|
|
16871
|
-
var INTERVAL =
|
|
16897
|
+
var INTERVAL = 150;
|
|
16872
16898
|
var MusicSpinner = memo8(({ color }) => {
|
|
16873
|
-
const [index, setIndex] =
|
|
16874
|
-
|
|
16899
|
+
const [index, setIndex] = useState5(0);
|
|
16900
|
+
useEffect6(() => {
|
|
16875
16901
|
const timer = setInterval(() => {
|
|
16876
16902
|
setIndex((i) => (i + 1) % FRAMES.length);
|
|
16877
16903
|
}, INTERVAL);
|
|
@@ -16912,11 +16938,11 @@ var RetryView = ({ retryState }) => {
|
|
|
16912
16938
|
import { Box as Box10, Text as Text12 } from "ink";
|
|
16913
16939
|
|
|
16914
16940
|
// src/platform/tui/components/ShimmerText.tsx
|
|
16915
|
-
import { useState as
|
|
16941
|
+
import { useState as useState6, useEffect as useEffect7, memo as memo9 } from "react";
|
|
16916
16942
|
import { Text as Text11 } from "ink";
|
|
16917
16943
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
16918
|
-
var
|
|
16919
|
-
var
|
|
16944
|
+
var FRAME_INTERVAL = 120;
|
|
16945
|
+
var WAVE_SPEED = 0.25;
|
|
16920
16946
|
var CHAR_PHASE_GAP = 0.55;
|
|
16921
16947
|
function sinToColor(sin) {
|
|
16922
16948
|
const t = (sin + 1) / 2;
|
|
@@ -16925,14 +16951,14 @@ function sinToColor(sin) {
|
|
|
16925
16951
|
return `#${hex}${hex}${hex}`;
|
|
16926
16952
|
}
|
|
16927
16953
|
var ShimmerText = memo9(({ children, bold, phase = 0 }) => {
|
|
16928
|
-
const [tick, setTick] =
|
|
16929
|
-
|
|
16954
|
+
const [tick, setTick] = useState6(0);
|
|
16955
|
+
useEffect7(() => {
|
|
16930
16956
|
const timer = setInterval(() => {
|
|
16931
16957
|
setTick((t) => t + 1);
|
|
16932
|
-
},
|
|
16958
|
+
}, FRAME_INTERVAL);
|
|
16933
16959
|
return () => clearInterval(timer);
|
|
16934
16960
|
}, []);
|
|
16935
|
-
const globalPhase = tick *
|
|
16961
|
+
const globalPhase = tick * WAVE_SPEED + phase;
|
|
16936
16962
|
return /* @__PURE__ */ jsx11(Text11, { bold, children: Array.from(children).map((char, i) => {
|
|
16937
16963
|
const charPhase = globalPhase - i * CHAR_PHASE_GAP;
|
|
16938
16964
|
const sin = Math.sin(charPhase);
|
|
@@ -17010,7 +17036,7 @@ var StatusDisplay = memo10(({
|
|
|
17010
17036
|
});
|
|
17011
17037
|
|
|
17012
17038
|
// src/platform/tui/components/ChatInput.tsx
|
|
17013
|
-
import { useMemo, useCallback as useCallback9, useRef as useRef8, memo as memo11, useState as
|
|
17039
|
+
import { useMemo, useCallback as useCallback9, useRef as useRef8, memo as memo11, useState as useState7, useEffect as useEffect8 } from "react";
|
|
17014
17040
|
import { Box as Box15, Text as Text17, useInput as useInput3 } from "ink";
|
|
17015
17041
|
|
|
17016
17042
|
// src/platform/tui/components/input/AutocompletePreview.tsx
|
|
@@ -17133,7 +17159,7 @@ var ChatInput = memo11(({
|
|
|
17133
17159
|
return getMatchingCommands(partialCmd).slice(0, MAX_SUGGESTIONS);
|
|
17134
17160
|
}, [isSlashMode, partialCmd, hasArgs]);
|
|
17135
17161
|
const showPreview = isSlashMode && !hasArgs && suggestions.length > 0;
|
|
17136
|
-
const [selectedIdx, setSelectedIdx] =
|
|
17162
|
+
const [selectedIdx, setSelectedIdx] = useState7(0);
|
|
17137
17163
|
const clampedIdx = Math.min(selectedIdx, Math.max(0, suggestions.length - 1));
|
|
17138
17164
|
const selectedIdxRef = useRef8(clampedIdx);
|
|
17139
17165
|
selectedIdxRef.current = clampedIdx;
|
|
@@ -17149,10 +17175,10 @@ var ChatInput = memo11(({
|
|
|
17149
17175
|
inputRequestRef.current = inputRequest;
|
|
17150
17176
|
const onChangeRef = useRef8(onChange);
|
|
17151
17177
|
onChangeRef.current = onChange;
|
|
17152
|
-
const [pastedHint, setPastedHint] =
|
|
17178
|
+
const [pastedHint, setPastedHint] = useState7(null);
|
|
17153
17179
|
const prevValueRef = useRef8(value);
|
|
17154
17180
|
const pasteTimerRef = useRef8(null);
|
|
17155
|
-
|
|
17181
|
+
useEffect8(() => {
|
|
17156
17182
|
const diff = value.length - prevValueRef.current.length;
|
|
17157
17183
|
if (diff > 20) {
|
|
17158
17184
|
if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current);
|
|
@@ -17164,7 +17190,7 @@ var ChatInput = memo11(({
|
|
|
17164
17190
|
if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current);
|
|
17165
17191
|
};
|
|
17166
17192
|
}, [value]);
|
|
17167
|
-
const [inputKey, setInputKey] =
|
|
17193
|
+
const [inputKey, setInputKey] = useState7(0);
|
|
17168
17194
|
const completeCommand = useCallback9((idx) => {
|
|
17169
17195
|
const sug = suggestionsRef.current;
|
|
17170
17196
|
if (!sug.length) return;
|
|
@@ -17485,10 +17511,10 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
17485
17511
|
const { exit } = useApp();
|
|
17486
17512
|
const { stdout } = useStdout4();
|
|
17487
17513
|
const terminalWidth = stdout?.columns ?? 80;
|
|
17488
|
-
const [input, setInput] =
|
|
17489
|
-
const [secretInput, setSecretInput] =
|
|
17490
|
-
const [autoApproveMode, setAutoApproveMode] =
|
|
17491
|
-
const [modal, setModal] =
|
|
17514
|
+
const [input, setInput] = useState8("");
|
|
17515
|
+
const [secretInput, setSecretInput] = useState8("");
|
|
17516
|
+
const [autoApproveMode, setAutoApproveMode] = useState8(autoApprove);
|
|
17517
|
+
const [modal, setModal] = useState8({ type: null, content: "", scrollOffset: 0 });
|
|
17492
17518
|
const {
|
|
17493
17519
|
agent,
|
|
17494
17520
|
messages,
|
|
@@ -17521,7 +17547,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
17521
17547
|
const clearInput = useCallback11(() => {
|
|
17522
17548
|
setInput("");
|
|
17523
17549
|
}, []);
|
|
17524
|
-
const [historyScrollOffset, setHistoryScrollOffset] =
|
|
17550
|
+
const [historyScrollOffset, setHistoryScrollOffset] = useState8(0);
|
|
17525
17551
|
const handleScroll = useCallback11((delta) => {
|
|
17526
17552
|
setHistoryScrollOffset((prev) => Math.max(0, prev - delta));
|
|
17527
17553
|
}, []);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pentesting",
|
|
3
|
-
"version": "0.70.
|
|
3
|
+
"version": "0.70.4",
|
|
4
4
|
"description": "Autonomous Penetration Testing AI Agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"type": "git",
|
|
36
36
|
"url": "git+https://github.com/agnusdei1207"
|
|
37
37
|
},
|
|
38
|
-
"homepage": "https://agnusdei1207.github.io/brainscience/",
|
|
38
|
+
"homepage": "https://agnusdei1207.github.io/brainscience/pentesting",
|
|
39
39
|
"bugs": {
|
|
40
|
-
"url": "https://agnusdei1207.github.io/brainscience/"
|
|
40
|
+
"url": "https://agnusdei1207.github.io/brainscience/pentesting"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|
|
43
43
|
"penetration-testing",
|