pentesting 0.73.2 → 0.73.3
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/agent-tool-JEFUBDZE.js +989 -0
- package/dist/{chunk-BGEXGHPB.js → chunk-BKWCGMSV.js} +879 -427
- package/dist/{chunk-YFDJI3GO.js → chunk-GLO6TOJN.js} +2 -0
- package/dist/{chunk-KBJPZDIL.js → chunk-UB7RW6LM.js} +267 -153
- package/dist/main.js +1377 -196
- package/dist/{persistence-VFIOGTRC.js → persistence-2WKQHGOL.js} +2 -2
- package/dist/{process-registry-GSHEX2LT.js → process-registry-QIW7ZIUT.js} +1 -1
- package/dist/prompts/main-agent.md +35 -1
- package/dist/prompts/strategist-system.md +34 -0
- package/package.json +1 -1
- package/dist/agent-tool-HYQGTZC4.js +0 -256
|
@@ -65,6 +65,8 @@ var PROCESS_EVENTS = {
|
|
|
65
65
|
CONNECTION_DETECTED: "connection_detected",
|
|
66
66
|
ROLE_CHANGED: "role_changed",
|
|
67
67
|
COMMAND_SENT: "command_sent",
|
|
68
|
+
SHELL_UPGRADE_ATTEMPTED: "shell_upgrade_attempted",
|
|
69
|
+
SHELL_STABILIZED: "shell_stabilized",
|
|
68
70
|
STOPPED: "stopped",
|
|
69
71
|
DIED: "died",
|
|
70
72
|
ZOMBIE_CLEANED: "zombie_cleaned"
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
getProcessEventLog,
|
|
19
19
|
logEvent,
|
|
20
20
|
setProcess
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GLO6TOJN.js";
|
|
22
22
|
|
|
23
23
|
// src/shared/constants/time/conversions.ts
|
|
24
24
|
var MS_PER_MINUTE = 6e4;
|
|
@@ -235,7 +235,7 @@ var INPUT_PROMPT_PATTERNS = [
|
|
|
235
235
|
|
|
236
236
|
// src/shared/constants/agent.ts
|
|
237
237
|
var APP_NAME = "Pentest AI";
|
|
238
|
-
var APP_VERSION = "0.73.
|
|
238
|
+
var APP_VERSION = "0.73.3";
|
|
239
239
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
240
240
|
var LLM_ROLES = {
|
|
241
241
|
SYSTEM: "system",
|
|
@@ -509,6 +509,18 @@ var TOOL_NAMES = {
|
|
|
509
509
|
READ_FILE: "read_file",
|
|
510
510
|
WRITE_FILE: "write_file",
|
|
511
511
|
BG_PROCESS: "bg_process",
|
|
512
|
+
LISTENER_START: "listener_start",
|
|
513
|
+
LISTENER_STATUS: "listener_status",
|
|
514
|
+
SHELL_PROMOTE: "shell_promote",
|
|
515
|
+
SHELL_EXEC: "shell_exec",
|
|
516
|
+
SHELL_CHECK: "shell_check",
|
|
517
|
+
SHELL_UPGRADE: "shell_upgrade",
|
|
518
|
+
EXPLOIT_CREDENTIAL_CHECK: "exploit_credential_check",
|
|
519
|
+
EXPLOIT_ARTIFACT_CHECK: "exploit_artifact_check",
|
|
520
|
+
EXPLOIT_FOOTHOLD_CHECK: "exploit_foothold_check",
|
|
521
|
+
PWN_CRASH_REPRO: "pwn_crash_repro",
|
|
522
|
+
PWN_OFFSET_CHECK: "pwn_offset_check",
|
|
523
|
+
PWN_PAYLOAD_SMOKE: "pwn_payload_smoke",
|
|
512
524
|
// Intelligence & Research
|
|
513
525
|
PARSE_NMAP: "parse_nmap",
|
|
514
526
|
SEARCH_CVE: "search_cve",
|
|
@@ -1507,6 +1519,57 @@ function splitByPipe(command) {
|
|
|
1507
1519
|
}
|
|
1508
1520
|
|
|
1509
1521
|
// src/shared/utils/command-validator/redirect.ts
|
|
1522
|
+
function isAllowedRedirectPath(target) {
|
|
1523
|
+
return SAFE_REDIRECT_PATHS.some((pathPrefix) => target.startsWith(pathPrefix));
|
|
1524
|
+
}
|
|
1525
|
+
function updateQuoteState(ch, state3) {
|
|
1526
|
+
if (ch === "'" && !state3.inDouble) {
|
|
1527
|
+
state3.inSingle = !state3.inSingle;
|
|
1528
|
+
return true;
|
|
1529
|
+
}
|
|
1530
|
+
if (ch === '"' && !state3.inSingle) {
|
|
1531
|
+
state3.inDouble = !state3.inDouble;
|
|
1532
|
+
return true;
|
|
1533
|
+
}
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
function extractFileDescriptor(command, operatorIndex) {
|
|
1537
|
+
let fd = "";
|
|
1538
|
+
let b = operatorIndex - 1;
|
|
1539
|
+
while (b >= 0 && /\d/.test(command[b])) {
|
|
1540
|
+
fd = command[b] + fd;
|
|
1541
|
+
b--;
|
|
1542
|
+
}
|
|
1543
|
+
return fd;
|
|
1544
|
+
}
|
|
1545
|
+
function skipSpaces(command, start) {
|
|
1546
|
+
let index = start;
|
|
1547
|
+
while (index < command.length && /\s/.test(command[index])) index++;
|
|
1548
|
+
return index;
|
|
1549
|
+
}
|
|
1550
|
+
function readRedirectTarget(command, start) {
|
|
1551
|
+
let i = start;
|
|
1552
|
+
let target = "";
|
|
1553
|
+
let targetInSingle = false;
|
|
1554
|
+
let targetInDouble = false;
|
|
1555
|
+
while (i < command.length) {
|
|
1556
|
+
const ch = command[i];
|
|
1557
|
+
if (ch === "'" && !targetInDouble) {
|
|
1558
|
+
targetInSingle = !targetInSingle;
|
|
1559
|
+
i++;
|
|
1560
|
+
continue;
|
|
1561
|
+
}
|
|
1562
|
+
if (ch === '"' && !targetInSingle) {
|
|
1563
|
+
targetInDouble = !targetInDouble;
|
|
1564
|
+
i++;
|
|
1565
|
+
continue;
|
|
1566
|
+
}
|
|
1567
|
+
if (!targetInSingle && !targetInDouble && /[\s|;&<>]/.test(ch)) break;
|
|
1568
|
+
target += ch;
|
|
1569
|
+
i++;
|
|
1570
|
+
}
|
|
1571
|
+
return { target, nextIndex: i };
|
|
1572
|
+
}
|
|
1510
1573
|
function stripRedirects(segment) {
|
|
1511
1574
|
return segment.replace(/\d*>\s*&\d+/g, "").replace(/\d*>>\s*\S+/g, "").replace(/\d*>\s*\S+/g, "").replace(/<\s*\S+/g, "").trim();
|
|
1512
1575
|
}
|
|
@@ -1515,8 +1578,7 @@ function validateRedirects(command) {
|
|
|
1515
1578
|
for (const { type, target } of redirects) {
|
|
1516
1579
|
if (type === ">" || type === ">>") {
|
|
1517
1580
|
if (target.startsWith("&") || target === "/dev/null") continue;
|
|
1518
|
-
|
|
1519
|
-
if (!isAllowed) {
|
|
1581
|
+
if (!isAllowedRedirectPath(target)) {
|
|
1520
1582
|
return {
|
|
1521
1583
|
isSafe: false,
|
|
1522
1584
|
error: `Redirect to '${target}' is not in allowed paths`,
|
|
@@ -1524,8 +1586,7 @@ function validateRedirects(command) {
|
|
|
1524
1586
|
};
|
|
1525
1587
|
}
|
|
1526
1588
|
} else if (type === "<") {
|
|
1527
|
-
|
|
1528
|
-
if (!isAllowed) {
|
|
1589
|
+
if (!isAllowedRedirectPath(target)) {
|
|
1529
1590
|
return {
|
|
1530
1591
|
isSafe: false,
|
|
1531
1592
|
error: `Input redirect from '${target}' is not in allowed paths`,
|
|
@@ -1538,55 +1599,23 @@ function validateRedirects(command) {
|
|
|
1538
1599
|
}
|
|
1539
1600
|
function extractRedirectTargets(command) {
|
|
1540
1601
|
const redirects = [];
|
|
1541
|
-
|
|
1542
|
-
let inDouble = false;
|
|
1602
|
+
const quoteState = { inSingle: false, inDouble: false };
|
|
1543
1603
|
let i = 0;
|
|
1544
1604
|
while (i < command.length) {
|
|
1545
1605
|
const ch = command[i];
|
|
1546
|
-
if (ch
|
|
1547
|
-
inSingle = !inSingle;
|
|
1606
|
+
if (updateQuoteState(ch, quoteState)) {
|
|
1548
1607
|
i++;
|
|
1549
1608
|
continue;
|
|
1550
1609
|
}
|
|
1551
|
-
if (
|
|
1552
|
-
inDouble = !inDouble;
|
|
1553
|
-
i++;
|
|
1554
|
-
continue;
|
|
1555
|
-
}
|
|
1556
|
-
if (!inSingle && !inDouble) {
|
|
1610
|
+
if (!quoteState.inSingle && !quoteState.inDouble) {
|
|
1557
1611
|
if (ch === ">" || ch === "<") {
|
|
1558
1612
|
const isAppend = ch === ">" && command[i + 1] === ">";
|
|
1559
1613
|
const type = isAppend ? ">>" : ch;
|
|
1560
1614
|
const jump = isAppend ? 2 : 1;
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
fd = command[b] + fd;
|
|
1566
|
-
b--;
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
i += jump;
|
|
1570
|
-
while (i < command.length && /\s/.test(command[i])) i++;
|
|
1571
|
-
let target = "";
|
|
1572
|
-
let targetInSingle = false;
|
|
1573
|
-
let targetInDouble = false;
|
|
1574
|
-
while (i < command.length) {
|
|
1575
|
-
const tc = command[i];
|
|
1576
|
-
if (tc === "'" && !targetInDouble) {
|
|
1577
|
-
targetInSingle = !targetInSingle;
|
|
1578
|
-
i++;
|
|
1579
|
-
continue;
|
|
1580
|
-
}
|
|
1581
|
-
if (tc === '"' && !targetInSingle) {
|
|
1582
|
-
targetInDouble = !targetInDouble;
|
|
1583
|
-
i++;
|
|
1584
|
-
continue;
|
|
1585
|
-
}
|
|
1586
|
-
if (!targetInSingle && !targetInDouble && /[\s|;&<>]/.test(tc)) break;
|
|
1587
|
-
target += tc;
|
|
1588
|
-
i++;
|
|
1589
|
-
}
|
|
1615
|
+
const fd = ch === ">" ? extractFileDescriptor(command, i) : "";
|
|
1616
|
+
const targetStart = skipSpaces(command, i + jump);
|
|
1617
|
+
const { target, nextIndex } = readRedirectTarget(command, targetStart);
|
|
1618
|
+
i = nextIndex;
|
|
1590
1619
|
if (target) {
|
|
1591
1620
|
redirects.push({ type, fd, target });
|
|
1592
1621
|
}
|
|
@@ -1946,76 +1975,115 @@ function getTorBrowserArgs() {
|
|
|
1946
1975
|
}
|
|
1947
1976
|
|
|
1948
1977
|
// src/shared/utils/config/tor/wrapper.ts
|
|
1978
|
+
function wrapCurl(command, socks) {
|
|
1979
|
+
if (!/\bcurl\b/.test(command)) return null;
|
|
1980
|
+
if (/--socks5|--proxy\b|-x\s/.test(command)) return command;
|
|
1981
|
+
return command.replace(/\bcurl\b/, `curl --socks5-hostname ${socks}`);
|
|
1982
|
+
}
|
|
1983
|
+
function wrapWget(command, socks) {
|
|
1984
|
+
if (!/\bwget\b/.test(command)) return null;
|
|
1985
|
+
if (/--execute.*proxy|http_proxy|https_proxy/i.test(command)) return command;
|
|
1986
|
+
return command.replace(
|
|
1987
|
+
/\bwget\b/,
|
|
1988
|
+
`wget -e use_proxy=yes -e http_proxy=socks5h://${socks} -e https_proxy=socks5h://${socks}`
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1991
|
+
function wrapSqlmap(command) {
|
|
1992
|
+
if (!/\bsqlmap\b/.test(command)) return null;
|
|
1993
|
+
if (/--tor\b|--proxy\b/.test(command)) return command;
|
|
1994
|
+
return command.replace(
|
|
1995
|
+
/\bsqlmap\b/,
|
|
1996
|
+
`sqlmap --tor --tor-type=SOCKS5 --tor-port=${TOR_PROXY.SOCKS_PORT}`
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
function wrapGobuster(command, socks) {
|
|
2000
|
+
if (!/\bgobuster\b/.test(command)) return null;
|
|
2001
|
+
if (/--proxy\b/.test(command)) return command;
|
|
2002
|
+
return command.replace(/\bgobuster\b/, `gobuster --proxy socks5://${socks}`);
|
|
2003
|
+
}
|
|
2004
|
+
function wrapFfuf(command, socks) {
|
|
2005
|
+
if (!/\bffuf\b/.test(command)) return null;
|
|
2006
|
+
if (/-x\s/.test(command)) return command;
|
|
2007
|
+
return command.replace(/\bffuf\b/, `ffuf -x socks5://${socks}`);
|
|
2008
|
+
}
|
|
2009
|
+
function wrapNmap(command, wrapperPrefix) {
|
|
2010
|
+
if (!/\bnmap\b/.test(command)) return null;
|
|
2011
|
+
let nmapCmd = command;
|
|
2012
|
+
nmapCmd = nmapCmd.replace(/\s-s[SAXFN]\b/g, " -sT");
|
|
2013
|
+
if (!/\s-Pn\b/.test(nmapCmd)) {
|
|
2014
|
+
nmapCmd = nmapCmd.replace(/\bnmap\b/, "nmap -Pn");
|
|
2015
|
+
}
|
|
2016
|
+
return `${wrapperPrefix} ${nmapCmd}`;
|
|
2017
|
+
}
|
|
1949
2018
|
function wrapCommandForTor(command) {
|
|
1950
2019
|
if (!isTorEnabled()) return command;
|
|
1951
|
-
const
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
return command.replace(
|
|
1966
|
-
/\bsqlmap\b/,
|
|
1967
|
-
`sqlmap --tor --tor-type=SOCKS5 --tor-port=${TOR_PROXY.SOCKS_PORT}`
|
|
1968
|
-
);
|
|
1969
|
-
}
|
|
1970
|
-
if (/\bgobuster\b/.test(command)) {
|
|
1971
|
-
if (/--proxy\b/.test(command)) return command;
|
|
1972
|
-
return command.replace(/\bgobuster\b/, `gobuster --proxy socks5://${SOCKS}`);
|
|
1973
|
-
}
|
|
1974
|
-
if (/\bffuf\b/.test(command)) {
|
|
1975
|
-
if (/-x\s/.test(command)) return command;
|
|
1976
|
-
return command.replace(/\bffuf\b/, `ffuf -x socks5://${SOCKS}`);
|
|
1977
|
-
}
|
|
1978
|
-
if (/\bnmap\b/.test(command)) {
|
|
1979
|
-
let nmapCmd = command;
|
|
1980
|
-
nmapCmd = nmapCmd.replace(/\s-s[SAXFN]\b/g, " -sT");
|
|
1981
|
-
if (!/\s-Pn\b/.test(nmapCmd)) {
|
|
1982
|
-
nmapCmd = nmapCmd.replace(/\bnmap\b/, "nmap -Pn");
|
|
2020
|
+
const socks = `${TOR_PROXY.SOCKS_HOST}:${TOR_PROXY.SOCKS_PORT}`;
|
|
2021
|
+
const wrapperPrefix = `${TOR_PROXY.WRAPPER_CMD} ${TOR_PROXY.WRAPPER_FLAGS}`;
|
|
2022
|
+
const handlers = [
|
|
2023
|
+
() => wrapCurl(command, socks),
|
|
2024
|
+
() => wrapWget(command, socks),
|
|
2025
|
+
() => wrapSqlmap(command),
|
|
2026
|
+
() => wrapGobuster(command, socks),
|
|
2027
|
+
() => wrapFfuf(command, socks),
|
|
2028
|
+
() => wrapNmap(command, wrapperPrefix)
|
|
2029
|
+
];
|
|
2030
|
+
for (const handler of handlers) {
|
|
2031
|
+
const wrapped = handler();
|
|
2032
|
+
if (wrapped !== null) {
|
|
2033
|
+
return wrapped;
|
|
1983
2034
|
}
|
|
1984
|
-
return `${TOR_PROXY.WRAPPER_CMD} ${TOR_PROXY.WRAPPER_FLAGS} ${nmapCmd}`;
|
|
1985
2035
|
}
|
|
1986
|
-
return `${
|
|
2036
|
+
return `${wrapperPrefix} ${command}`;
|
|
1987
2037
|
}
|
|
1988
2038
|
|
|
1989
2039
|
// src/shared/utils/config/tor/leak-detector.ts
|
|
2040
|
+
function checkPingLeakRisk(command) {
|
|
2041
|
+
if (!/\bping\b/.test(command)) return null;
|
|
2042
|
+
return {
|
|
2043
|
+
safe: false,
|
|
2044
|
+
reason: "ping uses ICMP \u2014 bypasses Tor, real IP exposed to target",
|
|
2045
|
+
suggestion: "Use TCP probe instead: curl --socks5-hostname 127.0.0.1:9050 -s --connect-timeout 5 http://<target>:<port>"
|
|
2046
|
+
};
|
|
2047
|
+
}
|
|
2048
|
+
function checkTracerouteLeakRisk(command) {
|
|
2049
|
+
if (!/\btraceroute\b|\btracepath\b|\bmtr\b/.test(command)) return null;
|
|
2050
|
+
return {
|
|
2051
|
+
safe: false,
|
|
2052
|
+
reason: "traceroute/tracepath/mtr uses ICMP/UDP \u2014 bypasses Tor, real IP exposed",
|
|
2053
|
+
suggestion: "Skip traceroute when Tor is enabled (reveals all hops including your IP)"
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
function checkDnsLeakRisk(command) {
|
|
2057
|
+
if (!/\bdig\b/.test(command) && !/\bnslookup\b/.test(command) && !/(?:^|[;&|\s])host(?:\s|$)/.test(command)) {
|
|
2058
|
+
return null;
|
|
2059
|
+
}
|
|
2060
|
+
return {
|
|
2061
|
+
safe: false,
|
|
2062
|
+
reason: "dig/host/nslookup use UDP \u2014 DNS query bypasses Tor, real IP visible to DNS server",
|
|
2063
|
+
suggestion: `Use DNS-over-HTTPS: curl --socks5-hostname ${TOR_PROXY.SOCKS_HOST}:${TOR_PROXY.SOCKS_PORT} "https://dns.google/resolve?name=<host>&type=A"`
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
function checkNmapUdpLeakRisk(command) {
|
|
2067
|
+
if (!/\bnmap\b/.test(command) || !/\s-sU\b/.test(command)) return null;
|
|
2068
|
+
return {
|
|
2069
|
+
safe: false,
|
|
2070
|
+
reason: "nmap -sU (UDP scan) bypasses Tor \u2014 UDP is not routed through SOCKS5",
|
|
2071
|
+
suggestion: `Skip UDP scan with Tor ON. Use TCP scan: ${TOR_PROXY.WRAPPER_CMD} ${TOR_PROXY.WRAPPER_FLAGS} nmap -sT -Pn`
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
1990
2074
|
function checkTorLeakRisk(command) {
|
|
1991
2075
|
if (!isTorEnabled()) return { safe: true };
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
suggestion: "Skip traceroute when Tor is enabled (reveals all hops including your IP)"
|
|
2004
|
-
};
|
|
2005
|
-
}
|
|
2006
|
-
if (/\bdig\b/.test(command) || /\bnslookup\b/.test(command) || /(?:^|[;&|\s])host(?:\s|$)/.test(command)) {
|
|
2007
|
-
return {
|
|
2008
|
-
safe: false,
|
|
2009
|
-
reason: "dig/host/nslookup use UDP \u2014 DNS query bypasses Tor, real IP visible to DNS server",
|
|
2010
|
-
suggestion: `Use DNS-over-HTTPS: curl --socks5-hostname ${TOR_PROXY.SOCKS_HOST}:${TOR_PROXY.SOCKS_PORT} "https://dns.google/resolve?name=<host>&type=A"`
|
|
2011
|
-
};
|
|
2012
|
-
}
|
|
2013
|
-
if (/\bnmap\b/.test(command) && /\s-sU\b/.test(command)) {
|
|
2014
|
-
return {
|
|
2015
|
-
safe: false,
|
|
2016
|
-
reason: "nmap -sU (UDP scan) bypasses Tor \u2014 UDP is not routed through SOCKS5",
|
|
2017
|
-
suggestion: `Skip UDP scan with Tor ON. Use TCP scan: ${TOR_PROXY.WRAPPER_CMD} ${TOR_PROXY.WRAPPER_FLAGS} nmap -sT -Pn`
|
|
2018
|
-
};
|
|
2076
|
+
const checks = [
|
|
2077
|
+
checkPingLeakRisk,
|
|
2078
|
+
checkTracerouteLeakRisk,
|
|
2079
|
+
checkDnsLeakRisk,
|
|
2080
|
+
checkNmapUdpLeakRisk
|
|
2081
|
+
];
|
|
2082
|
+
for (const check of checks) {
|
|
2083
|
+
const risk = check(command);
|
|
2084
|
+
if (risk) {
|
|
2085
|
+
return risk;
|
|
2086
|
+
}
|
|
2019
2087
|
}
|
|
2020
2088
|
return { safe: true };
|
|
2021
2089
|
}
|
|
@@ -2606,7 +2674,7 @@ async function cleanupAllProcesses() {
|
|
|
2606
2674
|
cleanupDone = false;
|
|
2607
2675
|
return;
|
|
2608
2676
|
}
|
|
2609
|
-
const { getBackgroundProcessesMap: getBackgroundProcessesMap2 } = await import("./process-registry-
|
|
2677
|
+
const { getBackgroundProcessesMap: getBackgroundProcessesMap2 } = await import("./process-registry-QIW7ZIUT.js");
|
|
2610
2678
|
const backgroundProcesses = getBackgroundProcessesMap2();
|
|
2611
2679
|
terminateAllNatively(backgroundProcesses, "SIGTERM");
|
|
2612
2680
|
await new Promise((r) => setTimeout(r, SYSTEM_LIMITS.CLEANUP_BATCH_WAIT_MS));
|
|
@@ -2674,43 +2742,35 @@ function cleanupOrphanProcesses() {
|
|
|
2674
2742
|
|
|
2675
2743
|
// src/engine/process/resource-summary.ts
|
|
2676
2744
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
2677
|
-
function
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
const
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
const roleIcon = PROCESS_ICONS[p.role] || PROCESS_ICONS[PROCESS_ROLES.BACKGROUND];
|
|
2693
|
-
let lastOutput = "";
|
|
2694
|
-
try {
|
|
2695
|
-
if (p.stdoutFile && existsSync5(p.stdoutFile)) {
|
|
2696
|
-
const content = readFileSync5(p.stdoutFile, "utf-8");
|
|
2697
|
-
const outputLines = content.trim().split("\n");
|
|
2698
|
-
lastOutput = outputLines.slice(-SYSTEM_LIMITS.RECENT_OUTPUT_LINES).join(" | ").replace(/\n/g, " ");
|
|
2699
|
-
}
|
|
2700
|
-
} catch {
|
|
2745
|
+
function formatActiveProcesses(running, lines) {
|
|
2746
|
+
if (running.length === 0) return;
|
|
2747
|
+
lines.push(`Active Assets (${running.length}):`);
|
|
2748
|
+
for (const p of running) {
|
|
2749
|
+
const dur = Math.round(p.durationMs / 1e3);
|
|
2750
|
+
const portInfo = p.listeningPort ? ` port:${p.listeningPort}` : "";
|
|
2751
|
+
const childInfo = p.childPids.length > 0 ? ` children:${p.childPids.join(",")}` : "";
|
|
2752
|
+
const interactiveFlag = p.isInteractive ? ` ${STATUS_MARKERS.INTERACTIVE}` : "";
|
|
2753
|
+
const roleIcon = PROCESS_ICONS[p.role] || PROCESS_ICONS[PROCESS_ROLES.BACKGROUND];
|
|
2754
|
+
let lastOutput = "";
|
|
2755
|
+
try {
|
|
2756
|
+
if (p.stdoutFile && existsSync5(p.stdoutFile)) {
|
|
2757
|
+
const content = readFileSync5(p.stdoutFile, "utf-8");
|
|
2758
|
+
const outputLines = content.trim().split("\n");
|
|
2759
|
+
lastOutput = outputLines.slice(-SYSTEM_LIMITS.RECENT_OUTPUT_LINES).join(" | ").replace(/\n/g, " ");
|
|
2701
2760
|
}
|
|
2702
|
-
|
|
2703
|
-
> Log: ${lastOutput}` : "";
|
|
2704
|
-
lines.push(` ${roleIcon} [${p.id}] PID:${p.pid}${portInfo}${childInfo}${interactiveFlag} [${p.role}] ${p.purpose} (${dur}s)${outputSnippet}`);
|
|
2761
|
+
} catch {
|
|
2705
2762
|
}
|
|
2763
|
+
const outputSnippet = lastOutput ? `
|
|
2764
|
+
> Log: ${lastOutput}` : "";
|
|
2765
|
+
lines.push(` ${roleIcon} [${p.id}] PID:${p.pid}${portInfo}${childInfo}${interactiveFlag} [${p.role}] ${p.purpose} (${dur}s)${outputSnippet}`);
|
|
2706
2766
|
}
|
|
2767
|
+
}
|
|
2768
|
+
function formatZombies(exited, lines) {
|
|
2707
2769
|
const orphans = [];
|
|
2708
2770
|
for (const p of exited) {
|
|
2709
2771
|
if (p.childPids.length > 0) {
|
|
2710
2772
|
const aliveChildren = p.childPids.filter((pid) => isPidAlive(pid));
|
|
2711
|
-
if (aliveChildren.length > 0) {
|
|
2712
|
-
orphans.push({ id: p.id, childPids: aliveChildren });
|
|
2713
|
-
}
|
|
2773
|
+
if (aliveChildren.length > 0) orphans.push({ id: p.id, childPids: aliveChildren });
|
|
2714
2774
|
}
|
|
2715
2775
|
}
|
|
2716
2776
|
if (orphans.length > 0) {
|
|
@@ -2721,10 +2781,8 @@ ${STATUS_MARKERS.WARNING} SUSPECTED ZOMBIES (Orphaned Children):`);
|
|
|
2721
2781
|
}
|
|
2722
2782
|
lines.push(` \u2192 Recommendation: Run bg_process({ action: "stop", process_id: "ID" }) to clean up.`);
|
|
2723
2783
|
}
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
Ports In Use: ${ports.join(", ")}`);
|
|
2727
|
-
}
|
|
2784
|
+
}
|
|
2785
|
+
function formatActiveShells(running, lines) {
|
|
2728
2786
|
const activeShells = running.filter((p) => p.role === PROCESS_ROLES.ACTIVE_SHELL);
|
|
2729
2787
|
if (activeShells.length > 0) {
|
|
2730
2788
|
lines.push(`
|
|
@@ -2733,19 +2791,39 @@ Ports In Use: ${ports.join(", ")}`);
|
|
|
2733
2791
|
lines.push(` \u2192 [${s.id}] Use interact to execute commands. Upgrade if unstable.`);
|
|
2734
2792
|
}
|
|
2735
2793
|
}
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2794
|
+
}
|
|
2795
|
+
function formatExitedProcesses(exited, lines) {
|
|
2796
|
+
if (exited.length === 0) return;
|
|
2797
|
+
lines.push(`Exited Processes (${exited.length}):`);
|
|
2798
|
+
for (const p of exited) {
|
|
2799
|
+
lines.push(` ${STATUS_MARKERS.EXITED} [${p.id}] exit:${p.exitCode} [${p.role}] ${p.description}`);
|
|
2741
2800
|
}
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2801
|
+
}
|
|
2802
|
+
function formatRecentEvents(recentEvents, lines) {
|
|
2803
|
+
if (recentEvents.length === 0) return;
|
|
2804
|
+
lines.push(`Recent Process Events:`);
|
|
2805
|
+
for (const e of recentEvents.slice(-SYSTEM_LIMITS.RECENT_EVENTS_DISPLAY)) {
|
|
2806
|
+
const ago = Math.round((Date.now() - e.timestamp) / 1e3);
|
|
2807
|
+
lines.push(` ${ago}s ago: [${e.event}] ${e.detail}`);
|
|
2748
2808
|
}
|
|
2809
|
+
}
|
|
2810
|
+
function getResourceSummary() {
|
|
2811
|
+
const procs = listBackgroundProcesses();
|
|
2812
|
+
const running = procs.filter((p) => p.isRunning);
|
|
2813
|
+
const exited = procs.filter((p) => !p.isRunning);
|
|
2814
|
+
const ports = getUsedPorts();
|
|
2815
|
+
const recentEvents = getProcessEventLog().slice(-SYSTEM_LIMITS.RECENT_EVENTS_IN_SUMMARY);
|
|
2816
|
+
if (running.length === 0 && exited.length === 0 && recentEvents.length === 0) return "";
|
|
2817
|
+
const lines = [];
|
|
2818
|
+
formatActiveProcesses(running, lines);
|
|
2819
|
+
formatZombies(exited, lines);
|
|
2820
|
+
if (ports.length > 0) {
|
|
2821
|
+
lines.push(`
|
|
2822
|
+
Ports In Use: ${ports.join(", ")}`);
|
|
2823
|
+
}
|
|
2824
|
+
formatActiveShells(running, lines);
|
|
2825
|
+
formatExitedProcesses(exited, lines);
|
|
2826
|
+
formatRecentEvents(recentEvents, lines);
|
|
2749
2827
|
return lines.join("\n");
|
|
2750
2828
|
}
|
|
2751
2829
|
|
|
@@ -3604,6 +3682,7 @@ var StateSerializer = class {
|
|
|
3604
3682
|
const lines = [];
|
|
3605
3683
|
this.formatContextAndMission(state3, lines);
|
|
3606
3684
|
this.formatArtifactsAndObjectives(state3, lines);
|
|
3685
|
+
this.formatDelegatedTasks(state3, lines);
|
|
3607
3686
|
this.formatTargets(state3, lines);
|
|
3608
3687
|
this.formatFindings(state3, lines);
|
|
3609
3688
|
this.formatLoot(state3, lines);
|
|
@@ -3625,6 +3704,34 @@ var StateSerializer = class {
|
|
|
3625
3704
|
}
|
|
3626
3705
|
}
|
|
3627
3706
|
}
|
|
3707
|
+
static formatDelegatedTasks(state3, lines) {
|
|
3708
|
+
const activeTasks = state3.getActiveDelegatedTasks();
|
|
3709
|
+
if (activeTasks.length === 0) return;
|
|
3710
|
+
lines.push(`Delegated Tasks (${activeTasks.length} active):`);
|
|
3711
|
+
for (const task of activeTasks.slice(0, DISPLAY_LIMITS.COMPACT_LIST_ITEMS)) {
|
|
3712
|
+
const waiting = task.waitingOn ? ` waiting:${task.waitingOn}` : "";
|
|
3713
|
+
const workerType = task.nextWorkerType || task.workerType;
|
|
3714
|
+
const worker = workerType ? ` worker:${workerType}` : "";
|
|
3715
|
+
lines.push(` [${task.status}] ${task.task}${worker}${waiting}`);
|
|
3716
|
+
lines.push(` summary: ${task.summary}`);
|
|
3717
|
+
if (task.parentTaskId || task.rootTaskId) {
|
|
3718
|
+
const chainParts = [
|
|
3719
|
+
task.parentTaskId ? `parent:${task.parentTaskId}` : "",
|
|
3720
|
+
task.rootTaskId ? `root:${task.rootTaskId}` : ""
|
|
3721
|
+
].filter(Boolean);
|
|
3722
|
+
lines.push(` chain: ${chainParts.join(" ")}`);
|
|
3723
|
+
}
|
|
3724
|
+
if (task.assets.length > 0) {
|
|
3725
|
+
lines.push(` assets: ${task.assets.join(", ")}`);
|
|
3726
|
+
}
|
|
3727
|
+
if (task.sessions.length > 0) {
|
|
3728
|
+
lines.push(` sessions: ${task.sessions.join(", ")}`);
|
|
3729
|
+
}
|
|
3730
|
+
if (task.resumeHint) {
|
|
3731
|
+
lines.push(` resume: ${task.resumeHint}`);
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
}
|
|
3628
3735
|
static formatContextAndMission(state3, lines) {
|
|
3629
3736
|
const engagement = state3.getEngagement();
|
|
3630
3737
|
const scope = state3.getScope();
|
|
@@ -3761,7 +3868,8 @@ function saveState(state3) {
|
|
|
3761
3868
|
actionLog: state3.getRecentActions(AGENT_LIMITS.MAX_ACTION_LOG),
|
|
3762
3869
|
currentPhase: state3.getPhase(),
|
|
3763
3870
|
missionSummary: state3.getMissionSummary(),
|
|
3764
|
-
missionChecklist: state3.getMissionChecklist()
|
|
3871
|
+
missionChecklist: state3.getMissionChecklist(),
|
|
3872
|
+
delegatedTasks: state3.getDelegatedTasks()
|
|
3765
3873
|
};
|
|
3766
3874
|
const sessionFile = join5(sessionsDir, FILE_PATTERNS.session());
|
|
3767
3875
|
const json = JSON.stringify(snapshot, null, 2);
|
|
@@ -3832,6 +3940,11 @@ function loadState(state3) {
|
|
|
3832
3940
|
if (snapshot.missionChecklist?.length > 0) {
|
|
3833
3941
|
state3.restoreMissionChecklist(snapshot.missionChecklist);
|
|
3834
3942
|
}
|
|
3943
|
+
if (Array.isArray(snapshot.delegatedTasks)) {
|
|
3944
|
+
for (const task of snapshot.delegatedTasks) {
|
|
3945
|
+
state3.restoreDelegatedTask(task);
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3835
3948
|
return true;
|
|
3836
3949
|
} catch (err) {
|
|
3837
3950
|
debugLog("general", `Failed to load state: ${err}`);
|
|
@@ -3922,6 +4035,7 @@ export {
|
|
|
3922
4035
|
COMMAND_EVENT_TYPES,
|
|
3923
4036
|
UI_COMMANDS,
|
|
3924
4037
|
generateId,
|
|
4038
|
+
generatePrefixedId,
|
|
3925
4039
|
WorkingMemory,
|
|
3926
4040
|
EpisodicMemory,
|
|
3927
4041
|
saveSessionSnapshot,
|