pentesting 0.72.8 → 0.72.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/{chunk-74KL4OOU.js → chunk-GHJPYI4S.js} +0 -8
- package/dist/{chunk-6YWYFB6E.js → chunk-SLDFXMHL.js} +166 -117
- package/dist/main.js +1154 -570
- package/dist/{persistence-RDC7AENL.js → persistence-7FTYXIZY.js} +2 -2
- package/dist/{process-registry-BDTYM4MC.js → process-registry-CCAQVJ4Y.js} +1 -1
- package/dist/prompts/base.md +7 -7
- package/dist/prompts/llm/input-processor-system.md +55 -0
- package/dist/prompts/llm/{summary-regenerator-system.md → memory-synth-system.md} +1 -1
- package/dist/prompts/llm/triage-system.md +1 -1
- package/dist/prompts/offensive-playbook.md +24 -3
- package/dist/prompts/recon.md +11 -2
- package/dist/prompts/strategist-system.md +16 -12
- package/dist/prompts/strategy.md +35 -2
- package/dist/prompts/techniques/auth-access.md +1 -1
- package/dist/prompts/techniques/forensics.md +1 -1
- package/dist/prompts/techniques/pwn.md +1 -1
- package/dist/prompts/vuln.md +9 -0
- package/dist/prompts/web.md +9 -0
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -48,20 +48,23 @@ import {
|
|
|
48
48
|
WORKSPACE,
|
|
49
49
|
WORK_DIR,
|
|
50
50
|
cleanupAllProcesses,
|
|
51
|
-
|
|
52
|
-
clearInputHandler,
|
|
51
|
+
clearActiveSessionRuntime,
|
|
53
52
|
clearWorkspace,
|
|
53
|
+
createSessionRuntime,
|
|
54
54
|
createTempFile,
|
|
55
55
|
debugLog,
|
|
56
56
|
ensureDirExists,
|
|
57
57
|
flowLog,
|
|
58
58
|
generateId,
|
|
59
59
|
generatePrefixedId,
|
|
60
|
+
getActiveSessionRuntime,
|
|
60
61
|
getApiKey,
|
|
62
|
+
getApprovalMode,
|
|
61
63
|
getBaseUrl,
|
|
62
64
|
getErrorMessage,
|
|
63
65
|
getModel,
|
|
64
66
|
getProcessOutput,
|
|
67
|
+
getScopeMode,
|
|
65
68
|
getSearchApiKey,
|
|
66
69
|
getSearchApiUrl,
|
|
67
70
|
getThinkingBudget,
|
|
@@ -78,14 +81,13 @@ import {
|
|
|
78
81
|
runCommand,
|
|
79
82
|
saveState,
|
|
80
83
|
sendToProcess,
|
|
81
|
-
|
|
82
|
-
setInputHandler,
|
|
84
|
+
setActiveSessionRuntime,
|
|
83
85
|
setTorEnabled,
|
|
84
86
|
startBackgroundProcess,
|
|
85
87
|
stopBackgroundProcess,
|
|
86
88
|
validateRequiredConfig,
|
|
87
89
|
writeFileContent
|
|
88
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-SLDFXMHL.js";
|
|
89
91
|
import {
|
|
90
92
|
DETECTION_PATTERNS,
|
|
91
93
|
EXIT_CODES,
|
|
@@ -101,11 +103,10 @@ import {
|
|
|
101
103
|
getProcessEventLog,
|
|
102
104
|
getPromptBuilderConfig,
|
|
103
105
|
getPromptSources,
|
|
104
|
-
getUserInputQueueConfig,
|
|
105
106
|
llmNodeCooldownPolicy,
|
|
106
107
|
llmNodeOutputParsing,
|
|
107
108
|
llmNodeSystemPrompt
|
|
108
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-GHJPYI4S.js";
|
|
109
110
|
|
|
110
111
|
// src/platform/tui/main.tsx
|
|
111
112
|
import chalk5 from "chalk";
|
|
@@ -511,35 +512,35 @@ function prioritizeChains(chains) {
|
|
|
511
512
|
);
|
|
512
513
|
return unique.slice(0, GRAPH_LIMITS.MAX_CHAINS);
|
|
513
514
|
}
|
|
514
|
-
function dfsChains(nodeId,
|
|
515
|
+
function dfsChains(nodeId, path4, pathEdges, visited, ctx) {
|
|
515
516
|
const { nodes, edges, goalTypes, results } = ctx;
|
|
516
517
|
const node = nodes.get(nodeId);
|
|
517
|
-
if (!node || visited.has(nodeId) ||
|
|
518
|
+
if (!node || visited.has(nodeId) || path4.length >= GRAPH_LIMITS.MAX_CHAIN_DEPTH || node.status === NODE_STATUS.FAILED) {
|
|
518
519
|
return;
|
|
519
520
|
}
|
|
520
521
|
visited.add(nodeId);
|
|
521
|
-
|
|
522
|
-
if (isGoalReached(node, goalTypes,
|
|
523
|
-
results.push(buildChain(
|
|
522
|
+
path4.push(node);
|
|
523
|
+
if (isGoalReached(node, goalTypes, path4)) {
|
|
524
|
+
results.push(buildChain(path4, pathEdges, node));
|
|
524
525
|
}
|
|
525
526
|
const outEdges = edges.filter((e) => e.from === nodeId && e.status !== EDGE_STATUS.FAILED);
|
|
526
527
|
for (const edge of outEdges) {
|
|
527
|
-
dfsChains(edge.to,
|
|
528
|
+
dfsChains(edge.to, path4, [...pathEdges, edge], visited, ctx);
|
|
528
529
|
}
|
|
529
|
-
|
|
530
|
+
path4.pop();
|
|
530
531
|
visited.delete(nodeId);
|
|
531
532
|
}
|
|
532
|
-
function isGoalReached(node, goalTypes,
|
|
533
|
-
return goalTypes.includes(node.type) && node.status !== NODE_STATUS.SUCCEEDED &&
|
|
533
|
+
function isGoalReached(node, goalTypes, path4) {
|
|
534
|
+
return goalTypes.includes(node.type) && node.status !== NODE_STATUS.SUCCEEDED && path4.length > 1;
|
|
534
535
|
}
|
|
535
|
-
function buildChain(
|
|
536
|
+
function buildChain(path4, edges, targetNode) {
|
|
536
537
|
return {
|
|
537
|
-
steps: [...
|
|
538
|
+
steps: [...path4],
|
|
538
539
|
edges: [...edges],
|
|
539
|
-
description:
|
|
540
|
+
description: path4.map((n) => n.label).join(" \u2192 "),
|
|
540
541
|
probability: edges.reduce((acc, e) => acc * e.confidence, 1),
|
|
541
542
|
impact: estimateImpact(targetNode),
|
|
542
|
-
length:
|
|
543
|
+
length: path4.length
|
|
543
544
|
};
|
|
544
545
|
}
|
|
545
546
|
function estimateImpact(node) {
|
|
@@ -1001,8 +1002,8 @@ var AttackGraphStore = class {
|
|
|
1001
1002
|
* Record a failed path with IMP-1 cap.
|
|
1002
1003
|
* Keeps only the most recent MAX_FAILED_PATHS entries.
|
|
1003
1004
|
*/
|
|
1004
|
-
recordFailedPath(
|
|
1005
|
-
this.failedPaths.push(
|
|
1005
|
+
recordFailedPath(path4) {
|
|
1006
|
+
this.failedPaths.push(path4);
|
|
1006
1007
|
if (this.failedPaths.length > AGENT_LIMITS.MAX_FAILED_PATHS) {
|
|
1007
1008
|
this.failedPaths = this.failedPaths.slice(-AGENT_LIMITS.MAX_FAILED_PATHS);
|
|
1008
1009
|
}
|
|
@@ -1079,7 +1080,7 @@ var AttackGraph = class {
|
|
|
1079
1080
|
*/
|
|
1080
1081
|
markFailed(nodeId, reason) {
|
|
1081
1082
|
markNodeFailedInGraph(this.store.getNodesMap(), this.store.getEdgesList(), nodeId, reason, {
|
|
1082
|
-
onFailedPath: (
|
|
1083
|
+
onFailedPath: (path4) => this.store.recordFailedPath(path4)
|
|
1083
1084
|
});
|
|
1084
1085
|
}
|
|
1085
1086
|
/**
|
|
@@ -1093,7 +1094,7 @@ var AttackGraph = class {
|
|
|
1093
1094
|
*/
|
|
1094
1095
|
markEdgeFailed(fromId, toId, reason) {
|
|
1095
1096
|
markEdgeFailedInList(this.store.getEdgesList(), fromId, toId, reason, {
|
|
1096
|
-
onFailedPath: (
|
|
1097
|
+
onFailedPath: (path4) => this.store.recordFailedPath(path4)
|
|
1097
1098
|
});
|
|
1098
1099
|
}
|
|
1099
1100
|
// ─── Domain-Specific Registration ───────────────────────────
|
|
@@ -1233,44 +1234,83 @@ var EPISODIC_EVENT_TYPES = {
|
|
|
1233
1234
|
};
|
|
1234
1235
|
|
|
1235
1236
|
// src/shared/utils/agent-memory/fingerprint.ts
|
|
1237
|
+
var WORDLIST_FLAGS = /* @__PURE__ */ new Set(["-w", "-P", "-U", "-L", "--wordlist", "--password", "--passwords", "--username", "--usernames"]);
|
|
1238
|
+
var PORT_FLAGS = /* @__PURE__ */ new Set(["-p", "--port"]);
|
|
1239
|
+
var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["python", "python3", "bash", "sh", "zsh", "node", "ruby", "perl"]);
|
|
1240
|
+
function stripWrappingQuotes(value) {
|
|
1241
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1242
|
+
return value.slice(1, -1);
|
|
1243
|
+
}
|
|
1244
|
+
return value;
|
|
1245
|
+
}
|
|
1246
|
+
function tokenizeCommand(command) {
|
|
1247
|
+
const matches = command.match(/"[^"]*"|'[^']*'|\S+/g) ?? [];
|
|
1248
|
+
return matches.map(stripWrappingQuotes);
|
|
1249
|
+
}
|
|
1250
|
+
function parseOptionTokens(tokens) {
|
|
1251
|
+
const options = [];
|
|
1252
|
+
const positionals = [];
|
|
1253
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
1254
|
+
const token = tokens[i];
|
|
1255
|
+
if (token.startsWith("--")) {
|
|
1256
|
+
const eqIndex = token.indexOf("=");
|
|
1257
|
+
if (eqIndex !== -1) {
|
|
1258
|
+
options.push({ flag: token.slice(0, eqIndex), value: token.slice(eqIndex + 1) });
|
|
1259
|
+
continue;
|
|
1260
|
+
}
|
|
1261
|
+
const next = tokens[i + 1];
|
|
1262
|
+
if (next && !next.startsWith("-")) {
|
|
1263
|
+
options.push({ flag: token, value: next });
|
|
1264
|
+
i++;
|
|
1265
|
+
} else {
|
|
1266
|
+
options.push({ flag: token, value: "" });
|
|
1267
|
+
}
|
|
1268
|
+
continue;
|
|
1269
|
+
}
|
|
1270
|
+
if (token.startsWith("-") && token.length > 1) {
|
|
1271
|
+
const next = tokens[i + 1];
|
|
1272
|
+
const expectsValue = /^-[A-Za-z]$/.test(token) || /^-[a-z]{2,}$/.test(token);
|
|
1273
|
+
const canConsumeNext = expectsValue && next && !next.startsWith("-");
|
|
1274
|
+
if (canConsumeNext) {
|
|
1275
|
+
options.push({ flag: token, value: next });
|
|
1276
|
+
i++;
|
|
1277
|
+
} else {
|
|
1278
|
+
options.push({ flag: token, value: "" });
|
|
1279
|
+
}
|
|
1280
|
+
continue;
|
|
1281
|
+
}
|
|
1282
|
+
positionals.push(token);
|
|
1283
|
+
}
|
|
1284
|
+
return { options, positionals };
|
|
1285
|
+
}
|
|
1286
|
+
function findOptionValue(options, flags) {
|
|
1287
|
+
return options.find((option) => flags.has(option.flag))?.value || "";
|
|
1288
|
+
}
|
|
1289
|
+
function buildOptionSignature(options, positionals, effectiveTool) {
|
|
1290
|
+
const entries = options.filter((option) => !WORDLIST_FLAGS.has(option.flag) && !PORT_FLAGS.has(option.flag)).map((option) => option.value ? `${option.flag}=${option.value}` : option.flag);
|
|
1291
|
+
if (SCRIPT_RUNNERS.has(effectiveTool) && positionals.length > 0) {
|
|
1292
|
+
entries.push(`script=${positionals[0]}`);
|
|
1293
|
+
}
|
|
1294
|
+
return Array.from(new Set(entries)).sort().join(" ");
|
|
1295
|
+
}
|
|
1236
1296
|
function extractFingerprint(tool, command) {
|
|
1237
1297
|
const cmd = command || "";
|
|
1298
|
+
const tokens = tokenizeCommand(cmd);
|
|
1238
1299
|
let effectiveTool = tool.toLowerCase();
|
|
1239
1300
|
if (effectiveTool === "run_cmd" || effectiveTool === "run_background") {
|
|
1240
|
-
const firstWord =
|
|
1301
|
+
const firstWord = tokens[0];
|
|
1241
1302
|
if (firstWord && !firstWord.startsWith("-")) {
|
|
1242
1303
|
effectiveTool = firstWord.toLowerCase();
|
|
1243
1304
|
}
|
|
1244
1305
|
}
|
|
1306
|
+
const { options, positionals } = parseOptionTokens(tokens);
|
|
1245
1307
|
const targetMatch = cmd.match(
|
|
1246
1308
|
/(?::\/\/|@)([\w.\-]+(?::\d+)?)|\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d+)?\b/
|
|
1247
1309
|
);
|
|
1248
1310
|
const target = targetMatch?.[1] || targetMatch?.[2] || "";
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
}
|
|
1253
|
-
const wordlist = wordlistMatch?.[1] || "";
|
|
1254
|
-
const portMatch = cmd.match(/(?:-p\s+|--port(?:=|\s+))(\S+)/);
|
|
1255
|
-
const port = portMatch?.[1] || "";
|
|
1256
|
-
const flagPatterns = [
|
|
1257
|
-
/--level(?:=|\s+)(\S+)/i,
|
|
1258
|
-
// sqlmap
|
|
1259
|
-
/--risk(?:=|\s+)(\S+)/i,
|
|
1260
|
-
// sqlmap
|
|
1261
|
-
/-s([VSTCAUOPMX]+)/,
|
|
1262
|
-
// nmap scan type
|
|
1263
|
-
/--script(?:=|\s+)(\S+)/i,
|
|
1264
|
-
// nmap scripts
|
|
1265
|
-
/-[el]\s+(\S+)/i,
|
|
1266
|
-
// hydra login/password single
|
|
1267
|
-
/--method(?:=|\s+)(\S+)/i
|
|
1268
|
-
// HTTP method
|
|
1269
|
-
];
|
|
1270
|
-
const flags = flagPatterns.map((p) => {
|
|
1271
|
-
const m = cmd.match(p);
|
|
1272
|
-
return m?.[0]?.trim() || "";
|
|
1273
|
-
}).filter(Boolean).join(" ");
|
|
1311
|
+
const wordlist = findOptionValue(options, WORDLIST_FLAGS);
|
|
1312
|
+
const port = findOptionValue(options, PORT_FLAGS);
|
|
1313
|
+
const flags = buildOptionSignature(options, positionals, effectiveTool);
|
|
1274
1314
|
return { tool: effectiveTool, target, wordlist, flags, port };
|
|
1275
1315
|
}
|
|
1276
1316
|
function fingerprintsMatch(a, b) {
|
|
@@ -1978,10 +2018,25 @@ var DynamicTechniqueLibrary = class {
|
|
|
1978
2018
|
};
|
|
1979
2019
|
|
|
1980
2020
|
// src/engine/state/models/engagement.ts
|
|
2021
|
+
function safeList(values) {
|
|
2022
|
+
return Array.isArray(values) ? values.filter((value) => typeof value === "string") : [];
|
|
2023
|
+
}
|
|
2024
|
+
function normalizeScope(scope) {
|
|
2025
|
+
return {
|
|
2026
|
+
allowedCidrs: safeList(scope.allowedCidrs),
|
|
2027
|
+
allowedDomains: safeList(scope.allowedDomains),
|
|
2028
|
+
exclusions: safeList(scope.exclusions),
|
|
2029
|
+
isDOSAllowed: Boolean(scope.isDOSAllowed),
|
|
2030
|
+
isSocialAllowed: Boolean(scope.isSocialAllowed)
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
1981
2033
|
var EngagementState = class {
|
|
1982
2034
|
engagement = null;
|
|
1983
2035
|
set(engagement) {
|
|
1984
|
-
this.engagement =
|
|
2036
|
+
this.engagement = {
|
|
2037
|
+
...engagement,
|
|
2038
|
+
scope: normalizeScope(engagement.scope)
|
|
2039
|
+
};
|
|
1985
2040
|
}
|
|
1986
2041
|
get() {
|
|
1987
2042
|
return this.engagement;
|
|
@@ -1990,14 +2045,15 @@ var EngagementState = class {
|
|
|
1990
2045
|
return this.engagement?.scope || null;
|
|
1991
2046
|
}
|
|
1992
2047
|
setScope(scope, currentPhase) {
|
|
2048
|
+
const normalizedScope = normalizeScope(scope);
|
|
1993
2049
|
if (this.engagement) {
|
|
1994
|
-
this.engagement.scope =
|
|
2050
|
+
this.engagement.scope = normalizedScope;
|
|
1995
2051
|
} else {
|
|
1996
2052
|
this.engagement = {
|
|
1997
2053
|
id: generateId(AGENT_LIMITS.ID_RADIX, AGENT_LIMITS.ID_LENGTH),
|
|
1998
2054
|
name: DEFAULTS.ENGAGEMENT_NAME,
|
|
1999
2055
|
client: DEFAULTS.ENGAGEMENT_CLIENT,
|
|
2000
|
-
scope,
|
|
2056
|
+
scope: normalizedScope,
|
|
2001
2057
|
phase: currentPhase,
|
|
2002
2058
|
startedAt: Date.now()
|
|
2003
2059
|
};
|
|
@@ -2302,9 +2358,9 @@ var DIRECTIVES = {
|
|
|
2302
2358
|
].join("\n"),
|
|
2303
2359
|
SPRINT: (ctx) => [
|
|
2304
2360
|
`\u26A1 SPRINT MODE [${ctx.pctStr} elapsed, ${ctx.remainStr} of ${ctx.totalStr} remaining]:`,
|
|
2305
|
-
"-
|
|
2306
|
-
"-
|
|
2307
|
-
"- Run
|
|
2361
|
+
"- Start with the fastest broad discovery method available, then deepen only on confirmed surfaces",
|
|
2362
|
+
"- If host discovery looks filtered, prefer reconnaissance that does not depend on ICMP assumptions",
|
|
2363
|
+
"- Run independent discovery tasks in parallel (network, web, OSINT, version intel)",
|
|
2308
2364
|
"- Try default/weak credentials on every discovered service IMMEDIATELY",
|
|
2309
2365
|
"- Check for exposed files (.env, .git, backup.sql, phpinfo)",
|
|
2310
2366
|
"- Anonymous access: FTP, SMB null session, Redis no auth, MongoDB",
|
|
@@ -2527,7 +2583,7 @@ var SharedState = class {
|
|
|
2527
2583
|
/**
|
|
2528
2584
|
* Last turn's triage memo (Triager ⑧).
|
|
2529
2585
|
* Structured priority classification of tool results.
|
|
2530
|
-
* WHY: Reflector and
|
|
2586
|
+
* WHY: Reflector and MemorySynth read this for richer delta analysis.
|
|
2531
2587
|
* Injected into prompt as <triage-memo> for the main LLM.
|
|
2532
2588
|
*/
|
|
2533
2589
|
lastTriageMemo = "";
|
|
@@ -2822,8 +2878,9 @@ var FILE_EXTENSIONS_TO_SKIP = /* @__PURE__ */ new Set([
|
|
|
2822
2878
|
"dec"
|
|
2823
2879
|
]);
|
|
2824
2880
|
var ScopeGuard = class {
|
|
2825
|
-
constructor(state) {
|
|
2881
|
+
constructor(state, mode = getScopeMode()) {
|
|
2826
2882
|
this.state = state;
|
|
2883
|
+
this.mode = mode;
|
|
2827
2884
|
}
|
|
2828
2885
|
/**
|
|
2829
2886
|
* AI-Native: always allow.
|
|
@@ -2831,8 +2888,28 @@ var ScopeGuard = class {
|
|
|
2831
2888
|
* The agent should attempt everything; humans and infrastructure judge the results.
|
|
2832
2889
|
* isTargetInScope() exists for advisory reporting — not for blocking.
|
|
2833
2890
|
*/
|
|
2834
|
-
check(
|
|
2835
|
-
|
|
2891
|
+
check(toolCall) {
|
|
2892
|
+
if (this.mode === "advisory") {
|
|
2893
|
+
return { isAllowed: true };
|
|
2894
|
+
}
|
|
2895
|
+
const scope = this.state.getScope();
|
|
2896
|
+
const serializedInput = JSON.stringify(toolCall.input);
|
|
2897
|
+
const targets = Array.from(this.extractTargets(serializedInput));
|
|
2898
|
+
if (targets.length === 0) return { isAllowed: true };
|
|
2899
|
+
if (!scope) {
|
|
2900
|
+
return {
|
|
2901
|
+
isAllowed: false,
|
|
2902
|
+
reason: "Scope enforcement is enabled but no scope is configured.",
|
|
2903
|
+
violations: targets
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
const violations = targets.filter((target) => !this.isTargetInScope(target));
|
|
2907
|
+
if (violations.length === 0) return { isAllowed: true };
|
|
2908
|
+
return {
|
|
2909
|
+
isAllowed: false,
|
|
2910
|
+
reason: `Out-of-scope target(s): ${violations.join(", ")}`,
|
|
2911
|
+
violations
|
|
2912
|
+
};
|
|
2836
2913
|
}
|
|
2837
2914
|
/**
|
|
2838
2915
|
* Advisory check: is a specific target in scope?
|
|
@@ -2841,13 +2918,16 @@ var ScopeGuard = class {
|
|
|
2841
2918
|
isTargetInScope(target) {
|
|
2842
2919
|
const scope = this.state.getScope();
|
|
2843
2920
|
if (!scope) return false;
|
|
2844
|
-
|
|
2921
|
+
const exclusions = Array.isArray(scope.exclusions) ? scope.exclusions : [];
|
|
2922
|
+
const allowedDomains = Array.isArray(scope.allowedDomains) ? scope.allowedDomains : [];
|
|
2923
|
+
const allowedCidrs = Array.isArray(scope.allowedCidrs) ? scope.allowedCidrs : [];
|
|
2924
|
+
if (exclusions.some((e) => this.matchesDomain(target, e))) {
|
|
2845
2925
|
return false;
|
|
2846
2926
|
}
|
|
2847
|
-
if (
|
|
2927
|
+
if (allowedDomains.some((d) => this.matchesDomain(target, d))) {
|
|
2848
2928
|
return true;
|
|
2849
2929
|
}
|
|
2850
|
-
if (
|
|
2930
|
+
if (allowedCidrs.some((c) => this.matchesCidr(target, c))) {
|
|
2851
2931
|
return true;
|
|
2852
2932
|
}
|
|
2853
2933
|
return false;
|
|
@@ -2916,7 +2996,7 @@ var ScopeGuard = class {
|
|
|
2916
2996
|
const lower = match.toLowerCase();
|
|
2917
2997
|
const ext = lower.split(".").pop() || "";
|
|
2918
2998
|
if (FILE_EXTENSIONS_TO_SKIP.has(ext)) continue;
|
|
2919
|
-
if (/^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_]*$/i.test(match)) continue;
|
|
2999
|
+
if (/^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_]*$/i.test(match) && ext.length > 3) continue;
|
|
2920
3000
|
targets.add(lower);
|
|
2921
3001
|
}
|
|
2922
3002
|
return targets;
|
|
@@ -2925,8 +3005,9 @@ var ScopeGuard = class {
|
|
|
2925
3005
|
|
|
2926
3006
|
// src/engine/approval.ts
|
|
2927
3007
|
var ApprovalGate = class {
|
|
2928
|
-
constructor(shouldAutoApprove = false) {
|
|
3008
|
+
constructor(shouldAutoApprove = false, mode = getApprovalMode()) {
|
|
2929
3009
|
this.shouldAutoApprove = shouldAutoApprove;
|
|
3010
|
+
this.mode = mode;
|
|
2930
3011
|
}
|
|
2931
3012
|
/**
|
|
2932
3013
|
* Set auto-approve mode
|
|
@@ -2945,7 +3026,13 @@ var ApprovalGate = class {
|
|
|
2945
3026
|
* The agent must have unrestricted freedom to exploit targets.
|
|
2946
3027
|
* Category/level system retained for audit trail only.
|
|
2947
3028
|
*/
|
|
2948
|
-
async request(
|
|
3029
|
+
async request(toolCall) {
|
|
3030
|
+
if (this.mode === "require_auto_approve" && !this.shouldAutoApprove) {
|
|
3031
|
+
return {
|
|
3032
|
+
isApproved: false,
|
|
3033
|
+
reason: `Approval required for ${toolCall.name} while PENTEST_APPROVAL_MODE=require_auto_approve.`
|
|
3034
|
+
};
|
|
3035
|
+
}
|
|
2949
3036
|
return { isApproved: true };
|
|
2950
3037
|
}
|
|
2951
3038
|
};
|
|
@@ -3284,22 +3371,16 @@ var systemTools = [
|
|
|
3284
3371
|
];
|
|
3285
3372
|
|
|
3286
3373
|
// src/engine/tools/agents.ts
|
|
3287
|
-
var globalCredentialHandler = null;
|
|
3288
|
-
function setCredentialHandler(handler) {
|
|
3289
|
-
globalCredentialHandler = handler;
|
|
3290
|
-
}
|
|
3291
|
-
function clearCredentialHandler() {
|
|
3292
|
-
globalCredentialHandler = null;
|
|
3293
|
-
}
|
|
3294
3374
|
async function requestCredential(request) {
|
|
3295
|
-
|
|
3375
|
+
const credentialHandler = getActiveSessionRuntime()?.getCredentialHandler();
|
|
3376
|
+
if (!credentialHandler) {
|
|
3296
3377
|
return {
|
|
3297
3378
|
success: false,
|
|
3298
3379
|
output: `No credential handler available. Requested: ${request.type} - ${request.prompt}`
|
|
3299
3380
|
};
|
|
3300
3381
|
}
|
|
3301
3382
|
try {
|
|
3302
|
-
const value = await
|
|
3383
|
+
const value = await credentialHandler(request);
|
|
3303
3384
|
if (value === null) {
|
|
3304
3385
|
if (request.isOptional) {
|
|
3305
3386
|
return {
|
|
@@ -6762,7 +6843,7 @@ import { existsSync as existsSync3, readdirSync, rmSync } from "fs";
|
|
|
6762
6843
|
import { join as join6 } from "path";
|
|
6763
6844
|
function parseTurnNumbers(turnsDir) {
|
|
6764
6845
|
if (!existsSync3(turnsDir)) return [];
|
|
6765
|
-
return readdirSync(turnsDir).filter((e) => /^\d
|
|
6846
|
+
return readdirSync(turnsDir).filter((e) => /^\d+-memory\.md$/.test(e)).map((e) => Number(e.replace("-memory.md", "")));
|
|
6766
6847
|
}
|
|
6767
6848
|
function rotateTurnRecords() {
|
|
6768
6849
|
try {
|
|
@@ -6773,7 +6854,7 @@ function rotateTurnRecords() {
|
|
|
6773
6854
|
const toDel = turns.slice(0, turns.length - MEMORY_LIMITS.MAX_TURN_ENTRIES);
|
|
6774
6855
|
for (const n of toDel) {
|
|
6775
6856
|
try {
|
|
6776
|
-
rmSync(join6(turnsDir, `${n}.md`), { force: true });
|
|
6857
|
+
rmSync(join6(turnsDir, `${n}-memory.md`), { force: true });
|
|
6777
6858
|
} catch {
|
|
6778
6859
|
}
|
|
6779
6860
|
}
|
|
@@ -6832,6 +6913,40 @@ function getRecentTurnContents(count) {
|
|
|
6832
6913
|
|
|
6833
6914
|
// src/shared/utils/journal/summary.ts
|
|
6834
6915
|
import { writeFileSync as writeFileSync4 } from "fs";
|
|
6916
|
+
|
|
6917
|
+
// src/shared/utils/journal/memory-file.ts
|
|
6918
|
+
function yamlList(values) {
|
|
6919
|
+
if (values.length === 0) return " - none";
|
|
6920
|
+
return values.map((value) => ` - ${value}`).join("\n");
|
|
6921
|
+
}
|
|
6922
|
+
function buildTurnMemoryDocument(input) {
|
|
6923
|
+
const body = input.memoryBody.trim();
|
|
6924
|
+
return [
|
|
6925
|
+
"---",
|
|
6926
|
+
`turn: ${input.turn}`,
|
|
6927
|
+
`phase: ${input.phase}`,
|
|
6928
|
+
"file_kind: turn_memory",
|
|
6929
|
+
`written_by: ${input.writtenBy}`,
|
|
6930
|
+
"input_sources:",
|
|
6931
|
+
yamlList(input.inputSources),
|
|
6932
|
+
"notes_included:",
|
|
6933
|
+
yamlList(input.notesIncluded),
|
|
6934
|
+
`generated_at: ${input.generatedAt}`,
|
|
6935
|
+
"---",
|
|
6936
|
+
"",
|
|
6937
|
+
`# Turn Memory ${input.turn}`,
|
|
6938
|
+
"",
|
|
6939
|
+
"## Provenance",
|
|
6940
|
+
`written_by: ${input.writtenBy}`,
|
|
6941
|
+
`input_sources: ${input.inputSources.join(", ") || "none"}`,
|
|
6942
|
+
`notes_included: ${input.notesIncluded.join(", ") || "none"}`,
|
|
6943
|
+
"",
|
|
6944
|
+
"## Memory",
|
|
6945
|
+
body
|
|
6946
|
+
].join("\n");
|
|
6947
|
+
}
|
|
6948
|
+
|
|
6949
|
+
// src/shared/utils/journal/summary.ts
|
|
6835
6950
|
function regenerateJournalSummary() {
|
|
6836
6951
|
try {
|
|
6837
6952
|
const contents = getRecentTurnContents(MEMORY_LIMITS.MAX_TURN_ENTRIES);
|
|
@@ -6840,10 +6955,19 @@ function regenerateJournalSummary() {
|
|
|
6840
6955
|
if (currentTurn < 1) return;
|
|
6841
6956
|
ensureDirExists(WORKSPACE.TURNS);
|
|
6842
6957
|
const summary = contents.slice(-5).join("\n\n---\n\n");
|
|
6843
|
-
|
|
6958
|
+
const memoryFile = buildTurnMemoryDocument({
|
|
6959
|
+
turn: currentTurn,
|
|
6960
|
+
phase: "unknown",
|
|
6961
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6962
|
+
writtenBy: "fallback_concat",
|
|
6963
|
+
inputSources: ["recent_turn_memory_files"],
|
|
6964
|
+
notesIncluded: ["fallback_concat"],
|
|
6965
|
+
memoryBody: summary
|
|
6966
|
+
});
|
|
6967
|
+
writeFileSync4(WORKSPACE.turnPath(currentTurn), memoryFile, "utf-8");
|
|
6844
6968
|
debugLog("general", "Fallback journal summary written", {
|
|
6845
6969
|
turns: contents.length,
|
|
6846
|
-
target: `turns/${currentTurn}.md`
|
|
6970
|
+
target: `turns/${currentTurn}-memory.md`
|
|
6847
6971
|
});
|
|
6848
6972
|
} catch (err) {
|
|
6849
6973
|
debugLog("general", "Failed to regenerate journal summary", { error: String(err) });
|
|
@@ -6895,9 +7019,18 @@ var STATUS_ICONS2 = {
|
|
|
6895
7019
|
};
|
|
6896
7020
|
|
|
6897
7021
|
// src/shared/utils/journal/formatters/record.ts
|
|
7022
|
+
function safeList2(values) {
|
|
7023
|
+
return Array.isArray(values) ? values.filter((value) => typeof value === "string") : [];
|
|
7024
|
+
}
|
|
6898
7025
|
function formatTurnRecord(input) {
|
|
6899
7026
|
const { turn, timestamp, phase, tools, memo: memo13, reflection } = input;
|
|
6900
7027
|
const time = timestamp.slice(0, 19).replace("T", " ");
|
|
7028
|
+
const keyFindings = safeList2(memo13.keyFindings);
|
|
7029
|
+
const credentials = safeList2(memo13.credentials);
|
|
7030
|
+
const attackVectors = safeList2(memo13.attackVectors);
|
|
7031
|
+
const failures = safeList2(memo13.failures);
|
|
7032
|
+
const suspicions = safeList2(memo13.suspicions);
|
|
7033
|
+
const nextSteps = safeList2(memo13.nextSteps);
|
|
6901
7034
|
const sections = [];
|
|
6902
7035
|
sections.push(`# Turn ${turn} | ${time} | Phase: ${phase}`);
|
|
6903
7036
|
sections.push("");
|
|
@@ -6913,25 +7046,25 @@ function formatTurnRecord(input) {
|
|
|
6913
7046
|
}
|
|
6914
7047
|
sections.push("");
|
|
6915
7048
|
sections.push(`## ${TURN_SECTIONS.KEY_INSIGHTS}`);
|
|
6916
|
-
if (
|
|
6917
|
-
for (const f of
|
|
7049
|
+
if (keyFindings.length > 0) {
|
|
7050
|
+
for (const f of keyFindings) sections.push(`- ${INSIGHT_TAGS.DISCOVERED}: ${f}`);
|
|
6918
7051
|
}
|
|
6919
|
-
if (
|
|
6920
|
-
for (const c of
|
|
7052
|
+
if (credentials.length > 0) {
|
|
7053
|
+
for (const c of credentials) sections.push(`- ${INSIGHT_TAGS.CREDENTIAL}: ${c}`);
|
|
6921
7054
|
}
|
|
6922
|
-
if (
|
|
6923
|
-
for (const v of
|
|
7055
|
+
if (attackVectors.length > 0) {
|
|
7056
|
+
for (const v of attackVectors) sections.push(`- ${INSIGHT_TAGS.CONFIRMED}: ${v}`);
|
|
6924
7057
|
}
|
|
6925
|
-
if (
|
|
6926
|
-
for (const f of
|
|
7058
|
+
if (failures.length > 0) {
|
|
7059
|
+
for (const f of failures) sections.push(`- ${INSIGHT_TAGS.DEAD_END}: ${f}`);
|
|
6927
7060
|
}
|
|
6928
|
-
if (
|
|
6929
|
-
for (const s of
|
|
7061
|
+
if (suspicions.length > 0) {
|
|
7062
|
+
for (const s of suspicions) sections.push(`- ${INSIGHT_TAGS.SUSPICIOUS}: ${s}`);
|
|
6930
7063
|
}
|
|
6931
|
-
if (
|
|
6932
|
-
for (const n of
|
|
7064
|
+
if (nextSteps.length > 0) {
|
|
7065
|
+
for (const n of nextSteps) sections.push(`- ${INSIGHT_TAGS.NEXT}: ${n}`);
|
|
6933
7066
|
}
|
|
6934
|
-
if (
|
|
7067
|
+
if (keyFindings.length === 0 && failures.length === 0 && credentials.length === 0) {
|
|
6935
7068
|
sections.push(`- ${TURN_EMPTY_MESSAGES.NO_INSIGHTS}`);
|
|
6936
7069
|
}
|
|
6937
7070
|
sections.push("");
|
|
@@ -6942,6 +7075,9 @@ function formatTurnRecord(input) {
|
|
|
6942
7075
|
}
|
|
6943
7076
|
|
|
6944
7077
|
// src/shared/utils/journal/formatters/reflection.ts
|
|
7078
|
+
function safeList3(values) {
|
|
7079
|
+
return Array.isArray(values) ? values.filter((value) => typeof value === "string") : [];
|
|
7080
|
+
}
|
|
6945
7081
|
function formatReflectionInput(input) {
|
|
6946
7082
|
const { tools, memo: memo13, phase, triageMemo } = input;
|
|
6947
7083
|
const parts = [
|
|
@@ -6962,10 +7098,14 @@ function formatReflectionInput(input) {
|
|
|
6962
7098
|
parts.push("");
|
|
6963
7099
|
parts.push("Analyst \uCD94\uCD9C \uBA54\uBAA8:");
|
|
6964
7100
|
if (memo13) {
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
7101
|
+
const keyFindings = safeList3(memo13.keyFindings);
|
|
7102
|
+
const credentials = safeList3(memo13.credentials);
|
|
7103
|
+
const failures = safeList3(memo13.failures);
|
|
7104
|
+
const suspicions = safeList3(memo13.suspicions);
|
|
7105
|
+
if (keyFindings.length > 0) parts.push(` \uBC1C\uACAC: ${keyFindings.join(", ")}`);
|
|
7106
|
+
if (credentials.length > 0) parts.push(` \uD06C\uB808\uB374\uC15C: ${credentials.join(", ")}`);
|
|
7107
|
+
if (failures.length > 0) parts.push(` \uC2E4\uD328: ${failures.join(", ")}`);
|
|
7108
|
+
if (suspicions.length > 0) parts.push(` \uC758\uC2EC: ${suspicions.join(", ")}`);
|
|
6969
7109
|
parts.push(` \uACF5\uACA9 \uAC00\uCE58: ${memo13.attackValue}`);
|
|
6970
7110
|
} else {
|
|
6971
7111
|
parts.push(" (\uBD84\uC11D \uACB0\uACFC \uC5C6\uC74C)");
|
|
@@ -6986,7 +7126,6 @@ var Reflector = class extends AuxiliaryLLMBase {
|
|
|
6986
7126
|
formatInput(input) {
|
|
6987
7127
|
return formatReflectionInput({
|
|
6988
7128
|
tools: input.tools,
|
|
6989
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6990
7129
|
memo: input.memo,
|
|
6991
7130
|
phase: input.phase,
|
|
6992
7131
|
triageMemo: input.triageMemo
|
|
@@ -7003,14 +7142,14 @@ function createReflector(llm) {
|
|
|
7003
7142
|
return new Reflector(llm);
|
|
7004
7143
|
}
|
|
7005
7144
|
|
|
7006
|
-
// src/engine/auxiliary-llm/
|
|
7007
|
-
var
|
|
7145
|
+
// src/engine/auxiliary-llm/memory-synth.ts
|
|
7146
|
+
var MemorySynth = class extends AuxiliaryLLMBase {
|
|
7008
7147
|
constructor(llm) {
|
|
7009
|
-
super(llm, { systemPrompt: llmNodeSystemPrompt("
|
|
7148
|
+
super(llm, { systemPrompt: llmNodeSystemPrompt("memory_synth"), logErrors: true });
|
|
7010
7149
|
}
|
|
7011
7150
|
formatInput(input) {
|
|
7012
7151
|
if (input.existingSummary) {
|
|
7013
|
-
return `Previous
|
|
7152
|
+
return `Previous memory:
|
|
7014
7153
|
${input.existingSummary}
|
|
7015
7154
|
|
|
7016
7155
|
Current turn:
|
|
@@ -7026,8 +7165,8 @@ ${input.turnData}`;
|
|
|
7026
7165
|
return { summary: "", success: false };
|
|
7027
7166
|
}
|
|
7028
7167
|
};
|
|
7029
|
-
function
|
|
7030
|
-
return new
|
|
7168
|
+
function createMemorySynth(llm) {
|
|
7169
|
+
return new MemorySynth(llm);
|
|
7031
7170
|
}
|
|
7032
7171
|
|
|
7033
7172
|
// src/engine/auxiliary-llm/playbook-synthesizer.ts
|
|
@@ -7142,6 +7281,45 @@ function createTriager(llm) {
|
|
|
7142
7281
|
return new Triager(llm);
|
|
7143
7282
|
}
|
|
7144
7283
|
|
|
7284
|
+
// src/shared/utils/policy/document.ts
|
|
7285
|
+
import fs from "fs";
|
|
7286
|
+
import path from "path";
|
|
7287
|
+
var DEFAULT_POLICY_DOCUMENT = `# Policy Memory
|
|
7288
|
+
|
|
7289
|
+
No persistent user policy has been recorded yet.
|
|
7290
|
+
Store only durable constraints, sensitive handling rules, and reusable engagement guidance here.
|
|
7291
|
+
`;
|
|
7292
|
+
function getPolicyDocumentPath() {
|
|
7293
|
+
return WORKSPACE.POLICY;
|
|
7294
|
+
}
|
|
7295
|
+
function ensurePolicyDocument() {
|
|
7296
|
+
const filePath = getPolicyDocumentPath();
|
|
7297
|
+
const dirPath = path.dirname(filePath);
|
|
7298
|
+
if (!fs.existsSync(dirPath)) {
|
|
7299
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
7300
|
+
}
|
|
7301
|
+
if (!fs.existsSync(filePath)) {
|
|
7302
|
+
fs.writeFileSync(filePath, DEFAULT_POLICY_DOCUMENT, "utf-8");
|
|
7303
|
+
}
|
|
7304
|
+
return filePath;
|
|
7305
|
+
}
|
|
7306
|
+
function readPolicyDocument() {
|
|
7307
|
+
try {
|
|
7308
|
+
ensurePolicyDocument();
|
|
7309
|
+
return fs.readFileSync(getPolicyDocumentPath(), "utf-8").trim();
|
|
7310
|
+
} catch {
|
|
7311
|
+
return "";
|
|
7312
|
+
}
|
|
7313
|
+
}
|
|
7314
|
+
function writePolicyDocument(content) {
|
|
7315
|
+
ensurePolicyDocument();
|
|
7316
|
+
fs.writeFileSync(
|
|
7317
|
+
getPolicyDocumentPath(),
|
|
7318
|
+
content.trim() || DEFAULT_POLICY_DOCUMENT,
|
|
7319
|
+
"utf-8"
|
|
7320
|
+
);
|
|
7321
|
+
}
|
|
7322
|
+
|
|
7145
7323
|
// src/engine/auxiliary-llm/strategist.ts
|
|
7146
7324
|
var Strategist = class extends AuxiliaryLLMBase {
|
|
7147
7325
|
lastDirective = null;
|
|
@@ -7167,6 +7345,8 @@ var Strategist = class extends AuxiliaryLLMBase {
|
|
|
7167
7345
|
if (journalSummary) sections.push("", "## Session Journal (past turns summary)", journalSummary);
|
|
7168
7346
|
} catch {
|
|
7169
7347
|
}
|
|
7348
|
+
const policyDocument = readPolicyDocument();
|
|
7349
|
+
if (policyDocument) sections.push("", "## Policy Memory", policyDocument);
|
|
7170
7350
|
const graph = state.attackGraph.toPrompt();
|
|
7171
7351
|
if (graph) sections.push("", "## Attack Graph", graph);
|
|
7172
7352
|
const timeline = state.episodicMemory.toPrompt();
|
|
@@ -7300,6 +7480,74 @@ function createStrategist(llm) {
|
|
|
7300
7480
|
return new Strategist(llm);
|
|
7301
7481
|
}
|
|
7302
7482
|
|
|
7483
|
+
// src/engine/auxiliary-llm/input-processor.ts
|
|
7484
|
+
function extractTag(content, tag) {
|
|
7485
|
+
const match = content.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "i"));
|
|
7486
|
+
return match?.[1]?.trim() ?? "";
|
|
7487
|
+
}
|
|
7488
|
+
function parseBoolean(value) {
|
|
7489
|
+
return value.trim().toLowerCase() === "true";
|
|
7490
|
+
}
|
|
7491
|
+
var InputProcessor = class extends AuxiliaryLLMBase {
|
|
7492
|
+
constructor(llm) {
|
|
7493
|
+
super(llm, {
|
|
7494
|
+
systemPrompt: llmNodeSystemPrompt("input_processor"),
|
|
7495
|
+
logErrors: true
|
|
7496
|
+
});
|
|
7497
|
+
}
|
|
7498
|
+
formatInput(input) {
|
|
7499
|
+
return [
|
|
7500
|
+
"<input-processor-context>",
|
|
7501
|
+
`<has-active-engagement>${String(input.hasActiveEngagement)}</has-active-engagement>`,
|
|
7502
|
+
`<current-objective>${input.currentObjective || "none"}</current-objective>`,
|
|
7503
|
+
"<existing-policy>",
|
|
7504
|
+
input.existingPolicy || "No existing policy document.",
|
|
7505
|
+
"</existing-policy>",
|
|
7506
|
+
"<raw-user-input>",
|
|
7507
|
+
input.rawInput,
|
|
7508
|
+
"</raw-user-input>",
|
|
7509
|
+
"</input-processor-context>"
|
|
7510
|
+
].join("\n");
|
|
7511
|
+
}
|
|
7512
|
+
parseOutput(response) {
|
|
7513
|
+
const shouldForwardToMain = parseBoolean(extractTag(response, "should_forward_to_main"));
|
|
7514
|
+
const shouldWritePolicy = parseBoolean(extractTag(response, "should_write_policy"));
|
|
7515
|
+
const forwardedInput = extractTag(response, "forwarded_input");
|
|
7516
|
+
const directResponse = extractTag(response, "direct_response");
|
|
7517
|
+
const policyDocument = extractTag(response, "policy_document_markdown");
|
|
7518
|
+
const policyUpdateSummary = extractTag(response, "policy_update_summary");
|
|
7519
|
+
const insightSummary = extractTag(response, "insight_summary");
|
|
7520
|
+
return {
|
|
7521
|
+
shouldForwardToMain,
|
|
7522
|
+
forwardedInput,
|
|
7523
|
+
directResponse,
|
|
7524
|
+
shouldWritePolicy,
|
|
7525
|
+
policyDocument,
|
|
7526
|
+
policyUpdateSummary,
|
|
7527
|
+
insightSummary,
|
|
7528
|
+
success: true
|
|
7529
|
+
};
|
|
7530
|
+
}
|
|
7531
|
+
createFailureOutput(_reason) {
|
|
7532
|
+
return {
|
|
7533
|
+
shouldForwardToMain: true,
|
|
7534
|
+
forwardedInput: "",
|
|
7535
|
+
directResponse: "",
|
|
7536
|
+
shouldWritePolicy: false,
|
|
7537
|
+
policyDocument: "",
|
|
7538
|
+
policyUpdateSummary: "",
|
|
7539
|
+
insightSummary: "",
|
|
7540
|
+
success: false
|
|
7541
|
+
};
|
|
7542
|
+
}
|
|
7543
|
+
handleEmptyResponse() {
|
|
7544
|
+
return this.createFailureOutput("Empty response from LLM");
|
|
7545
|
+
}
|
|
7546
|
+
};
|
|
7547
|
+
function createInputProcessor(llm) {
|
|
7548
|
+
return new InputProcessor(llm);
|
|
7549
|
+
}
|
|
7550
|
+
|
|
7303
7551
|
// src/domains/engagement/mission.ts
|
|
7304
7552
|
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
7305
7553
|
import { join as join7 } from "path";
|
|
@@ -9769,8 +10017,8 @@ Install: apt-get install binwalk` };
|
|
|
9769
10017
|
if (tryPassword(String(password))) {
|
|
9770
10018
|
results.push(`Extracted with password: "${password}"`);
|
|
9771
10019
|
try {
|
|
9772
|
-
const { readFileSync:
|
|
9773
|
-
results.push(`Content: ${
|
|
10020
|
+
const { readFileSync: readFileSync6 } = await import("fs");
|
|
10021
|
+
results.push(`Content: ${readFileSync6(outFile, "utf8").slice(0, 1e3)}`);
|
|
9774
10022
|
} catch {
|
|
9775
10023
|
results.push(`Saved to: ${outFile}`);
|
|
9776
10024
|
}
|
|
@@ -9785,8 +10033,8 @@ Install: apt-get install binwalk` };
|
|
|
9785
10033
|
results.push(`Extracted with password: "${pwd}"`);
|
|
9786
10034
|
found = true;
|
|
9787
10035
|
try {
|
|
9788
|
-
const { readFileSync:
|
|
9789
|
-
results.push(`Content: ${
|
|
10036
|
+
const { readFileSync: readFileSync6 } = await import("fs");
|
|
10037
|
+
results.push(`Content: ${readFileSync6(outFile, "utf8").slice(0, 1e3)}`);
|
|
9790
10038
|
} catch {
|
|
9791
10039
|
results.push(`Saved to: ${outFile}`);
|
|
9792
10040
|
}
|
|
@@ -10460,8 +10708,8 @@ function extractFuzzStructured(output) {
|
|
|
10460
10708
|
for (const pattern of pathPatterns) {
|
|
10461
10709
|
let match;
|
|
10462
10710
|
while ((match = pattern.exec(output)) !== null) {
|
|
10463
|
-
const
|
|
10464
|
-
const cleanPath =
|
|
10711
|
+
const path4 = match[1] || match[0];
|
|
10712
|
+
const cleanPath = path4.replace(/\s.*$/, "").trim();
|
|
10465
10713
|
if (cleanPath.startsWith("/") && !paths.includes(cleanPath)) {
|
|
10466
10714
|
paths.push(cleanPath);
|
|
10467
10715
|
}
|
|
@@ -10696,6 +10944,19 @@ function autoExtractStructured(toolName, output) {
|
|
|
10696
10944
|
|
|
10697
10945
|
// src/engine/tool-registry/pipeline.ts
|
|
10698
10946
|
var PRIVATE_IP_RE = /^(?:10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|127\.|0\.)/;
|
|
10947
|
+
var RECON_TRIGGER_TOOLS = /* @__PURE__ */ new Set([
|
|
10948
|
+
TOOL_NAMES.RUN_CMD,
|
|
10949
|
+
TOOL_NAMES.BROWSE_URL,
|
|
10950
|
+
TOOL_NAMES.PARSE_NMAP,
|
|
10951
|
+
TOOL_NAMES.WHOIS_LOOKUP,
|
|
10952
|
+
TOOL_NAMES.DNS_RECON,
|
|
10953
|
+
TOOL_NAMES.SUBDOMAIN_ENUM,
|
|
10954
|
+
TOOL_NAMES.HARVESTER,
|
|
10955
|
+
TOOL_NAMES.BINWALK_ANALYZE,
|
|
10956
|
+
TOOL_NAMES.EXIF_DATA,
|
|
10957
|
+
TOOL_NAMES.CHECKSEC,
|
|
10958
|
+
TOOL_NAMES.FILE_INFO
|
|
10959
|
+
]);
|
|
10699
10960
|
function handleOSINTIPs(state, ips, sourceTool) {
|
|
10700
10961
|
const publicIPs = ips.filter((ip) => !PRIVATE_IP_RE.test(ip)).slice(0, 10);
|
|
10701
10962
|
const registered = [];
|
|
@@ -10707,81 +10968,123 @@ function handleOSINTIPs(state, ips, sourceTool) {
|
|
|
10707
10968
|
}
|
|
10708
10969
|
}
|
|
10709
10970
|
if (registered.length > 0) {
|
|
10710
|
-
state.episodicMemory.record(
|
|
10971
|
+
state.episodicMemory.record(
|
|
10972
|
+
"tool_success",
|
|
10973
|
+
`OSINT auto-registered ${registered.length} new target(s): ${registered.slice(0, 3).join(", ")}`
|
|
10974
|
+
);
|
|
10711
10975
|
}
|
|
10712
10976
|
return `
|
|
10713
10977
|
[AUTO-EXTRACTED] ${publicIPs.length} IP(s) discovered: ${publicIPs.slice(0, 5).join(", ")}`;
|
|
10714
10978
|
}
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10979
|
+
function buildCommand(toolCall) {
|
|
10980
|
+
return String(
|
|
10981
|
+
toolCall.input.command || toolCall.input.url || toolCall.input.query || JSON.stringify(toolCall.input)
|
|
10982
|
+
);
|
|
10983
|
+
}
|
|
10984
|
+
var recordWorkingMemoryStep = {
|
|
10985
|
+
name: "working_memory_update",
|
|
10986
|
+
run(ctx) {
|
|
10987
|
+
if (ctx.result.success) {
|
|
10988
|
+
ctx.state.workingMemory.recordSuccess(ctx.toolCall.name, ctx.command, ctx.result.output || "");
|
|
10989
|
+
return;
|
|
10990
|
+
}
|
|
10991
|
+
ctx.state.workingMemory.recordFailure(
|
|
10992
|
+
ctx.toolCall.name,
|
|
10993
|
+
ctx.command,
|
|
10994
|
+
ctx.result.error || "Unknown error"
|
|
10995
|
+
);
|
|
10996
|
+
ctx.state.dynamicTechniques.recordFailure(ctx.command);
|
|
10997
|
+
}
|
|
10998
|
+
};
|
|
10999
|
+
var extractStructuredOutputStep = {
|
|
11000
|
+
name: "structured_extraction",
|
|
11001
|
+
run(ctx) {
|
|
11002
|
+
if (!ctx.result.success || !ctx.result.output) return;
|
|
11003
|
+
ctx.structured = autoExtractStructured(ctx.toolCall.name, ctx.result.output);
|
|
11004
|
+
}
|
|
11005
|
+
};
|
|
11006
|
+
var annotateStructuredOutputStep = {
|
|
11007
|
+
name: "output_annotation",
|
|
11008
|
+
run(ctx) {
|
|
11009
|
+
if (!ctx.structured) return;
|
|
11010
|
+
if (ctx.structured.credentials?.length) {
|
|
11011
|
+
ctx.outputAdditions.push(`
|
|
11012
|
+
[AUTO-EXTRACTED] ${ctx.structured.credentials.length} credential(s) found`);
|
|
11013
|
+
}
|
|
11014
|
+
if (ctx.structured.vulnerabilities?.length) {
|
|
11015
|
+
ctx.outputAdditions.push(`
|
|
11016
|
+
[AUTO-EXTRACTED] ${ctx.structured.vulnerabilities.length} CVE reference(s) found`);
|
|
11017
|
+
}
|
|
11018
|
+
if (ctx.structured.binaryAnalysisSummary) {
|
|
11019
|
+
ctx.outputAdditions.push(`
|
|
10753
11020
|
[AUTO-EXTRACTED] Binary analysis:
|
|
10754
|
-
${structured.binaryAnalysisSummary}`);
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
additions.push(`
|
|
10766
|
-
[AUTO-EXTRACTED] Crypto weaknesses: ${structured.cryptoWeaknesses.join("; ")}`);
|
|
10767
|
-
}
|
|
10768
|
-
if (structured.stegoHints?.length) {
|
|
10769
|
-
additions.push(`
|
|
10770
|
-
[AUTO-EXTRACTED] Stego hints: ${structured.stegoHints.join("; ")}`);
|
|
10771
|
-
}
|
|
10772
|
-
if (additions.length > 0) {
|
|
10773
|
-
result.output += additions.join("");
|
|
10774
|
-
}
|
|
11021
|
+
${ctx.structured.binaryAnalysisSummary}`);
|
|
11022
|
+
}
|
|
11023
|
+
if (ctx.structured.cryptoWeaknesses?.length) {
|
|
11024
|
+
ctx.outputAdditions.push(
|
|
11025
|
+
`
|
|
11026
|
+
[AUTO-EXTRACTED] Crypto weaknesses: ${ctx.structured.cryptoWeaknesses.join("; ")}`
|
|
11027
|
+
);
|
|
11028
|
+
}
|
|
11029
|
+
if (ctx.structured.stegoHints?.length) {
|
|
11030
|
+
ctx.outputAdditions.push(`
|
|
11031
|
+
[AUTO-EXTRACTED] Stego hints: ${ctx.structured.stegoHints.join("; ")}`);
|
|
10775
11032
|
}
|
|
10776
11033
|
}
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
11034
|
+
};
|
|
11035
|
+
var registerOSINTDiscoveriesStep = {
|
|
11036
|
+
name: "osint_target_registration",
|
|
11037
|
+
run(ctx) {
|
|
11038
|
+
if (!ctx.structured) return;
|
|
11039
|
+
if (ctx.structured.discoveredIPs?.length) {
|
|
11040
|
+
ctx.outputAdditions.push(handleOSINTIPs(ctx.state, ctx.structured.discoveredIPs, ctx.toolCall.name));
|
|
11041
|
+
}
|
|
11042
|
+
if (ctx.structured.discoveredSubdomains?.length) {
|
|
11043
|
+
for (const sub of ctx.structured.discoveredSubdomains.slice(0, 20)) {
|
|
11044
|
+
ctx.state.attackGraph.addOSINT("subdomain", sub, { source: ctx.toolCall.name });
|
|
10782
11045
|
}
|
|
10783
11046
|
}
|
|
10784
11047
|
}
|
|
11048
|
+
};
|
|
11049
|
+
var flushOutputAnnotationsStep = {
|
|
11050
|
+
name: "flush_output_annotation",
|
|
11051
|
+
run(ctx) {
|
|
11052
|
+
if (ctx.outputAdditions.length === 0) return;
|
|
11053
|
+
ctx.result.output += ctx.outputAdditions.join("");
|
|
11054
|
+
}
|
|
11055
|
+
};
|
|
11056
|
+
var detectChallengeStep = {
|
|
11057
|
+
name: "challenge_detection",
|
|
11058
|
+
run(ctx) {
|
|
11059
|
+
if (!ctx.result.success || ctx.state.getChallengeAnalysis()) return;
|
|
11060
|
+
if (!RECON_TRIGGER_TOOLS.has(ctx.toolCall.name)) return;
|
|
11061
|
+
if (!ctx.result.output || ctx.result.output.length <= MIN_RECON_OUTPUT_LENGTH) return;
|
|
11062
|
+
const analysis = analyzeChallenge(ctx.result.output);
|
|
11063
|
+
if (analysis.confidence > MIN_CHALLENGE_CONFIDENCE) {
|
|
11064
|
+
ctx.state.setChallengeAnalysis(analysis);
|
|
11065
|
+
}
|
|
11066
|
+
}
|
|
11067
|
+
};
|
|
11068
|
+
var POST_EXECUTION_STEPS = [
|
|
11069
|
+
recordWorkingMemoryStep,
|
|
11070
|
+
extractStructuredOutputStep,
|
|
11071
|
+
annotateStructuredOutputStep,
|
|
11072
|
+
registerOSINTDiscoveriesStep,
|
|
11073
|
+
flushOutputAnnotationsStep,
|
|
11074
|
+
detectChallengeStep
|
|
11075
|
+
];
|
|
11076
|
+
function runPostExecutionPipeline(state, toolCall, result) {
|
|
11077
|
+
const ctx = {
|
|
11078
|
+
state,
|
|
11079
|
+
toolCall,
|
|
11080
|
+
result,
|
|
11081
|
+
command: buildCommand(toolCall),
|
|
11082
|
+
structured: null,
|
|
11083
|
+
outputAdditions: []
|
|
11084
|
+
};
|
|
11085
|
+
for (const step of POST_EXECUTION_STEPS) {
|
|
11086
|
+
step.run(ctx);
|
|
11087
|
+
}
|
|
10785
11088
|
}
|
|
10786
11089
|
|
|
10787
11090
|
// src/engine/tool-registry/core.ts
|
|
@@ -11446,12 +11749,12 @@ function trackBlockedPattern(progress, toolName, errorLower) {
|
|
|
11446
11749
|
}
|
|
11447
11750
|
function appendBlockedCommandHints(lines, errorLower) {
|
|
11448
11751
|
if (errorLower.includes("pipe target") || errorLower.includes("injection")) {
|
|
11449
|
-
lines.push(`Fix: Use the tool's
|
|
11752
|
+
lines.push(`Fix: Use the tool's native output or formatting options instead of shell pipes.`);
|
|
11450
11753
|
lines.push(`Alternative approaches:`);
|
|
11451
11754
|
lines.push(` 1. Save output to file: command > ${WORK_DIR}/output.txt, then use read_file("${WORK_DIR}/output.txt")`);
|
|
11452
|
-
lines.push(` 2.
|
|
11453
|
-
lines.push(` 3.
|
|
11454
|
-
lines.push(` 4. If filtering output: run the command first, then read_file + parse
|
|
11755
|
+
lines.push(` 2. Discover the tool's own output flag via --help and use that instead of shell chaining`);
|
|
11756
|
+
lines.push(` 3. If the target is web content, prefer a dedicated browser/web tool over shell text filtering`);
|
|
11757
|
+
lines.push(` 4. If filtering output: run the command first, then read_file + parse the result in a second step`);
|
|
11455
11758
|
} else if (errorLower.includes("redirect")) {
|
|
11456
11759
|
lines.push(`Fix: Redirect to ${WORK_DIR}/ path.`);
|
|
11457
11760
|
lines.push(`Example: command > ${WORK_DIR}/output.txt or command 2>&1 > ${WORK_DIR}/errors.txt`);
|
|
@@ -11650,14 +11953,23 @@ function extractHypothesizedReason(failureLine) {
|
|
|
11650
11953
|
}
|
|
11651
11954
|
|
|
11652
11955
|
// src/shared/utils/context-digest/formatters.ts
|
|
11956
|
+
function safeList4(values) {
|
|
11957
|
+
return Array.isArray(values) ? values.filter((value) => typeof value === "string") : [];
|
|
11958
|
+
}
|
|
11653
11959
|
function formatContextForLLM(memo13) {
|
|
11654
11960
|
const compact = {};
|
|
11655
|
-
|
|
11656
|
-
|
|
11657
|
-
|
|
11658
|
-
|
|
11659
|
-
|
|
11660
|
-
|
|
11961
|
+
const keyFindings = safeList4(memo13.keyFindings);
|
|
11962
|
+
const credentials = safeList4(memo13.credentials);
|
|
11963
|
+
const attackVectors = safeList4(memo13.attackVectors);
|
|
11964
|
+
const failures = safeList4(memo13.failures);
|
|
11965
|
+
const suspicions = safeList4(memo13.suspicions);
|
|
11966
|
+
const nextSteps = safeList4(memo13.nextSteps);
|
|
11967
|
+
if (keyFindings.length > 0) compact.findings = keyFindings;
|
|
11968
|
+
if (credentials.length > 0) compact.credentials = credentials;
|
|
11969
|
+
if (attackVectors.length > 0) compact.attackVectors = attackVectors;
|
|
11970
|
+
if (failures.length > 0) compact.failures = failures;
|
|
11971
|
+
if (suspicions.length > 0) compact.suspicions = suspicions;
|
|
11972
|
+
if (nextSteps.length > 0) compact.nextSteps = nextSteps;
|
|
11661
11973
|
compact.attackValue = memo13.attackValue;
|
|
11662
11974
|
if (memo13.reflection) compact.reflection = memo13.reflection;
|
|
11663
11975
|
return JSON.stringify(compact);
|
|
@@ -12315,8 +12627,8 @@ function getTechniquesDir() {
|
|
|
12315
12627
|
return _techniquesDir;
|
|
12316
12628
|
}
|
|
12317
12629
|
function loadPromptFile(filename) {
|
|
12318
|
-
const
|
|
12319
|
-
return existsSync6(
|
|
12630
|
+
const path4 = join10(getPromptsDir(), filename);
|
|
12631
|
+
return existsSync6(path4) ? readFileSync3(path4, PROMPT_CONFIG.ENCODING) : "";
|
|
12320
12632
|
}
|
|
12321
12633
|
function loadTechniqueFile(techniqueName) {
|
|
12322
12634
|
const filename = techniqueName.endsWith(".md") ? techniqueName : `${techniqueName}.md`;
|
|
@@ -12330,14 +12642,20 @@ function loadTechniqueFile(techniqueName) {
|
|
|
12330
12642
|
}
|
|
12331
12643
|
|
|
12332
12644
|
// src/agents/prompt-builder/fragments/core.ts
|
|
12645
|
+
function safeList5(values) {
|
|
12646
|
+
return Array.isArray(values) ? values.filter((value) => typeof value === "string") : [];
|
|
12647
|
+
}
|
|
12333
12648
|
function buildScopeFragment(state) {
|
|
12334
12649
|
const scope = state.getScope();
|
|
12335
12650
|
if (!scope) return PROMPT_DEFAULTS.NO_SCOPE;
|
|
12651
|
+
const allowedCidrs = safeList5(scope.allowedCidrs);
|
|
12652
|
+
const allowedDomains = safeList5(scope.allowedDomains);
|
|
12653
|
+
const exclusions = safeList5(scope.exclusions);
|
|
12336
12654
|
const flags = `DOS Allowed: ${scope.isDOSAllowed} | Social Engineering Allowed: ${scope.isSocialAllowed}`;
|
|
12337
12655
|
return PROMPT_XML.SCOPE(
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
|
|
12656
|
+
allowedCidrs.join(", ") || "none",
|
|
12657
|
+
allowedDomains.join(", ") || "none",
|
|
12658
|
+
exclusions.join(", ") || "none",
|
|
12341
12659
|
flags
|
|
12342
12660
|
);
|
|
12343
12661
|
}
|
|
@@ -12457,7 +12775,7 @@ ${summary}
|
|
|
12457
12775
|
</session-journal>`;
|
|
12458
12776
|
}
|
|
12459
12777
|
if (olderTurns.length > 0) {
|
|
12460
|
-
const indexLines = olderTurns.slice(-10).map((n) => `.pentesting/turns/${n}.md`).join("\n");
|
|
12778
|
+
const indexLines = olderTurns.slice(-10).map((n) => `.pentesting/turns/${n}-memory.md`).join("\n");
|
|
12461
12779
|
const ellipsis = olderTurns.length > 10 ? `
|
|
12462
12780
|
... (${olderTurns.length - 10} earlier turns \u2014 check .pentesting/turns/)` : "";
|
|
12463
12781
|
output += `
|
|
@@ -12477,6 +12795,8 @@ function buildUserContextFragment(userInput) {
|
|
|
12477
12795
|
}
|
|
12478
12796
|
|
|
12479
12797
|
// src/agents/prompt-builder/yaml-layer-executor.ts
|
|
12798
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
12799
|
+
import path2 from "path";
|
|
12480
12800
|
var STATE_FRAGMENT_REGISTRY = {
|
|
12481
12801
|
"state.scope": (ctx) => buildScopeFragment(ctx.state),
|
|
12482
12802
|
"state.todo": (ctx) => buildTodoFragment(ctx.state),
|
|
@@ -12508,7 +12828,7 @@ async function executeLayer(layer, ctx) {
|
|
|
12508
12828
|
case "static":
|
|
12509
12829
|
return layer.content?.trim() ?? null;
|
|
12510
12830
|
case "file_read":
|
|
12511
|
-
return
|
|
12831
|
+
return executeFileReadLayer(layer) || null;
|
|
12512
12832
|
case "user_input":
|
|
12513
12833
|
return buildUserContextFragment(ctx.userInput) || null;
|
|
12514
12834
|
case "memory": {
|
|
@@ -12522,6 +12842,21 @@ async function executeLayer(layer, ctx) {
|
|
|
12522
12842
|
return null;
|
|
12523
12843
|
}
|
|
12524
12844
|
}
|
|
12845
|
+
function executeFileReadLayer(layer) {
|
|
12846
|
+
const source = layer.source?.trim();
|
|
12847
|
+
if (!source) return null;
|
|
12848
|
+
if (source.includes("{N-1}")) {
|
|
12849
|
+
return buildJournalFragment() || null;
|
|
12850
|
+
}
|
|
12851
|
+
const absolutePath = path2.resolve(process.cwd(), source);
|
|
12852
|
+
if (!existsSync7(absolutePath)) return null;
|
|
12853
|
+
const content = readFileSync4(absolutePath, "utf-8").trim();
|
|
12854
|
+
if (!content) return null;
|
|
12855
|
+
if (layer.wrap) {
|
|
12856
|
+
return layer.wrap.replace("{content}", content);
|
|
12857
|
+
}
|
|
12858
|
+
return content;
|
|
12859
|
+
}
|
|
12525
12860
|
function executeFileLayer(layer) {
|
|
12526
12861
|
if (!layer.source) return null;
|
|
12527
12862
|
const parts = layer.source.split("/");
|
|
@@ -12640,6 +12975,9 @@ function isPipelineNode(step) {
|
|
|
12640
12975
|
}
|
|
12641
12976
|
|
|
12642
12977
|
// src/engine/pipeline/runner.ts
|
|
12978
|
+
function collectChangedMemoryKeys(base, next) {
|
|
12979
|
+
return Object.keys(next).filter((key) => !Object.is(base[key], next[key]));
|
|
12980
|
+
}
|
|
12643
12981
|
var PipelineRunner = class {
|
|
12644
12982
|
/**
|
|
12645
12983
|
* Recursively execute a pipeline step.
|
|
@@ -12677,7 +13015,29 @@ var PipelineRunner = class {
|
|
|
12677
13015
|
return;
|
|
12678
13016
|
}
|
|
12679
13017
|
if ("parallel" in step) {
|
|
12680
|
-
await Promise.all(step.parallel.map((s) =>
|
|
13018
|
+
const branchResults = await Promise.all(step.parallel.map(async (s) => {
|
|
13019
|
+
const localMemory = { ...ctx.memory };
|
|
13020
|
+
const branchCtx = { ...ctx, memory: localMemory };
|
|
13021
|
+
await this.execute(s, branchCtx);
|
|
13022
|
+
return localMemory;
|
|
13023
|
+
}));
|
|
13024
|
+
const collisions = /* @__PURE__ */ new Set();
|
|
13025
|
+
const baseMemory = { ...ctx.memory };
|
|
13026
|
+
for (const branchMemory of branchResults) {
|
|
13027
|
+
const changedKeys = collectChangedMemoryKeys(baseMemory, branchMemory);
|
|
13028
|
+
for (const key of changedKeys) {
|
|
13029
|
+
if (Object.prototype.hasOwnProperty.call(ctx.memory, key) && !Object.is(ctx.memory[key], baseMemory[key])) {
|
|
13030
|
+
collisions.add(key);
|
|
13031
|
+
continue;
|
|
13032
|
+
}
|
|
13033
|
+
ctx.memory[key] = branchMemory[key];
|
|
13034
|
+
}
|
|
13035
|
+
}
|
|
13036
|
+
if (collisions.size > 0) {
|
|
13037
|
+
throw new Error(
|
|
13038
|
+
`PipelineRunner parallel memory collision on key(s): ${Array.from(collisions).join(", ")}`
|
|
13039
|
+
);
|
|
13040
|
+
}
|
|
12681
13041
|
return;
|
|
12682
13042
|
}
|
|
12683
13043
|
if ("condition" in step) {
|
|
@@ -12732,7 +13092,7 @@ var ActionNode = class {
|
|
|
12732
13092
|
var flagsCaptured = (ctx) => ctx.flagsAfter > ctx.flagsBefore;
|
|
12733
13093
|
|
|
12734
13094
|
// src/engine/pipeline/loader.ts
|
|
12735
|
-
import { readFileSync as
|
|
13095
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
12736
13096
|
import { join as join11 } from "path";
|
|
12737
13097
|
import { parse as yamlParse } from "yaml";
|
|
12738
13098
|
|
|
@@ -12853,32 +13213,45 @@ var makeSynthesizePlaybook = (llm, opts) => async (ctx) => {
|
|
|
12853
13213
|
// src/agents/main-agent/turn-recorder.ts
|
|
12854
13214
|
import { writeFileSync as writeFileSync7 } from "fs";
|
|
12855
13215
|
async function recordTurn(context) {
|
|
12856
|
-
const { turnCounter, toolJournal,
|
|
13216
|
+
const { turnCounter, toolJournal, memorySynth } = context;
|
|
12857
13217
|
if (toolJournal.length === 0) return turnCounter;
|
|
12858
13218
|
try {
|
|
12859
|
-
await writeTurnInsight(turnCounter,
|
|
13219
|
+
await writeTurnInsight(turnCounter, memorySynth, context);
|
|
12860
13220
|
rotateTurnRecords();
|
|
12861
13221
|
} catch {
|
|
12862
13222
|
}
|
|
12863
13223
|
return turnCounter + 1;
|
|
12864
13224
|
}
|
|
12865
|
-
async function writeTurnInsight(turnCounter,
|
|
13225
|
+
async function writeTurnInsight(turnCounter, memorySynth, ctx) {
|
|
12866
13226
|
const { phase, toolJournal, memo: memo13, reflections } = ctx;
|
|
13227
|
+
const fallbackNextSteps = Array.isArray(memo13.nextSteps) ? memo13.nextSteps : [];
|
|
12867
13228
|
const turnData = formatTurnRecord({
|
|
12868
13229
|
turn: turnCounter,
|
|
12869
13230
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12870
13231
|
phase,
|
|
12871
13232
|
tools: toolJournal,
|
|
12872
13233
|
memo: memo13,
|
|
12873
|
-
reflection: reflections.length > 0 ? reflections.join(" | ") :
|
|
13234
|
+
reflection: reflections.length > 0 ? reflections.join(" | ") : fallbackNextSteps.join("; ")
|
|
12874
13235
|
});
|
|
12875
13236
|
const existingSummary = readJournalSummary();
|
|
12876
13237
|
try {
|
|
12877
|
-
const result = await
|
|
13238
|
+
const result = await memorySynth.execute({ existingSummary, turnData });
|
|
12878
13239
|
if (result.success && result.summary) {
|
|
12879
13240
|
ensureDirExists(WORKSPACE.TURNS);
|
|
12880
|
-
|
|
12881
|
-
|
|
13241
|
+
const memoryFile = buildTurnMemoryDocument({
|
|
13242
|
+
turn: turnCounter,
|
|
13243
|
+
phase,
|
|
13244
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13245
|
+
writtenBy: "memory_synth",
|
|
13246
|
+
inputSources: [
|
|
13247
|
+
"previous_turn_memory",
|
|
13248
|
+
"current_turn_record"
|
|
13249
|
+
],
|
|
13250
|
+
notesIncluded: reflections.length > 0 ? ["analyst_memo", "turn_reviews"] : ["analyst_memo"],
|
|
13251
|
+
memoryBody: result.summary
|
|
13252
|
+
});
|
|
13253
|
+
writeFileSync7(WORKSPACE.turnPath(turnCounter), memoryFile, "utf-8");
|
|
13254
|
+
flowLog("\u2465MemorySynth", "\u2192", `turns/${turnCounter}-memory.md`, `${memoryFile.length}B`);
|
|
12882
13255
|
} else {
|
|
12883
13256
|
regenerateJournalSummary();
|
|
12884
13257
|
}
|
|
@@ -12887,27 +13260,158 @@ async function writeTurnInsight(turnCounter, summaryRegenerator, ctx) {
|
|
|
12887
13260
|
}
|
|
12888
13261
|
}
|
|
12889
13262
|
|
|
13263
|
+
// src/engine/verifier/turn-verifier.ts
|
|
13264
|
+
function asStringArray(values) {
|
|
13265
|
+
return Array.isArray(values) ? values.filter((value) => typeof value === "string") : [];
|
|
13266
|
+
}
|
|
13267
|
+
function uniq(values) {
|
|
13268
|
+
const safeValues = asStringArray(values);
|
|
13269
|
+
if (safeValues.length === 0) return [];
|
|
13270
|
+
return [...new Set(safeValues.map((v) => v.trim()).filter(Boolean))];
|
|
13271
|
+
}
|
|
13272
|
+
function parseInputSummary(inputSummary) {
|
|
13273
|
+
try {
|
|
13274
|
+
const parsed = JSON.parse(inputSummary);
|
|
13275
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
13276
|
+
} catch {
|
|
13277
|
+
return null;
|
|
13278
|
+
}
|
|
13279
|
+
}
|
|
13280
|
+
function verifyStateConsistency(ctx) {
|
|
13281
|
+
const issues = [];
|
|
13282
|
+
const lootDetails = ctx.state.getLoot().map((item) => item.detail.toLowerCase());
|
|
13283
|
+
const findingTexts = ctx.state.getFindings().map((item) => `${item.title}
|
|
13284
|
+
${item.description}`.toLowerCase());
|
|
13285
|
+
for (const credential of uniq(ctx.memo?.credentials)) {
|
|
13286
|
+
if (!lootDetails.some((detail) => detail.includes(credential.toLowerCase()))) {
|
|
13287
|
+
issues.push({
|
|
13288
|
+
severity: "error",
|
|
13289
|
+
code: "state_consistency",
|
|
13290
|
+
message: `Analyst extracted credential "${credential}" but state.loot does not contain it.`
|
|
13291
|
+
});
|
|
13292
|
+
}
|
|
13293
|
+
}
|
|
13294
|
+
if (ctx.memo?.attackValue === "HIGH" || ctx.memo?.attackValue === "MED") {
|
|
13295
|
+
for (const vector of uniq(ctx.memo?.attackVectors)) {
|
|
13296
|
+
const needle = vector.toLowerCase().slice(0, 80);
|
|
13297
|
+
if (!findingTexts.some((text) => text.includes(needle))) {
|
|
13298
|
+
issues.push({
|
|
13299
|
+
severity: "warning",
|
|
13300
|
+
code: "state_consistency",
|
|
13301
|
+
message: `Analyst marked attack vector "${vector}" but no matching finding was recorded.`
|
|
13302
|
+
});
|
|
13303
|
+
}
|
|
13304
|
+
}
|
|
13305
|
+
}
|
|
13306
|
+
return issues;
|
|
13307
|
+
}
|
|
13308
|
+
function verifyScopeConsistency(ctx) {
|
|
13309
|
+
if (getScopeMode() !== "enforce") return [];
|
|
13310
|
+
const issues = [];
|
|
13311
|
+
const guard = new ScopeGuard(ctx.state, "enforce");
|
|
13312
|
+
for (const tool of ctx.journal) {
|
|
13313
|
+
if (!tool.success) continue;
|
|
13314
|
+
const parsedInput = parseInputSummary(tool.inputSummary);
|
|
13315
|
+
if (!parsedInput) continue;
|
|
13316
|
+
const serialized = JSON.stringify(parsedInput);
|
|
13317
|
+
const targets = Array.from(guard.extractTargets(serialized));
|
|
13318
|
+
const violations = targets.filter((target) => !guard.isTargetInScope(target));
|
|
13319
|
+
if (violations.length === 0) continue;
|
|
13320
|
+
issues.push({
|
|
13321
|
+
severity: "error",
|
|
13322
|
+
code: "scope_violation",
|
|
13323
|
+
message: `Successful tool ${tool.name} referenced out-of-scope target(s): ${violations.join(", ")}`
|
|
13324
|
+
});
|
|
13325
|
+
}
|
|
13326
|
+
return issues;
|
|
13327
|
+
}
|
|
13328
|
+
function verifyAskUserUsage(ctx) {
|
|
13329
|
+
const issues = [];
|
|
13330
|
+
const askUserCalls = ctx.journal.filter((tool) => tool.name === TOOL_NAMES.ASK_USER && tool.success);
|
|
13331
|
+
const nonSensitive = [];
|
|
13332
|
+
for (const call of askUserCalls) {
|
|
13333
|
+
const parsed = parseInputSummary(call.inputSummary);
|
|
13334
|
+
const inputType = String(parsed?.input_type || "text");
|
|
13335
|
+
const question = String(parsed?.question || "");
|
|
13336
|
+
if (!SENSITIVE_INPUT_TYPES.includes(inputType)) {
|
|
13337
|
+
nonSensitive.push({ inputType, question });
|
|
13338
|
+
}
|
|
13339
|
+
}
|
|
13340
|
+
if (nonSensitive.length > 0) {
|
|
13341
|
+
issues.push({
|
|
13342
|
+
severity: "warning",
|
|
13343
|
+
code: "ask_user_overuse",
|
|
13344
|
+
message: `Non-sensitive ask_user used ${nonSensitive.length} time(s): ${nonSensitive.map((item) => `${item.inputType}:${item.question.slice(0, 80)}`).join(" | ")}`
|
|
13345
|
+
});
|
|
13346
|
+
}
|
|
13347
|
+
if (askUserCalls.length > 1) {
|
|
13348
|
+
issues.push({
|
|
13349
|
+
severity: "warning",
|
|
13350
|
+
code: "ask_user_overuse",
|
|
13351
|
+
message: `ask_user was called ${askUserCalls.length} times in one turn.`
|
|
13352
|
+
});
|
|
13353
|
+
}
|
|
13354
|
+
return issues;
|
|
13355
|
+
}
|
|
13356
|
+
function formatSummary(issues) {
|
|
13357
|
+
if (issues.length === 0) return "[VERIFIER] OK - no rule violations detected";
|
|
13358
|
+
const errorCount = issues.filter((issue) => issue.severity === "error").length;
|
|
13359
|
+
const warningCount = issues.filter((issue) => issue.severity === "warning").length;
|
|
13360
|
+
const lines = [`[VERIFIER] ${errorCount} error(s), ${warningCount} warning(s)`];
|
|
13361
|
+
for (const issue of issues.slice(0, 5)) {
|
|
13362
|
+
lines.push(`- ${issue.severity.toUpperCase()} ${issue.code}: ${issue.message}`);
|
|
13363
|
+
}
|
|
13364
|
+
return lines.join("\n");
|
|
13365
|
+
}
|
|
13366
|
+
function verifyTurnContext(ctx) {
|
|
13367
|
+
const issues = [
|
|
13368
|
+
...verifyStateConsistency(ctx),
|
|
13369
|
+
...verifyScopeConsistency(ctx),
|
|
13370
|
+
...verifyAskUserUsage(ctx)
|
|
13371
|
+
];
|
|
13372
|
+
return {
|
|
13373
|
+
ok: !issues.some((issue) => issue.severity === "error"),
|
|
13374
|
+
issues,
|
|
13375
|
+
summary: formatSummary(issues)
|
|
13376
|
+
};
|
|
13377
|
+
}
|
|
13378
|
+
|
|
12890
13379
|
// src/engine/pipeline/handlers/turn-mgmt.ts
|
|
13380
|
+
function resolveCurrentTurnCounter(memory) {
|
|
13381
|
+
return typeof memory.turnCounter === "number" ? memory.turnCounter : Math.max(1, (getNextTurnNumber() || 2) - 1);
|
|
13382
|
+
}
|
|
13383
|
+
function collectTurnReflections(ctx) {
|
|
13384
|
+
return [
|
|
13385
|
+
...ctx.state.lastReflection ? [ctx.state.lastReflection] : [],
|
|
13386
|
+
...typeof ctx.memory.turn_verifier_summary === "string" ? [ctx.memory.turn_verifier_summary] : []
|
|
13387
|
+
];
|
|
13388
|
+
}
|
|
12891
13389
|
var makeWriteInsight = (llm, _opts) => async (ctx) => {
|
|
12892
13390
|
if (!llm) return { success: false };
|
|
12893
|
-
const turnCounter =
|
|
13391
|
+
const turnCounter = resolveCurrentTurnCounter(ctx.memory);
|
|
12894
13392
|
await recordTurn({
|
|
12895
13393
|
turnCounter,
|
|
12896
13394
|
phase: ctx.state.getPhase(),
|
|
12897
13395
|
toolJournal: ctx.journal,
|
|
12898
13396
|
memo: ctx.memo,
|
|
12899
|
-
reflections: ctx
|
|
12900
|
-
|
|
13397
|
+
reflections: collectTurnReflections(ctx),
|
|
13398
|
+
memorySynth: createMemorySynth(llm)
|
|
12901
13399
|
});
|
|
12902
13400
|
return { success: true };
|
|
12903
13401
|
};
|
|
13402
|
+
var makeVerifyTurn = (_llm, _opts) => async (ctx) => {
|
|
13403
|
+
const report = verifyTurnContext(ctx);
|
|
13404
|
+
ctx.memory.turn_verifier_report = report;
|
|
13405
|
+
ctx.memory.turn_verifier_summary = report.summary;
|
|
13406
|
+
return { success: report.ok, output: report };
|
|
13407
|
+
};
|
|
12904
13408
|
var makeRotateTurns = (_llm, _opts) => async (_ctx) => {
|
|
12905
13409
|
rotateTurnRecords();
|
|
12906
13410
|
return { success: true };
|
|
12907
13411
|
};
|
|
12908
13412
|
var makeSaveSession = (_llm, _opts) => async (ctx) => {
|
|
12909
13413
|
try {
|
|
12910
|
-
const { saveState: saveState2 } = await import("./persistence-
|
|
13414
|
+
const { saveState: saveState2 } = await import("./persistence-7FTYXIZY.js");
|
|
12911
13415
|
saveState2(ctx.state);
|
|
12912
13416
|
} catch {
|
|
12913
13417
|
}
|
|
@@ -12915,9 +13419,26 @@ var makeSaveSession = (_llm, _opts) => async (ctx) => {
|
|
|
12915
13419
|
};
|
|
12916
13420
|
|
|
12917
13421
|
// src/engine/pipeline/handlers/core-loop.ts
|
|
12918
|
-
var
|
|
13422
|
+
var makeProcessUserInput = (_llm, _opts) => async (ctx) => {
|
|
12919
13423
|
if (!ctx.controller) return { success: true };
|
|
12920
|
-
ctx.controller.
|
|
13424
|
+
const result = await ctx.controller.processUserInputTurn();
|
|
13425
|
+
const shouldForward = result?.shouldForwardToMain !== false;
|
|
13426
|
+
ctx.memory.should_forward_to_main = shouldForward;
|
|
13427
|
+
if (!shouldForward) {
|
|
13428
|
+
const directResponse = typeof result?.directResponse === "string" ? result.directResponse : "";
|
|
13429
|
+
ctx.memory.output = directResponse;
|
|
13430
|
+
ctx.memory.short_circuit_response = ctx.memory.output;
|
|
13431
|
+
ctx.memory.has_tool_calls = false;
|
|
13432
|
+
ctx.memory.isCompleted = true;
|
|
13433
|
+
if (directResponse.trim() && ctx.events) {
|
|
13434
|
+
const phase = ctx.state.getPhase();
|
|
13435
|
+
ctx.events.emit({
|
|
13436
|
+
type: EVENT_TYPES.AI_RESPONSE,
|
|
13437
|
+
timestamp: Date.now(),
|
|
13438
|
+
data: { content: directResponse.trim(), phase }
|
|
13439
|
+
});
|
|
13440
|
+
}
|
|
13441
|
+
}
|
|
12921
13442
|
return { success: true };
|
|
12922
13443
|
};
|
|
12923
13444
|
var makeBuildSystemPrompt = (_llm, _opts) => async (ctx) => {
|
|
@@ -12928,6 +13449,12 @@ var makeBuildSystemPrompt = (_llm, _opts) => async (ctx) => {
|
|
|
12928
13449
|
};
|
|
12929
13450
|
var makeCoreInference = (_llm, _opts) => async (ctx) => {
|
|
12930
13451
|
if (!ctx.controller) throw new Error("AgentController missing in context");
|
|
13452
|
+
if (ctx.memory.short_circuit_response) {
|
|
13453
|
+
ctx.memory.output = ctx.memory.short_circuit_response;
|
|
13454
|
+
ctx.memory.has_tool_calls = false;
|
|
13455
|
+
ctx.memory.isCompleted = true;
|
|
13456
|
+
return { success: true };
|
|
13457
|
+
}
|
|
12931
13458
|
const prompt = ctx.memory.system_prompt;
|
|
12932
13459
|
if (!prompt) throw new Error("core_inference: system_prompt missing \u2014 build_system_prompt must run before core_inference");
|
|
12933
13460
|
const { output, toolCalls, hadReasoningEnd } = await ctx.controller.runLLMInference(ctx, prompt);
|
|
@@ -12959,11 +13486,12 @@ var ACTION_HANDLER_REGISTRY = {
|
|
|
12959
13486
|
replace_messages_from_memory: makeReplaceMessagesFromMemory,
|
|
12960
13487
|
synthesize_playbook: makeSynthesizePlaybook,
|
|
12961
13488
|
// ── Turn lifecycle handlers ─────────────────────────────────────────────
|
|
13489
|
+
verify_turn: makeVerifyTurn,
|
|
12962
13490
|
write_insight: makeWriteInsight,
|
|
12963
13491
|
rotate_turns: makeRotateTurns,
|
|
12964
13492
|
save_session: makeSaveSession,
|
|
12965
13493
|
// ── Core agent loop handlers ────────────────────────────────────────────
|
|
12966
|
-
|
|
13494
|
+
process_user_input: makeProcessUserInput,
|
|
12967
13495
|
build_system_prompt: makeBuildSystemPrompt,
|
|
12968
13496
|
core_inference: makeCoreInference,
|
|
12969
13497
|
core_tool_execution: makeCoreToolExecution
|
|
@@ -13031,11 +13559,6 @@ function buildStepV2(raw, nodeMap, conditions) {
|
|
|
13031
13559
|
throw new Error(`Invalid pipeline step: ${JSON.stringify(raw)}`);
|
|
13032
13560
|
}
|
|
13033
13561
|
const r = raw;
|
|
13034
|
-
if ("node" in r && typeof r["node"] === "string") {
|
|
13035
|
-
const node = nodeMap.get(r["node"]);
|
|
13036
|
-
if (!node) throw new Error(`Unknown node reference: "${r["node"]}". Declare it in nodes: section.`);
|
|
13037
|
-
return node;
|
|
13038
|
-
}
|
|
13039
13562
|
if ("serial" in r && Array.isArray(r["serial"])) {
|
|
13040
13563
|
return { serial: r["serial"].map((s) => buildStepV2(s, nodeMap, conditions)) };
|
|
13041
13564
|
}
|
|
@@ -13055,18 +13578,16 @@ function buildStepV2(raw, nodeMap, conditions) {
|
|
|
13055
13578
|
}
|
|
13056
13579
|
throw new Error(`Unrecognized step shape: ${JSON.stringify(raw)}`);
|
|
13057
13580
|
}
|
|
13058
|
-
function loadPipeline(yamlPath,
|
|
13059
|
-
const content =
|
|
13581
|
+
function loadPipeline(yamlPath, options) {
|
|
13582
|
+
const content = readFileSync5(yamlPath, "utf-8");
|
|
13060
13583
|
const config = yamlParse(content);
|
|
13061
|
-
const key =
|
|
13584
|
+
const key = options.key ?? "post_step";
|
|
13062
13585
|
const raw = config[key];
|
|
13063
13586
|
if (!raw) throw new Error(`Pipeline key "${key}" not found in ${yamlPath}`);
|
|
13064
|
-
if (
|
|
13065
|
-
|
|
13066
|
-
}
|
|
13067
|
-
return buildStepV1(raw, registryOrOptions);
|
|
13587
|
+
if (!config.nodes) throw new Error(`Pipeline config in ${yamlPath} must declare a nodes: section.`);
|
|
13588
|
+
return loadCurrent(config, raw, options);
|
|
13068
13589
|
}
|
|
13069
|
-
function
|
|
13590
|
+
function loadCurrent(config, pipelineRaw, opts) {
|
|
13070
13591
|
const llm = opts.llm;
|
|
13071
13592
|
const conditions = opts.conditions ?? {};
|
|
13072
13593
|
const nodeDefs = config.nodes ?? {};
|
|
@@ -13082,33 +13603,6 @@ function loadV2(config, pipelineRaw, opts) {
|
|
|
13082
13603
|
}
|
|
13083
13604
|
return buildStepV2(pipelineRaw, nodeMap, conditions);
|
|
13084
13605
|
}
|
|
13085
|
-
function buildStepV1(raw, registry) {
|
|
13086
|
-
if (!raw || typeof raw !== "object") {
|
|
13087
|
-
throw new Error(`Invalid pipeline step: ${JSON.stringify(raw)}`);
|
|
13088
|
-
}
|
|
13089
|
-
const r = raw;
|
|
13090
|
-
if ("node" in r) {
|
|
13091
|
-
const id = r["node"];
|
|
13092
|
-
const factory = registry.nodes[id];
|
|
13093
|
-
if (!factory) throw new Error(`Unknown node: "${id}". Register it in node-registry.ts.`);
|
|
13094
|
-
return factory(id);
|
|
13095
|
-
}
|
|
13096
|
-
if ("serial" in r && Array.isArray(r["serial"])) {
|
|
13097
|
-
return { serial: r["serial"].map((s) => buildStepV1(s, registry)) };
|
|
13098
|
-
}
|
|
13099
|
-
if ("parallel" in r && Array.isArray(r["parallel"])) {
|
|
13100
|
-
return { parallel: r["parallel"].map((s) => buildStepV1(s, registry)) };
|
|
13101
|
-
}
|
|
13102
|
-
if ("when" in r) {
|
|
13103
|
-
const condName = r["when"];
|
|
13104
|
-
const cond = registry.conditions[condName];
|
|
13105
|
-
if (!cond) throw new Error(`Unknown condition: "${condName}".`);
|
|
13106
|
-
const then = buildStepV1(r["then"], registry);
|
|
13107
|
-
const otherwise = "else" in r ? buildStepV1(r["else"], registry) : void 0;
|
|
13108
|
-
return { condition: cond, then, else: otherwise };
|
|
13109
|
-
}
|
|
13110
|
-
throw new Error(`Unrecognized step shape: ${JSON.stringify(raw)}`);
|
|
13111
|
-
}
|
|
13112
13606
|
function resolvePipelineYaml(relativePath) {
|
|
13113
13607
|
return join11(process.cwd(), relativePath);
|
|
13114
13608
|
}
|
|
@@ -13129,181 +13623,15 @@ function getConditionRegistry() {
|
|
|
13129
13623
|
// Fires when ≥ 2 SUCCEEDED attack graph nodes exist (works without flags)
|
|
13130
13624
|
has_exploit_chain: hasExploitChain,
|
|
13131
13625
|
// Fires when the LLM returned tool calls to execute
|
|
13132
|
-
has_tool_calls: (ctx) => ctx.memory.has_tool_calls === true
|
|
13626
|
+
has_tool_calls: (ctx) => ctx.memory.has_tool_calls === true,
|
|
13627
|
+
// Fires when input processing decided the main agent should continue.
|
|
13628
|
+
should_forward_to_main: (ctx) => ctx.memory.should_forward_to_main !== false
|
|
13133
13629
|
};
|
|
13134
13630
|
}
|
|
13135
13631
|
|
|
13136
|
-
// src/agents/user-input/constants.ts
|
|
13137
|
-
var RECENT_MESSAGE_THRESHOLD_SECONDS = 5;
|
|
13138
|
-
|
|
13139
|
-
// src/agents/user-input/intent/header.ts
|
|
13140
|
-
var INTENT_HEADER = `
|
|
13141
|
-
<user-message priority="INTERRUPT">
|
|
13142
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13143
|
-
\u26A1 USER MESSAGE \u2014 STOP. READ THIS FIRST. THEN ACT.
|
|
13144
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13145
|
-
|
|
13146
|
-
The user sent the following message(s) WHILE you are actively working.
|
|
13147
|
-
This message takes PRECEDENCE over your current plan. Process it NOW.
|
|
13148
|
-
|
|
13149
|
-
IMPORTANT RULES:
|
|
13150
|
-
- If the user is repeating themselves, it means you MISSED or IGNORED their previous message.
|
|
13151
|
-
- Check your Working Memory for the correct value before proceeding.
|
|
13152
|
-
- NEVER continue with an incorrect value after a correction, even if it appears in a SUCCESS log.
|
|
13153
|
-
- Working Memory success logs are NOT ground truth \u2014 user corrections override them.
|
|
13154
|
-
|
|
13155
|
-
<<USER_MESSAGES>>
|
|
13156
|
-
`;
|
|
13157
|
-
|
|
13158
|
-
// src/agents/user-input/intent/classification.ts
|
|
13159
|
-
var INTENT_CLASSIFICATION = `
|
|
13160
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13161
|
-
\xA71. INTENT CLASSIFICATION (Chain-of-Thought \u2014 MANDATORY)
|
|
13162
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13163
|
-
|
|
13164
|
-
You MUST internally reason through this decision tree IN ORDER.
|
|
13165
|
-
Stop at the FIRST matching category \u2014 do NOT skip ahead.
|
|
13166
|
-
|
|
13167
|
-
\u250C\u2500 STEP 1: Is the user telling you to STOP or ABORT?
|
|
13168
|
-
\u2502 Signals: "stop", "abort", "cancel", "enough", "halt", "wait"
|
|
13169
|
-
\u2502 \u2192 CATEGORY: ABORT
|
|
13170
|
-
\u2502 \u2192 ACTION: Immediately stop current tool execution.
|
|
13171
|
-
\u2502 Use \`ask_user\` to confirm: "Understood, stopping. What would you like me to do next?"
|
|
13172
|
-
\u2502
|
|
13173
|
-
\u251C\u2500 STEP 2: Is the user CORRECTING you or saying you're WRONG?
|
|
13174
|
-
\u2502 Signals: "that's wrong", "don't do that", "stop doing X", "you already tried that",
|
|
13175
|
-
\u2502 "not that way", "I said X not Y", negative feedback on your actions,
|
|
13176
|
-
\u2502 spelling corrections ("you wrote X, it should be Y"),
|
|
13177
|
-
\u2502 name corrections ("that's not the right username/target/domain")
|
|
13178
|
-
\u2502 \u2192 CATEGORY: CORRECTION
|
|
13179
|
-
\u2502 \u2192 ACTION: 1. Acknowledge the error in ONE sentence (do NOT apologize excessively).
|
|
13180
|
-
\u2502 2. IMMEDIATELY fix the mistake and resume work with the correct value.
|
|
13181
|
-
\u2502 3. Do NOT use \`ask_user\` for confirmation \u2014 fix it and continue.
|
|
13182
|
-
\u2502 4. NEVER repeat the same wrong value after a correction.
|
|
13183
|
-
\u2502
|
|
13184
|
-
\u251C\u2500 STEP 3: Is the user providing ACTIONABLE INFORMATION?
|
|
13185
|
-
\u2502 Signals: credentials, passwords, usernames, file paths, endpoints, API keys,
|
|
13186
|
-
\u2502 ports, version numbers, IP addresses, hints about the target
|
|
13187
|
-
\u2502 \u2192 CATEGORY: INFORMATION
|
|
13188
|
-
\u2502 \u2192 ACTION: 1. Store with \`add_loot\` (if credentials) or remember contextually.
|
|
13189
|
-
\u2502 2. USE this information immediately in your next tool call.
|
|
13190
|
-
\u2502 3. Do NOT ask "should I use this?" \u2014 just use it.
|
|
13191
|
-
\u2502 Example: User says "password is admin123"
|
|
13192
|
-
\u2502 \u2192 Immediately try those credentials on all discovered login surfaces.
|
|
13193
|
-
\u2502
|
|
13194
|
-
\u251C\u2500 STEP 4: Is the user giving a DIRECT COMMAND to execute something?
|
|
13195
|
-
\u2502 Signals: imperative verb + specific action: "run X", "scan Y", "exploit Z",
|
|
13196
|
-
\u2502 "try X on Y", "use sqlmap", "brute force SSH"
|
|
13197
|
-
\u2502 \u2192 CATEGORY: COMMAND
|
|
13198
|
-
\u2502 \u2192 ACTION: Execute EXACTLY what the user asked. No more, no less.
|
|
13199
|
-
\u2502 Do NOT add extra scans or "while we're at it" actions.
|
|
13200
|
-
\u2502 Do NOT ask for confirmation \u2014 the user already decided.
|
|
13201
|
-
\u2502
|
|
13202
|
-
\u251C\u2500 STEP 5: Is the user changing the TARGET or SCOPE?
|
|
13203
|
-
\u2502 Signals: new IP/domain, "switch to", "add target", "remove target",
|
|
13204
|
-
\u2502 "also attack X", "change scope"
|
|
13205
|
-
\u2502 \u2192 CATEGORY: TARGET_CHANGE
|
|
13206
|
-
\u2502 \u2192 ACTION: 1. Call \`add_target\` with the new target.
|
|
13207
|
-
\u2502 2. Confirm briefly with \`ask_user\`: "Added [target]. Starting reconnaissance."
|
|
13208
|
-
\u2502 3. Begin testing the new target.
|
|
13209
|
-
\u2502
|
|
13210
|
-
\u251C\u2500 STEP 6: Is the user providing STRATEGIC GUIDANCE?
|
|
13211
|
-
\u2502 Signals: "focus on X", "prioritize Y", "skip Z", "try X approach",
|
|
13212
|
-
\u2502 "what about X?", "have you considered X?", tactical suggestions
|
|
13213
|
-
\u2502 \u2192 CATEGORY: GUIDANCE
|
|
13214
|
-
\u2502 \u2192 ACTION: 1. Acknowledge the guidance briefly via \`ask_user\`:
|
|
13215
|
-
\u2502 "Understood \u2014 adjusting strategy to focus on [X]."
|
|
13216
|
-
\u2502 2. Immediately adjust your approach and continue working.
|
|
13217
|
-
\u2502 3. The acknowledgment and next action should be in the SAME turn.
|
|
13218
|
-
\u2502
|
|
13219
|
-
\u251C\u2500 STEP 7: Is the user asking about PROGRESS or STATUS?
|
|
13220
|
-
\u2502 Signals: "what did you find?", "any progress?", "status?", "what are you doing?",
|
|
13221
|
-
\u2502 "show me", "report", "findings so far", "how's it going?"
|
|
13222
|
-
\u2502 \u2192 CATEGORY: STATUS_QUERY
|
|
13223
|
-
\u2502 \u2192 ACTION: Use \`ask_user\` to provide a structured status report:
|
|
13224
|
-
\u2502 FORMAT:
|
|
13225
|
-
\u2502 "\u{1F4CA} Status Report:
|
|
13226
|
-
\u2502 \u2022 Phase: [current phase]
|
|
13227
|
-
\u2502 \u2022 Targets: [count] ([list key ones])
|
|
13228
|
-
\u2502 \u2022 Key Findings: [count] ([summarize top findings])
|
|
13229
|
-
\u2502 \u2022 Current Action: [what you were doing]
|
|
13230
|
-
\u2502 \u2022 Next Steps: [what you plan to do next]"
|
|
13231
|
-
\u2502 Then RESUME your previous work \u2014 do NOT stop after reporting.
|
|
13232
|
-
\u2502
|
|
13233
|
-
\u2514\u2500 STEP 8: Everything else \u2192 CONVERSATION
|
|
13234
|
-
Signals: greetings, questions, discussions, explanations, opinions,
|
|
13235
|
-
casual talk, "hello", "how does X work?", "explain Y"
|
|
13236
|
-
\u2192 CATEGORY: CONVERSATION
|
|
13237
|
-
\u2192 ACTION: Use \`ask_user\` to respond naturally and conversationally.
|
|
13238
|
-
Answer questions with your knowledge.
|
|
13239
|
-
Then ask if they want you to continue with the current task.
|
|
13240
|
-
Do NOT start any scans or attacks.
|
|
13241
|
-
`;
|
|
13242
|
-
|
|
13243
|
-
// src/agents/user-input/intent/resolution.ts
|
|
13244
|
-
var INTENT_RESOLUTION = `
|
|
13245
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13246
|
-
\xA72. MULTI-MESSAGE RESOLUTION
|
|
13247
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13248
|
-
|
|
13249
|
-
If multiple user messages are queued, process them as follows:
|
|
13250
|
-
1. Read ALL messages first to understand the full context.
|
|
13251
|
-
2. Later messages may OVERRIDE or CLARIFY earlier ones.
|
|
13252
|
-
Example: [1] "try brute force" \u2192 [2] "actually, skip brute force, try SQLi"
|
|
13253
|
-
\u2192 Only execute the SQLi instruction (message 2 overrides message 1).
|
|
13254
|
-
3. If messages are independent, process the HIGHEST PRIORITY category first
|
|
13255
|
-
(ABORT > CORRECTION > INFORMATION > COMMAND > TARGET > GUIDANCE > STATUS > CONVERSATION).
|
|
13256
|
-
4. Acknowledge all messages but act on the most recent directive.
|
|
13257
|
-
|
|
13258
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13259
|
-
\xA73. WORK RESUMPTION RULES
|
|
13260
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13261
|
-
|
|
13262
|
-
After handling the user's message, you MUST resume productive work:
|
|
13263
|
-
|
|
13264
|
-
\u251C\u2500 ABORT/CONVERSATION \u2192 Wait for next user instruction. Do NOT auto-resume.
|
|
13265
|
-
\u251C\u2500 STATUS_QUERY \u2192 Report status, then RESUME previous work in the same turn.
|
|
13266
|
-
\u251C\u2500 GUIDANCE/CORRECTION \u2192 Adjust plan, then CONTINUE with modified approach.
|
|
13267
|
-
\u251C\u2500 INFORMATION \u2192 USE the information immediately in your next action.
|
|
13268
|
-
\u251C\u2500 COMMAND \u2192 Execute the command. After completion, resume prior work.
|
|
13269
|
-
\u251C\u2500 TARGET_CHANGE \u2192 Switch to new target, begin fresh workflow.
|
|
13270
|
-
|
|
13271
|
-
KEY PRINCIPLE: Never leave a turn empty-handed.
|
|
13272
|
-
If you used \`ask_user\` to respond, you may ALSO call other tools in the same turn
|
|
13273
|
-
(except for ABORT and CONVERSATION categories).
|
|
13274
|
-
`;
|
|
13275
|
-
|
|
13276
|
-
// src/agents/user-input/intent/antipatterns.ts
|
|
13277
|
-
var INTENT_ANTIPATTERNS = `
|
|
13278
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13279
|
-
\xA74. ANTI-PATTERNS \u2014 NEVER DO THESE
|
|
13280
|
-
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
13281
|
-
|
|
13282
|
-
\u251C\u2500 \u274C Ignore the user's message and continue your previous plan
|
|
13283
|
-
\u251C\u2500 \u274C Start scanning/attacking after a greeting
|
|
13284
|
-
\u251C\u2500 \u274C Ask "should I use this?" when the user provides credentials \u2192 JUST USE THEM
|
|
13285
|
-
\u251C\u2500 \u274C Respond with only text (no tool call) \u2014 always use \`ask_user\` for responses
|
|
13286
|
-
\u251C\u2500 \u274C Stop all work after answering a status query \u2014 RESUME immediately
|
|
13287
|
-
\u251C\u2500 \u274C Add extra actions the user didn't ask for when handling a COMMAND
|
|
13288
|
-
\u251C\u2500 \u274C Repeat the same failed approach after a CORRECTION
|
|
13289
|
-
\u251C\u2500 \u274C Treat every input as an attack command \u2014 MOST inputs are collaborative
|
|
13290
|
-
\u251C\u2500 \u274C Apologize more than once for the same mistake \u2014 acknowledge once and fix it
|
|
13291
|
-
\u251C\u2500 \u274C Use the wrong value (typo/wrong target) AFTER the user corrected it
|
|
13292
|
-
\u2514\u2500 \u274C Ignore repeating corrections \u2014 if user says it twice, you missed it the first time
|
|
13293
|
-
</user-message>`;
|
|
13294
|
-
|
|
13295
|
-
// src/agents/user-input/intent/index.ts
|
|
13296
|
-
var USER_INPUT_INTENT_PROMPT = [
|
|
13297
|
-
INTENT_HEADER,
|
|
13298
|
-
INTENT_CLASSIFICATION,
|
|
13299
|
-
INTENT_RESOLUTION,
|
|
13300
|
-
INTENT_ANTIPATTERNS
|
|
13301
|
-
].join("\n");
|
|
13302
|
-
|
|
13303
13632
|
// src/agents/user-input/queue.ts
|
|
13304
13633
|
var MAX_QUEUE_ITEMS = 20;
|
|
13305
13634
|
var MAX_ITEM_CHARS = 500;
|
|
13306
|
-
var MAX_DRAIN_CHARS = 4e3;
|
|
13307
13635
|
function truncateText(text, max) {
|
|
13308
13636
|
if (text.length <= max) return text;
|
|
13309
13637
|
if (max <= 1) return text.slice(0, max);
|
|
@@ -13337,23 +13665,13 @@ var UserInputQueue = class {
|
|
|
13337
13665
|
return this.queue.length;
|
|
13338
13666
|
}
|
|
13339
13667
|
/**
|
|
13340
|
-
* Drain all queued inputs
|
|
13341
|
-
* Returns null if queue is empty.
|
|
13342
|
-
* Clears the queue after draining.
|
|
13668
|
+
* Drain all queued inputs as raw records.
|
|
13343
13669
|
*/
|
|
13344
|
-
|
|
13345
|
-
if (this.queue.length === 0) return
|
|
13670
|
+
drain() {
|
|
13671
|
+
if (this.queue.length === 0) return [];
|
|
13346
13672
|
const messages = [...this.queue];
|
|
13347
13673
|
this.queue = [];
|
|
13348
|
-
|
|
13349
|
-
const timeAgo = Math.round((Date.now() - m.timestamp) / 1e3);
|
|
13350
|
-
const timeLabel = timeAgo < RECENT_MESSAGE_THRESHOLD_SECONDS ? "just now" : `${timeAgo}s ago`;
|
|
13351
|
-
return `[${i + 1}] (${timeLabel}) "${truncateText(m.text, MAX_ITEM_CHARS)}"`;
|
|
13352
|
-
}).join("\n");
|
|
13353
|
-
return USER_INPUT_INTENT_PROMPT.replace(
|
|
13354
|
-
"<<USER_MESSAGES>>",
|
|
13355
|
-
truncateText(formattedMessages, MAX_DRAIN_CHARS)
|
|
13356
|
-
);
|
|
13674
|
+
return messages;
|
|
13357
13675
|
}
|
|
13358
13676
|
/**
|
|
13359
13677
|
* Peek at the queue without draining.
|
|
@@ -13431,32 +13749,36 @@ var MainAgent = class extends CoreAgent {
|
|
|
13431
13749
|
userInput = "";
|
|
13432
13750
|
turnCounter = 0;
|
|
13433
13751
|
userInputQueue = new UserInputQueue();
|
|
13752
|
+
pendingInitialUserInput = null;
|
|
13434
13753
|
pipelineRunner;
|
|
13435
13754
|
turnCyclePipeline;
|
|
13755
|
+
inputProcessor;
|
|
13756
|
+
sessionRuntime;
|
|
13436
13757
|
constructor(state, events, toolRegistry, approvalGate, scopeGuard) {
|
|
13437
13758
|
super(AGENT_ROLES.ORCHESTRATOR, state, events, toolRegistry);
|
|
13438
13759
|
this.approvalGate = approvalGate;
|
|
13439
13760
|
this.scopeGuard = scopeGuard;
|
|
13440
13761
|
this.promptBuilder = new PromptBuilder(state);
|
|
13441
13762
|
this.pipelineRunner = new PipelineRunner();
|
|
13763
|
+
this.inputProcessor = createInputProcessor(this.llm);
|
|
13764
|
+
this.sessionRuntime = createSessionRuntime();
|
|
13765
|
+
setActiveSessionRuntime(this.sessionRuntime);
|
|
13442
13766
|
const pipelineYaml = resolvePipelineYaml("pipeline.yaml");
|
|
13443
13767
|
this.turnCyclePipeline = loadPipeline(pipelineYaml, {
|
|
13444
13768
|
llm: this.llm,
|
|
13445
|
-
conditions: getConditionRegistry()
|
|
13446
|
-
|
|
13769
|
+
conditions: getConditionRegistry(),
|
|
13770
|
+
key: "turn_cycle"
|
|
13771
|
+
});
|
|
13447
13772
|
}
|
|
13448
13773
|
// ─── Lifecycle ─────────────────────────────────────────────────────────────
|
|
13449
13774
|
async execute(userInput) {
|
|
13450
|
-
this.userInput =
|
|
13451
|
-
this.
|
|
13452
|
-
|
|
13453
|
-
this.state.currentObjective = this.userInput.trim();
|
|
13454
|
-
}
|
|
13455
|
-
emitStart(this.events, this.userInput, this.state);
|
|
13775
|
+
this.userInput = "";
|
|
13776
|
+
this.pendingInitialUserInput = userInput;
|
|
13777
|
+
emitStart(this.events, userInput, this.state);
|
|
13456
13778
|
initializeTask(this.state);
|
|
13457
13779
|
try {
|
|
13458
13780
|
const initialPrompt = await this.buildDynamicPrompt({});
|
|
13459
|
-
const result = await this.run(
|
|
13781
|
+
const result = await this.run(userInput, initialPrompt);
|
|
13460
13782
|
return result.output;
|
|
13461
13783
|
} finally {
|
|
13462
13784
|
try {
|
|
@@ -13494,34 +13816,66 @@ var MainAgent = class extends CoreAgent {
|
|
|
13494
13816
|
isCompleted: !!ctx.memory.isCompleted
|
|
13495
13817
|
};
|
|
13496
13818
|
}
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
const
|
|
13511
|
-
if (
|
|
13512
|
-
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
} else {
|
|
13520
|
-
this.userInput = `${this.userInput}
|
|
13521
|
-
|
|
13522
|
-
${formatted}`;
|
|
13819
|
+
async processUserInputTurn() {
|
|
13820
|
+
const messages = this.collectPendingUserInputs();
|
|
13821
|
+
this.pendingInitialUserInput = null;
|
|
13822
|
+
if (messages.length === 0) {
|
|
13823
|
+
return { shouldForwardToMain: true };
|
|
13824
|
+
}
|
|
13825
|
+
const rawInput = messages.map((text, index) => `[${index + 1}] ${text}`).join("\n");
|
|
13826
|
+
const result = await this.inputProcessor.execute({
|
|
13827
|
+
rawInput,
|
|
13828
|
+
existingPolicy: readPolicyDocument(),
|
|
13829
|
+
hasActiveEngagement: this.state.hasActiveEngagement(),
|
|
13830
|
+
currentObjective: this.state.currentObjective || ""
|
|
13831
|
+
});
|
|
13832
|
+
const normalized = this.normalizeInputProcessorResult(result, rawInput);
|
|
13833
|
+
if (normalized.shouldWritePolicy && normalized.policyDocument.trim()) {
|
|
13834
|
+
writePolicyDocument(normalized.policyDocument);
|
|
13835
|
+
}
|
|
13836
|
+
if (normalized.shouldForwardToMain && normalized.forwardedInput.trim()) {
|
|
13837
|
+
this.userInput = this.appendUserInput(this.userInput, normalized.forwardedInput);
|
|
13838
|
+
if (!this.state.hasActiveEngagement()) {
|
|
13839
|
+
this.state.currentObjective = normalized.forwardedInput;
|
|
13840
|
+
}
|
|
13523
13841
|
}
|
|
13524
13842
|
this.events.emit({ type: EVENT_TYPES.QUEUE_DRAINED, timestamp: Date.now() });
|
|
13843
|
+
this.emitQueueUpdated();
|
|
13844
|
+
return normalized;
|
|
13845
|
+
}
|
|
13846
|
+
normalizeInputProcessorResult(result, fallbackInput) {
|
|
13847
|
+
if (!result.success) {
|
|
13848
|
+
return {
|
|
13849
|
+
shouldForwardToMain: true,
|
|
13850
|
+
forwardedInput: fallbackInput,
|
|
13851
|
+
directResponse: "",
|
|
13852
|
+
shouldWritePolicy: false,
|
|
13853
|
+
policyDocument: "",
|
|
13854
|
+
policyUpdateSummary: "",
|
|
13855
|
+
insightSummary: "Input processor fallback: forwarded raw input.",
|
|
13856
|
+
success: false
|
|
13857
|
+
};
|
|
13858
|
+
}
|
|
13859
|
+
return {
|
|
13860
|
+
...result,
|
|
13861
|
+
forwardedInput: result.forwardedInput.trim() || fallbackInput,
|
|
13862
|
+
directResponse: result.directResponse.trim(),
|
|
13863
|
+
policyDocument: result.policyDocument.trim(),
|
|
13864
|
+
policyUpdateSummary: result.policyUpdateSummary.trim(),
|
|
13865
|
+
insightSummary: result.insightSummary.trim()
|
|
13866
|
+
};
|
|
13867
|
+
}
|
|
13868
|
+
collectPendingUserInputs() {
|
|
13869
|
+
const drained = this.userInputQueue.drain();
|
|
13870
|
+
return [
|
|
13871
|
+
...this.pendingInitialUserInput ? [this.pendingInitialUserInput] : [],
|
|
13872
|
+
...drained.map((item) => item.text)
|
|
13873
|
+
].map((text) => text.trim()).filter(Boolean);
|
|
13874
|
+
}
|
|
13875
|
+
appendUserInput(existing, next) {
|
|
13876
|
+
return existing.trim() === "" ? next : `${existing}
|
|
13877
|
+
|
|
13878
|
+
${next}`;
|
|
13525
13879
|
}
|
|
13526
13880
|
async buildDynamicPrompt(memory) {
|
|
13527
13881
|
return this.promptBuilder.build(this.userInput, this.state.getPhase() || PHASES.RECON, memory);
|
|
@@ -13550,6 +13904,9 @@ ${formatted}`;
|
|
|
13550
13904
|
getEventEmitter() {
|
|
13551
13905
|
return this.events;
|
|
13552
13906
|
}
|
|
13907
|
+
getSessionRuntime() {
|
|
13908
|
+
return this.sessionRuntime;
|
|
13909
|
+
}
|
|
13553
13910
|
setScope(allowed, exclusions = []) {
|
|
13554
13911
|
this.state.setScope({
|
|
13555
13912
|
allowedCidrs: allowed.filter((a) => a.includes("/")),
|
|
@@ -13565,18 +13922,37 @@ ${formatted}`;
|
|
|
13565
13922
|
}
|
|
13566
13923
|
enqueueUserInput(text) {
|
|
13567
13924
|
this.userInputQueue.enqueue(text);
|
|
13925
|
+
this.emitQueueUpdated();
|
|
13568
13926
|
}
|
|
13569
13927
|
dequeueLastUserInput() {
|
|
13570
|
-
|
|
13928
|
+
const value = this.userInputQueue.dequeueLast();
|
|
13929
|
+
this.emitQueueUpdated();
|
|
13930
|
+
return value;
|
|
13571
13931
|
}
|
|
13572
13932
|
hasPendingUserInput() {
|
|
13573
13933
|
return this.userInputQueue.hasPending();
|
|
13574
13934
|
}
|
|
13935
|
+
getPendingUserInputCount() {
|
|
13936
|
+
return this.userInputQueue.pendingCount();
|
|
13937
|
+
}
|
|
13938
|
+
getPendingUserInputPreview() {
|
|
13939
|
+
return this.userInputQueue.peek().map((item) => item.text);
|
|
13940
|
+
}
|
|
13941
|
+
emitQueueUpdated() {
|
|
13942
|
+
this.events.emit({
|
|
13943
|
+
type: EVENT_TYPES.QUEUE_UPDATED,
|
|
13944
|
+
timestamp: Date.now(),
|
|
13945
|
+
data: {
|
|
13946
|
+
count: this.getPendingUserInputCount(),
|
|
13947
|
+
preview: this.getPendingUserInputPreview()
|
|
13948
|
+
}
|
|
13949
|
+
});
|
|
13950
|
+
}
|
|
13575
13951
|
};
|
|
13576
13952
|
|
|
13577
13953
|
// src/engine/yaml-runtime.ts
|
|
13578
|
-
import
|
|
13579
|
-
import
|
|
13954
|
+
import fs2 from "fs";
|
|
13955
|
+
import path3 from "path";
|
|
13580
13956
|
var YamlRuntime = class _YamlRuntime {
|
|
13581
13957
|
static build(state, events, toolRegistry, approvalGate, scopeGuard) {
|
|
13582
13958
|
const cfg = getPipelineConfig();
|
|
@@ -13584,14 +13960,15 @@ var YamlRuntime = class _YamlRuntime {
|
|
|
13584
13960
|
return new MainAgent(state, events, toolRegistry, approvalGate, scopeGuard);
|
|
13585
13961
|
}
|
|
13586
13962
|
static setupWorkspace(workspaceCfg) {
|
|
13587
|
-
const directories = workspaceCfg?.directories
|
|
13963
|
+
const directories = workspaceCfg?.directories ?? {};
|
|
13588
13964
|
for (const [key, dirPath] of Object.entries(directories)) {
|
|
13589
13965
|
if (dirPath === "DEPRECATED") continue;
|
|
13590
|
-
const resolved =
|
|
13591
|
-
if (!
|
|
13592
|
-
|
|
13966
|
+
const resolved = path3.resolve(process.cwd(), dirPath);
|
|
13967
|
+
if (!fs2.existsSync(resolved)) {
|
|
13968
|
+
fs2.mkdirSync(resolved, { recursive: true });
|
|
13593
13969
|
}
|
|
13594
13970
|
}
|
|
13971
|
+
ensurePolicyDocument();
|
|
13595
13972
|
}
|
|
13596
13973
|
};
|
|
13597
13974
|
|
|
@@ -13751,6 +14128,55 @@ var formatInlineStatus = () => {
|
|
|
13751
14128
|
return JSON.stringify(statusData);
|
|
13752
14129
|
};
|
|
13753
14130
|
|
|
14131
|
+
// src/platform/tui/utils/input-request-broker.ts
|
|
14132
|
+
function createInputRequestBrokerState() {
|
|
14133
|
+
return {
|
|
14134
|
+
active: { status: "inactive" },
|
|
14135
|
+
queue: []
|
|
14136
|
+
};
|
|
14137
|
+
}
|
|
14138
|
+
function sameRequest(a, b) {
|
|
14139
|
+
return a.prompt === b.prompt && a.inputType === b.inputType && a.context === b.context && a.source === b.source;
|
|
14140
|
+
}
|
|
14141
|
+
function sortQueue(queue) {
|
|
14142
|
+
return [...queue].sort((a, b) => b.priority - a.priority);
|
|
14143
|
+
}
|
|
14144
|
+
function enqueueInputRequest(state, request) {
|
|
14145
|
+
if (state.active.status === "inactive") {
|
|
14146
|
+
return {
|
|
14147
|
+
active: { status: "active", ...request },
|
|
14148
|
+
queue: []
|
|
14149
|
+
};
|
|
14150
|
+
}
|
|
14151
|
+
const existingIndex = state.queue.findIndex((item) => sameRequest(item, request));
|
|
14152
|
+
const nextQueue = existingIndex >= 0 ? state.queue.map((item, index) => index === existingIndex ? request : item) : [...state.queue, request];
|
|
14153
|
+
return {
|
|
14154
|
+
active: state.active,
|
|
14155
|
+
queue: sortQueue(nextQueue)
|
|
14156
|
+
};
|
|
14157
|
+
}
|
|
14158
|
+
function resolveActiveInputRequest(state) {
|
|
14159
|
+
const resolved = state.active;
|
|
14160
|
+
if (state.queue.length === 0) {
|
|
14161
|
+
return {
|
|
14162
|
+
resolved,
|
|
14163
|
+
nextState: { active: { status: "inactive" }, queue: [] }
|
|
14164
|
+
};
|
|
14165
|
+
}
|
|
14166
|
+
const [nextActive, ...rest] = sortQueue(state.queue);
|
|
14167
|
+
return {
|
|
14168
|
+
resolved,
|
|
14169
|
+
nextState: {
|
|
14170
|
+
active: { status: "active", ...nextActive },
|
|
14171
|
+
queue: rest
|
|
14172
|
+
}
|
|
14173
|
+
};
|
|
14174
|
+
}
|
|
14175
|
+
function clearAllInputRequests(state) {
|
|
14176
|
+
const pending = state.active.status === "active" ? [state.active, ...state.queue] : [...state.queue];
|
|
14177
|
+
return pending;
|
|
14178
|
+
}
|
|
14179
|
+
|
|
13754
14180
|
// src/platform/tui/hooks/useAgentState.ts
|
|
13755
14181
|
function sanitizeLiveProgress(progress) {
|
|
13756
14182
|
return {
|
|
@@ -13769,11 +14195,15 @@ var useAgentState = (isTyping = false) => {
|
|
|
13769
14195
|
const [elapsedTime, setElapsedTime] = useState(0);
|
|
13770
14196
|
const [retryState, setRetryState] = useState({ status: "idle" });
|
|
13771
14197
|
const [currentTokens, setCurrentTokens] = useState(0);
|
|
13772
|
-
const [
|
|
14198
|
+
const [inputBroker, setInputBroker] = useState(
|
|
14199
|
+
createInputRequestBrokerState()
|
|
14200
|
+
);
|
|
13773
14201
|
const [stats, setStats] = useState({ phase: DEFAULTS.INIT_PHASE, targets: 0, findings: 0, todo: 0, targetLabel: "" });
|
|
13774
14202
|
const [turnCount, setTurnCount] = useState(0);
|
|
13775
14203
|
const [liveProgressState, setLiveProgressState] = useState(DEFAULT_LIVE_PROGRESS);
|
|
13776
14204
|
const startTimeRef = useRef(0);
|
|
14205
|
+
const inputBrokerRef = useRef(createInputRequestBrokerState());
|
|
14206
|
+
inputBrokerRef.current = inputBroker;
|
|
13777
14207
|
const retryCountdownRef = useRef(null);
|
|
13778
14208
|
const retryCountRef = useRef(0);
|
|
13779
14209
|
const tokenAccumRef = useRef(0);
|
|
@@ -13824,6 +14254,21 @@ var useAgentState = (isTyping = false) => {
|
|
|
13824
14254
|
retryCountdownRef.current = null;
|
|
13825
14255
|
}
|
|
13826
14256
|
}, []);
|
|
14257
|
+
const enqueueInputRequest2 = useCallback((request) => {
|
|
14258
|
+
setInputBroker((prev) => enqueueInputRequest(prev, request));
|
|
14259
|
+
}, []);
|
|
14260
|
+
const settleActiveInputRequest = useCallback((value) => {
|
|
14261
|
+
const current = inputBrokerRef.current;
|
|
14262
|
+
if (current.active.status !== "active") return;
|
|
14263
|
+
current.active.resolve(value);
|
|
14264
|
+
setInputBroker(resolveActiveInputRequest(current).nextState);
|
|
14265
|
+
}, []);
|
|
14266
|
+
const cancelAllInputRequests = useCallback(() => {
|
|
14267
|
+
const current = inputBrokerRef.current;
|
|
14268
|
+
const pending = clearAllInputRequests(current);
|
|
14269
|
+
for (const request of pending) request.resolve(null);
|
|
14270
|
+
setInputBroker(createInputRequestBrokerState());
|
|
14271
|
+
}, []);
|
|
13827
14272
|
return {
|
|
13828
14273
|
// State
|
|
13829
14274
|
messages,
|
|
@@ -13837,8 +14282,8 @@ var useAgentState = (isTyping = false) => {
|
|
|
13837
14282
|
setRetryState,
|
|
13838
14283
|
currentTokens,
|
|
13839
14284
|
setCurrentTokens,
|
|
13840
|
-
inputRequest,
|
|
13841
|
-
|
|
14285
|
+
inputRequest: inputBroker.active,
|
|
14286
|
+
pendingInputRequests: inputBroker.queue.length,
|
|
13842
14287
|
stats,
|
|
13843
14288
|
setStats,
|
|
13844
14289
|
turnCount,
|
|
@@ -13857,7 +14302,10 @@ var useAgentState = (isTyping = false) => {
|
|
|
13857
14302
|
addMessage,
|
|
13858
14303
|
resetCumulativeCounters,
|
|
13859
14304
|
manageTimer,
|
|
13860
|
-
clearAllTimers
|
|
14305
|
+
clearAllTimers,
|
|
14306
|
+
enqueueInputRequest: enqueueInputRequest2,
|
|
14307
|
+
settleActiveInputRequest,
|
|
14308
|
+
cancelAllInputRequests
|
|
13861
14309
|
};
|
|
13862
14310
|
};
|
|
13863
14311
|
|
|
@@ -14220,7 +14668,7 @@ var AUXILIARY_STATUS_MAP = {
|
|
|
14220
14668
|
post_step: UI_STATUS_MESSAGES.AUXILIARY_POST_STEP,
|
|
14221
14669
|
turn_archive: UI_STATUS_MESSAGES.AUXILIARY_TURN_ARCHIVE,
|
|
14222
14670
|
turn_cycle: UI_STATUS_MESSAGES.AUXILIARY_TURN_CYCLE,
|
|
14223
|
-
|
|
14671
|
+
process_user_input: UI_STATUS_MESSAGES.AUXILIARY_DRAIN_INPUT,
|
|
14224
14672
|
strategist: UI_STATUS_MESSAGES.AUXILIARY_STRATEGIST,
|
|
14225
14673
|
build_system_prompt: UI_STATUS_MESSAGES.AUXILIARY_BUILD_PROMPT,
|
|
14226
14674
|
core_inference: UI_STATUS_MESSAGES.AUXILIARY_CORE_INFERENCE,
|
|
@@ -14421,50 +14869,63 @@ function createReasoningHandlers(state, reasoningBufferRef, isTyping = false) {
|
|
|
14421
14869
|
}
|
|
14422
14870
|
|
|
14423
14871
|
// src/platform/tui/hooks/useAgentEvents/handlers/input.ts
|
|
14424
|
-
|
|
14425
|
-
|
|
14872
|
+
var INPUT_REQUEST_PRIORITIES = {
|
|
14873
|
+
input_processor: 10,
|
|
14874
|
+
tool_prompt: 50,
|
|
14875
|
+
credential: 100
|
|
14876
|
+
};
|
|
14877
|
+
function buildRequestPayload(source, prompt, resolve, extra) {
|
|
14878
|
+
return {
|
|
14879
|
+
source,
|
|
14880
|
+
prompt,
|
|
14881
|
+
resolve,
|
|
14882
|
+
priority: INPUT_REQUEST_PRIORITIES[source],
|
|
14883
|
+
isPassword: extra.isPassword,
|
|
14884
|
+
inputType: extra.inputType,
|
|
14885
|
+
context: extra.context,
|
|
14886
|
+
optional: extra.optional,
|
|
14887
|
+
options: extra.options,
|
|
14888
|
+
placeholder: extra.placeholder
|
|
14889
|
+
};
|
|
14890
|
+
}
|
|
14891
|
+
function setupInputHandlers(runtime, enqueueInputRequest2, addMessage, setCurrentStatus) {
|
|
14892
|
+
runtime.setInputHandler((p) => {
|
|
14426
14893
|
return new Promise((resolve) => {
|
|
14427
14894
|
const isPassword = /password|passphrase/i.test(p);
|
|
14428
14895
|
const inputType = /sudo/i.test(p) ? INPUT_TYPES.SUDO_PASSWORD : isPassword ? INPUT_TYPES.PASSWORD : INPUT_TYPES.TEXT;
|
|
14429
14896
|
if (setCurrentStatus) setCurrentStatus("");
|
|
14430
14897
|
addMessage("ai", `${UI_ICONS.INPUT_LOCK} ${p.trim()}`);
|
|
14431
|
-
|
|
14432
|
-
status: "active",
|
|
14433
|
-
prompt: p.trim(),
|
|
14898
|
+
enqueueInputRequest2(buildRequestPayload("tool_prompt", p.trim(), resolve, {
|
|
14434
14899
|
isPassword,
|
|
14435
|
-
inputType
|
|
14436
|
-
|
|
14437
|
-
});
|
|
14900
|
+
inputType
|
|
14901
|
+
}));
|
|
14438
14902
|
});
|
|
14439
14903
|
});
|
|
14440
|
-
setCredentialHandler((request) => {
|
|
14904
|
+
runtime.setCredentialHandler((request) => {
|
|
14441
14905
|
return new Promise((resolve) => {
|
|
14442
14906
|
const isPassword = SENSITIVE_INPUT_TYPES.includes(request.type);
|
|
14443
14907
|
const displayPrompt = buildCredentialPrompt(request);
|
|
14444
14908
|
if (setCurrentStatus) setCurrentStatus("");
|
|
14445
14909
|
addMessage("ai", `${UI_ICONS.INPUT_LOCK} ${displayPrompt}`);
|
|
14446
|
-
|
|
14447
|
-
status: "active",
|
|
14448
|
-
prompt: displayPrompt,
|
|
14910
|
+
enqueueInputRequest2(buildRequestPayload("credential", displayPrompt, resolve, {
|
|
14449
14911
|
isPassword,
|
|
14450
14912
|
inputType: request.type,
|
|
14451
14913
|
context: request.context,
|
|
14452
14914
|
optional: request.isOptional,
|
|
14453
|
-
options: request.options
|
|
14454
|
-
|
|
14455
|
-
});
|
|
14915
|
+
options: request.options
|
|
14916
|
+
}));
|
|
14456
14917
|
});
|
|
14457
14918
|
});
|
|
14458
14919
|
return () => {
|
|
14459
|
-
clearInputHandler();
|
|
14460
|
-
clearCredentialHandler();
|
|
14920
|
+
runtime.clearInputHandler();
|
|
14921
|
+
runtime.clearCredentialHandler();
|
|
14461
14922
|
};
|
|
14462
14923
|
}
|
|
14463
14924
|
|
|
14464
14925
|
// src/platform/tui/hooks/useAgentEvents/handlers/command.ts
|
|
14465
|
-
function setupCommandHandlers(addMessage, setCurrentStatus) {
|
|
14926
|
+
function setupCommandHandlers(runtime, addMessage, setCurrentStatus) {
|
|
14466
14927
|
let lastStatusBase = "";
|
|
14467
|
-
setCommandEventEmitter((event) => {
|
|
14928
|
+
runtime.setCommandEventEmitter((event) => {
|
|
14468
14929
|
if (event.type === COMMAND_EVENT_TYPES.COMMAND_START) {
|
|
14469
14930
|
lastStatusBase = event.message;
|
|
14470
14931
|
setCurrentStatus(event.message);
|
|
@@ -14490,7 +14951,7 @@ ${UI_ICONS.LIVE_PREFIX}${cleanLine}`);
|
|
|
14490
14951
|
addMessage("system", msg);
|
|
14491
14952
|
});
|
|
14492
14953
|
return () => {
|
|
14493
|
-
clearCommandEventEmitter();
|
|
14954
|
+
runtime.clearCommandEventEmitter();
|
|
14494
14955
|
};
|
|
14495
14956
|
}
|
|
14496
14957
|
|
|
@@ -14500,7 +14961,7 @@ var useAgentEvents = (agent, eventsRef, state, isTyping = false) => {
|
|
|
14500
14961
|
addMessage,
|
|
14501
14962
|
setCurrentStatus,
|
|
14502
14963
|
setRetryState,
|
|
14503
|
-
|
|
14964
|
+
enqueueInputRequest: enqueueInputRequest2,
|
|
14504
14965
|
setStats,
|
|
14505
14966
|
setLiveProgress,
|
|
14506
14967
|
clearAllTimers,
|
|
@@ -14518,6 +14979,8 @@ var useAgentEvents = (agent, eventsRef, state, isTyping = false) => {
|
|
|
14518
14979
|
};
|
|
14519
14980
|
useEffect(() => {
|
|
14520
14981
|
const events = eventsRef.current;
|
|
14982
|
+
const runtime = agent.getSessionRuntime();
|
|
14983
|
+
setActiveSessionRuntime(runtime);
|
|
14521
14984
|
const toolHandlers = createToolHandlers({ addMessage, setCurrentStatus, setLiveProgress, toolStartedAtRef });
|
|
14522
14985
|
const lifecycleHandlers = createLifecycleHandlers(agent, {
|
|
14523
14986
|
addMessage,
|
|
@@ -14536,8 +14999,8 @@ var useAgentEvents = (agent, eventsRef, state, isTyping = false) => {
|
|
|
14536
14999
|
reasoningBufferRef,
|
|
14537
15000
|
isTyping
|
|
14538
15001
|
);
|
|
14539
|
-
const cleanupInput = setupInputHandlers(
|
|
14540
|
-
const cleanupCommand = setupCommandHandlers(addMessage, setCurrentStatus);
|
|
15002
|
+
const cleanupInput = setupInputHandlers(runtime, enqueueInputRequest2, addMessage, setCurrentStatus);
|
|
15003
|
+
const cleanupCommand = setupCommandHandlers(runtime, addMessage, setCurrentStatus);
|
|
14541
15004
|
const updateStats = () => {
|
|
14542
15005
|
const s = agent.getState();
|
|
14543
15006
|
setStats({
|
|
@@ -14589,6 +15052,7 @@ var useAgentEvents = (agent, eventsRef, state, isTyping = false) => {
|
|
|
14589
15052
|
clearAllTimers();
|
|
14590
15053
|
cleanupInput();
|
|
14591
15054
|
cleanupCommand();
|
|
15055
|
+
clearActiveSessionRuntime(runtime);
|
|
14592
15056
|
};
|
|
14593
15057
|
}, [
|
|
14594
15058
|
agent,
|
|
@@ -14596,7 +15060,7 @@ var useAgentEvents = (agent, eventsRef, state, isTyping = false) => {
|
|
|
14596
15060
|
setCurrentStatus,
|
|
14597
15061
|
setRetryState,
|
|
14598
15062
|
setCurrentTokens,
|
|
14599
|
-
|
|
15063
|
+
enqueueInputRequest2,
|
|
14600
15064
|
setStats,
|
|
14601
15065
|
setLiveProgress,
|
|
14602
15066
|
retryCountdownRef,
|
|
@@ -14611,6 +15075,11 @@ var useAgentEvents = (agent, eventsRef, state, isTyping = false) => {
|
|
|
14611
15075
|
};
|
|
14612
15076
|
|
|
14613
15077
|
// src/platform/tui/hooks/useAgent.ts
|
|
15078
|
+
function trimQueuedMessages(queue, maxLength, maxItems) {
|
|
15079
|
+
const trimmed = queue.map((text) => truncate(text, maxLength));
|
|
15080
|
+
if (trimmed.length <= maxItems) return trimmed;
|
|
15081
|
+
return trimmed.slice(trimmed.length - maxItems);
|
|
15082
|
+
}
|
|
14614
15083
|
var useAgent = (shouldAutoApprove, target, isTyping = false) => {
|
|
14615
15084
|
const [agent] = useState2(() => createMainAgent(shouldAutoApprove));
|
|
14616
15085
|
const eventsRef = useRef3(agent.getEventEmitter());
|
|
@@ -14626,7 +15095,7 @@ var useAgent = (shouldAutoApprove, target, isTyping = false) => {
|
|
|
14626
15095
|
retryState,
|
|
14627
15096
|
currentTokens,
|
|
14628
15097
|
inputRequest,
|
|
14629
|
-
|
|
15098
|
+
pendingInputRequests,
|
|
14630
15099
|
stats,
|
|
14631
15100
|
setStats,
|
|
14632
15101
|
addMessage,
|
|
@@ -14634,17 +15103,25 @@ var useAgent = (shouldAutoApprove, target, isTyping = false) => {
|
|
|
14634
15103
|
resetCumulativeCounters,
|
|
14635
15104
|
turnCount,
|
|
14636
15105
|
setTurnCount,
|
|
14637
|
-
liveProgress
|
|
15106
|
+
liveProgress,
|
|
15107
|
+
settleActiveInputRequest,
|
|
15108
|
+
cancelAllInputRequests
|
|
14638
15109
|
} = state;
|
|
14639
15110
|
const [messageQueue, setMessageQueue] = useState2([]);
|
|
15111
|
+
const messageQueueLengthRef = useRef3(0);
|
|
14640
15112
|
const setMessageQueueSafe = useCallback2((value) => {
|
|
14641
15113
|
setMessageQueue((prev) => {
|
|
14642
15114
|
const next = typeof value === "function" ? value(prev) : value;
|
|
14643
|
-
|
|
14644
|
-
|
|
14645
|
-
|
|
15115
|
+
return trimQueuedMessages(
|
|
15116
|
+
next,
|
|
15117
|
+
TUI_DISPLAY_LIMITS.QUEUED_MESSAGE_TEXT_MAX,
|
|
15118
|
+
TUI_DISPLAY_LIMITS.MAX_QUEUED_MESSAGES
|
|
15119
|
+
);
|
|
14646
15120
|
});
|
|
14647
15121
|
}, []);
|
|
15122
|
+
useEffect2(() => {
|
|
15123
|
+
messageQueueLengthRef.current = messageQueue.length;
|
|
15124
|
+
}, [messageQueue.length]);
|
|
14648
15125
|
useEffect2(() => {
|
|
14649
15126
|
if (target) {
|
|
14650
15127
|
agent.addTarget(target);
|
|
@@ -14652,19 +15129,22 @@ var useAgent = (shouldAutoApprove, target, isTyping = false) => {
|
|
|
14652
15129
|
}
|
|
14653
15130
|
}, [agent, target]);
|
|
14654
15131
|
useEffect2(() => {
|
|
15132
|
+
const handleQueueUpdated = (event) => {
|
|
15133
|
+
setMessageQueueSafe(event.data.preview);
|
|
15134
|
+
};
|
|
14655
15135
|
const handleQueueDrained = () => {
|
|
14656
|
-
|
|
14657
|
-
|
|
14658
|
-
|
|
14659
|
-
}
|
|
14660
|
-
return [];
|
|
14661
|
-
});
|
|
15136
|
+
if (messageQueueLengthRef.current > 0) {
|
|
15137
|
+
addMessage("system", `Queued input applied (${messageQueueLengthRef.current})`);
|
|
15138
|
+
}
|
|
14662
15139
|
};
|
|
15140
|
+
setMessageQueueSafe(agent.getPendingUserInputPreview());
|
|
15141
|
+
agent.getEventEmitter().on(EVENT_TYPES.QUEUE_UPDATED, handleQueueUpdated);
|
|
14663
15142
|
agent.getEventEmitter().on(EVENT_TYPES.QUEUE_DRAINED, handleQueueDrained);
|
|
14664
15143
|
return () => {
|
|
15144
|
+
agent.getEventEmitter().off(EVENT_TYPES.QUEUE_UPDATED, handleQueueUpdated);
|
|
14665
15145
|
agent.getEventEmitter().off(EVENT_TYPES.QUEUE_DRAINED, handleQueueDrained);
|
|
14666
15146
|
};
|
|
14667
|
-
}, [agent,
|
|
15147
|
+
}, [agent, addMessage, setMessageQueueSafe]);
|
|
14668
15148
|
useAgentEvents(agent, eventsRef, state, isTyping);
|
|
14669
15149
|
const abortedRef = useRef3(false);
|
|
14670
15150
|
const executeTask = useCallback2(async (task) => {
|
|
@@ -14689,7 +15169,6 @@ var useAgent = (shouldAutoApprove, target, isTyping = false) => {
|
|
|
14689
15169
|
}
|
|
14690
15170
|
if (agent.hasPendingUserInput()) {
|
|
14691
15171
|
currentTask = "";
|
|
14692
|
-
setMessageQueueSafe([]);
|
|
14693
15172
|
continuing = true;
|
|
14694
15173
|
continue;
|
|
14695
15174
|
}
|
|
@@ -14721,24 +15200,21 @@ var useAgent = (shouldAutoApprove, target, isTyping = false) => {
|
|
|
14721
15200
|
manageTimer("stop");
|
|
14722
15201
|
setCurrentStatus("");
|
|
14723
15202
|
addMessage("system", UI_MESSAGES.INTERRUPTED);
|
|
14724
|
-
|
|
14725
|
-
}, [agent, addMessage, manageTimer, setIsProcessing, setCurrentStatus, setMessageQueueSafe]);
|
|
15203
|
+
}, [agent, addMessage, manageTimer, setIsProcessing, setCurrentStatus]);
|
|
14726
15204
|
const recallQueuedInput = useCallback2(() => {
|
|
14727
15205
|
const recalled = agent.dequeueLastUserInput();
|
|
14728
15206
|
if (!recalled) return null;
|
|
14729
|
-
setMessageQueueSafe((prev) => prev.length > 0 ? prev.slice(0, -1) : prev);
|
|
14730
15207
|
return recalled;
|
|
14731
|
-
}, [agent
|
|
15208
|
+
}, [agent]);
|
|
14732
15209
|
const inputRequestRef = useRef3(inputRequest);
|
|
14733
15210
|
inputRequestRef.current = inputRequest;
|
|
14734
15211
|
const cancelInputRequest = useCallback2(() => {
|
|
14735
15212
|
const ir = inputRequestRef.current;
|
|
14736
15213
|
if (ir.status === "active") {
|
|
14737
|
-
|
|
14738
|
-
setInputRequest({ status: "inactive" });
|
|
15214
|
+
settleActiveInputRequest(null);
|
|
14739
15215
|
addMessage("system", UI_MESSAGES.INPUT_CANCELLED);
|
|
14740
15216
|
}
|
|
14741
|
-
}, [
|
|
15217
|
+
}, [settleActiveInputRequest, addMessage]);
|
|
14742
15218
|
const refreshStats = useCallback2(() => {
|
|
14743
15219
|
const s = agent.getState();
|
|
14744
15220
|
setStats({
|
|
@@ -14761,15 +15237,16 @@ var useAgent = (shouldAutoApprove, target, isTyping = false) => {
|
|
|
14761
15237
|
currentTokens,
|
|
14762
15238
|
liveProgress,
|
|
14763
15239
|
inputRequest,
|
|
14764
|
-
|
|
15240
|
+
pendingInputRequests,
|
|
14765
15241
|
stats,
|
|
14766
15242
|
turnCount,
|
|
14767
15243
|
messageQueue,
|
|
14768
|
-
setMessageQueue: setMessageQueueSafe,
|
|
14769
15244
|
recallQueuedInput,
|
|
14770
15245
|
executeTask,
|
|
14771
15246
|
abort,
|
|
14772
15247
|
cancelInputRequest,
|
|
15248
|
+
settleActiveInputRequest,
|
|
15249
|
+
cancelAllInputRequests,
|
|
14773
15250
|
addMessage,
|
|
14774
15251
|
refreshStats
|
|
14775
15252
|
};
|
|
@@ -15556,15 +16033,16 @@ var useAppLogic = ({ autoApprove = false, target }) => {
|
|
|
15556
16033
|
currentTokens,
|
|
15557
16034
|
liveProgress = DEFAULT_LIVE_PROGRESS,
|
|
15558
16035
|
inputRequest,
|
|
15559
|
-
|
|
16036
|
+
pendingInputRequests,
|
|
15560
16037
|
stats,
|
|
15561
16038
|
turnCount,
|
|
15562
16039
|
messageQueue,
|
|
15563
|
-
setMessageQueue,
|
|
15564
16040
|
recallQueuedInput,
|
|
15565
16041
|
executeTask,
|
|
15566
16042
|
abort,
|
|
15567
16043
|
cancelInputRequest,
|
|
16044
|
+
settleActiveInputRequest,
|
|
16045
|
+
cancelAllInputRequests,
|
|
15568
16046
|
addMessage,
|
|
15569
16047
|
refreshStats
|
|
15570
16048
|
} = useAgent(autoApproveMode, target, isTyping);
|
|
@@ -15597,16 +16075,12 @@ var useAppLogic = ({ autoApprove = false, target }) => {
|
|
|
15597
16075
|
});
|
|
15598
16076
|
}, [terminalHeight]);
|
|
15599
16077
|
const handleExit = useCallback7(() => {
|
|
15600
|
-
|
|
15601
|
-
if (ir.status === "active") {
|
|
15602
|
-
ir.resolve(null);
|
|
15603
|
-
setInputRequest({ status: "inactive" });
|
|
15604
|
-
}
|
|
16078
|
+
cancelAllInputRequests();
|
|
15605
16079
|
cleanupAllProcesses().catch(() => {
|
|
15606
16080
|
});
|
|
15607
16081
|
exit();
|
|
15608
16082
|
setTimeout(() => process.exit(0), DISPLAY_LIMITS.EXIT_DELAY);
|
|
15609
|
-
}, [exit,
|
|
16083
|
+
}, [exit, cancelAllInputRequests]);
|
|
15610
16084
|
const { handleCommand } = useCommands({
|
|
15611
16085
|
agent,
|
|
15612
16086
|
addMessage,
|
|
@@ -15630,10 +16104,9 @@ var useAppLogic = ({ autoApprove = false, target }) => {
|
|
|
15630
16104
|
const sanitized = sanitizeInput(value).slice(0, TUI_DISPLAY_LIMITS.MAX_INPUT_CHARS);
|
|
15631
16105
|
const displayText = ir.isPassword ? "\u2022".repeat(Math.min(sanitized.length, TUI_DISPLAY_LIMITS.PASSWORD_MASK_MAX)) : sanitized;
|
|
15632
16106
|
addMessage("user", displayText);
|
|
15633
|
-
|
|
15634
|
-
setInputRequest({ status: "inactive" });
|
|
16107
|
+
settleActiveInputRequest(sanitized);
|
|
15635
16108
|
setSecretInput("");
|
|
15636
|
-
}, [addMessage,
|
|
16109
|
+
}, [addMessage, settleActiveInputRequest]);
|
|
15637
16110
|
const handleSubmit = useCallback7(async (value) => {
|
|
15638
16111
|
const trimmed = sanitizeInput(value);
|
|
15639
16112
|
if (!trimmed) return;
|
|
@@ -15650,10 +16123,8 @@ var useAppLogic = ({ autoApprove = false, target }) => {
|
|
|
15650
16123
|
handleSecretSubmit(safeInput);
|
|
15651
16124
|
} else if (isProcessingRef.current) {
|
|
15652
16125
|
agent.enqueueUserInput(safeInput);
|
|
15653
|
-
setMessageQueue((prev) => [...prev, safeInput]);
|
|
15654
16126
|
} else {
|
|
15655
16127
|
addMessage("user", safeInput);
|
|
15656
|
-
setMessageQueue([]);
|
|
15657
16128
|
await executeTask(safeInput);
|
|
15658
16129
|
}
|
|
15659
16130
|
}, [agent, addMessage, executeTask, handleCommand, handleSecretSubmit]);
|
|
@@ -15690,6 +16161,7 @@ var useAppLogic = ({ autoApprove = false, target }) => {
|
|
|
15690
16161
|
currentTokens,
|
|
15691
16162
|
liveProgress,
|
|
15692
16163
|
inputRequest,
|
|
16164
|
+
pendingInputRequests,
|
|
15693
16165
|
stats,
|
|
15694
16166
|
turnCount,
|
|
15695
16167
|
messageQueue,
|
|
@@ -16327,11 +16799,115 @@ import { Box as Box8, Text as Text8 } from "ink";
|
|
|
16327
16799
|
// src/platform/tui/components/BlinkingCircle.tsx
|
|
16328
16800
|
import { memo as memo7 } from "react";
|
|
16329
16801
|
import { Text as Text7 } from "ink";
|
|
16802
|
+
|
|
16803
|
+
// src/platform/tui/utils/animation-style.ts
|
|
16804
|
+
var DOCKER_BLUE = "#0db7ed";
|
|
16805
|
+
var DOCKER_BLUE_DARK = "#2496ed";
|
|
16806
|
+
var BLINKING_CIRCLE_PHASE_LENGTH = 8;
|
|
16807
|
+
var BLINKING_CIRCLE_SOLID_PHASE = 4;
|
|
16808
|
+
var SPLASH_PULSE_PERIOD_DIVISOR = 10;
|
|
16809
|
+
var SPLASH_PULSE_BOLD_THRESHOLD = 0.55;
|
|
16810
|
+
var SPLASH_PULSE_DIM_THRESHOLD = 0.3;
|
|
16811
|
+
var SPLASH_PULSE_BRIGHT_THRESHOLD = 0.65;
|
|
16812
|
+
var SPLASH_PULSE_MID_THRESHOLD = 0.4;
|
|
16813
|
+
var SHIMMER_COLOR_STEPS = 64;
|
|
16814
|
+
var COIN_FRAME_FIXED_WIDTH = 40;
|
|
16815
|
+
function getBlinkingCircleFrame(tick, activeColor = THEME.primary) {
|
|
16816
|
+
const phase = tick % BLINKING_CIRCLE_PHASE_LENGTH;
|
|
16817
|
+
const isSolid = phase < BLINKING_CIRCLE_SOLID_PHASE;
|
|
16818
|
+
return {
|
|
16819
|
+
glyph: isSolid ? "\u25CF" : "\u25CC",
|
|
16820
|
+
color: isSolid ? activeColor : THEME.cyan,
|
|
16821
|
+
bold: isSolid,
|
|
16822
|
+
dimColor: !isSolid
|
|
16823
|
+
};
|
|
16824
|
+
}
|
|
16825
|
+
function normalizeFrameLines(frame) {
|
|
16826
|
+
const width = COIN_FRAME_FIXED_WIDTH;
|
|
16827
|
+
return {
|
|
16828
|
+
width,
|
|
16829
|
+
// Center each line within the fixed width
|
|
16830
|
+
lines: frame.map((line) => {
|
|
16831
|
+
const trimmed = line.trimEnd();
|
|
16832
|
+
const padding = Math.floor((width - trimmed.length) / 2);
|
|
16833
|
+
const leftPad = " ".repeat(Math.max(0, padding));
|
|
16834
|
+
const rightPad = " ".repeat(Math.max(0, width - trimmed.length - padding));
|
|
16835
|
+
return leftPad + trimmed + rightPad;
|
|
16836
|
+
})
|
|
16837
|
+
};
|
|
16838
|
+
}
|
|
16839
|
+
function hslToHex(h, s, l) {
|
|
16840
|
+
const a = s * Math.min(l, 1 - l);
|
|
16841
|
+
const f = (n) => {
|
|
16842
|
+
const k = (n + h / 30) % 12;
|
|
16843
|
+
const c = l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
|
|
16844
|
+
return Math.round(255 * c).toString(16).padStart(2, "0");
|
|
16845
|
+
};
|
|
16846
|
+
return `#${f(0)}${f(8)}${f(4)}`;
|
|
16847
|
+
}
|
|
16848
|
+
function coinHue(tick) {
|
|
16849
|
+
const t = (Math.sin(tick * (Math.PI / 960)) + 1) / 2;
|
|
16850
|
+
return hslToHex(197 + t * 15, 0.85, 0.45 + t * 0.15);
|
|
16851
|
+
}
|
|
16852
|
+
function getSplashPulseTone(tick) {
|
|
16853
|
+
const pulse = (Math.sin(tick * (Math.PI / SPLASH_PULSE_PERIOD_DIVISOR)) + 1) / 2;
|
|
16854
|
+
return {
|
|
16855
|
+
bold: pulse > SPLASH_PULSE_BOLD_THRESHOLD,
|
|
16856
|
+
dimColor: pulse < SPLASH_PULSE_DIM_THRESHOLD,
|
|
16857
|
+
color: pulse > SPLASH_PULSE_BRIGHT_THRESHOLD ? "#ffffff" : pulse > SPLASH_PULSE_MID_THRESHOLD ? DOCKER_BLUE : DOCKER_BLUE_DARK
|
|
16858
|
+
// #2496ed
|
|
16859
|
+
};
|
|
16860
|
+
}
|
|
16861
|
+
function lerp(a, b, t) {
|
|
16862
|
+
return Math.round(a + (b - a) * t);
|
|
16863
|
+
}
|
|
16864
|
+
function hexToRgb(hex) {
|
|
16865
|
+
return [
|
|
16866
|
+
parseInt(hex.slice(1, 3), 16),
|
|
16867
|
+
parseInt(hex.slice(3, 5), 16),
|
|
16868
|
+
parseInt(hex.slice(5, 7), 16)
|
|
16869
|
+
];
|
|
16870
|
+
}
|
|
16871
|
+
function rgbToHex([r, g, b]) {
|
|
16872
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
16873
|
+
}
|
|
16874
|
+
function buildNeutralShimmerPalette() {
|
|
16875
|
+
return Array.from({ length: SHIMMER_COLOR_STEPS }, (_, i) => {
|
|
16876
|
+
const t = i / (SHIMMER_COLOR_STEPS - 1);
|
|
16877
|
+
const v = Math.round(88 + t * (255 - 88));
|
|
16878
|
+
const h = v.toString(16).padStart(2, "0");
|
|
16879
|
+
return `#${h}${h}${h}`;
|
|
16880
|
+
});
|
|
16881
|
+
}
|
|
16882
|
+
function buildAccentShimmerPalette() {
|
|
16883
|
+
const accentStart = hexToRgb(DOCKER_BLUE_DARK);
|
|
16884
|
+
const accentMid = hexToRgb(DOCKER_BLUE);
|
|
16885
|
+
const accentPeak = hexToRgb("#ffffff");
|
|
16886
|
+
return Array.from({ length: SHIMMER_COLOR_STEPS }, (_, i) => {
|
|
16887
|
+
const t = i / (SHIMMER_COLOR_STEPS - 1);
|
|
16888
|
+
if (t < 0.6) {
|
|
16889
|
+
const local2 = t / 0.6;
|
|
16890
|
+
return rgbToHex([
|
|
16891
|
+
lerp(accentStart[0], accentMid[0], local2),
|
|
16892
|
+
lerp(accentStart[1], accentMid[1], local2),
|
|
16893
|
+
lerp(accentStart[2], accentMid[2], local2)
|
|
16894
|
+
]);
|
|
16895
|
+
}
|
|
16896
|
+
const local = (t - 0.6) / 0.4;
|
|
16897
|
+
return rgbToHex([
|
|
16898
|
+
lerp(accentMid[0], accentPeak[0], local),
|
|
16899
|
+
lerp(accentMid[1], accentPeak[1], local),
|
|
16900
|
+
lerp(accentMid[2], accentPeak[2], local)
|
|
16901
|
+
]);
|
|
16902
|
+
});
|
|
16903
|
+
}
|
|
16904
|
+
|
|
16905
|
+
// src/platform/tui/components/BlinkingCircle.tsx
|
|
16330
16906
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
16331
16907
|
var BlinkingCircle = memo7(({ color }) => {
|
|
16332
16908
|
const tick = useAnimationTick();
|
|
16333
|
-
const
|
|
16334
|
-
return /* @__PURE__ */ jsx9(Text7, { color: color
|
|
16909
|
+
const frame = getBlinkingCircleFrame(tick, color);
|
|
16910
|
+
return /* @__PURE__ */ jsx9(Text7, { color: frame.color, bold: frame.bold, dimColor: frame.dimColor, children: frame.glyph });
|
|
16335
16911
|
});
|
|
16336
16912
|
|
|
16337
16913
|
// src/platform/tui/components/status/RetryView.tsx
|
|
@@ -16356,22 +16932,23 @@ import { memo as memo8, useMemo as useMemo2 } from "react";
|
|
|
16356
16932
|
import { Text as Text9 } from "ink";
|
|
16357
16933
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
16358
16934
|
var SPOT_WIDTH = 6;
|
|
16359
|
-
var SWEEP_SPEED =
|
|
16935
|
+
var SWEEP_SPEED = 1.5;
|
|
16360
16936
|
var LOOP_PAD = SPOT_WIDTH * 2;
|
|
16361
16937
|
var TICK_WRAP = 1e6;
|
|
16362
|
-
var
|
|
16363
|
-
var
|
|
16364
|
-
const t = i / (COLOR_STEPS - 1);
|
|
16365
|
-
const v = Math.round(88 + t * (255 - 88));
|
|
16366
|
-
const h = v.toString(16).padStart(2, "0");
|
|
16367
|
-
return `#${h}${h}${h}`;
|
|
16368
|
-
});
|
|
16938
|
+
var NEUTRAL_PALETTE = buildNeutralShimmerPalette();
|
|
16939
|
+
var ACCENT_PALETTE = buildAccentShimmerPalette();
|
|
16369
16940
|
function gaussian(x, sigma) {
|
|
16370
16941
|
return Math.exp(-(x * x) / (2 * sigma * sigma));
|
|
16371
16942
|
}
|
|
16372
|
-
var ShimmerText = memo8(({
|
|
16943
|
+
var ShimmerText = memo8(({
|
|
16944
|
+
children,
|
|
16945
|
+
bold,
|
|
16946
|
+
phase = 0,
|
|
16947
|
+
variant = "neutral"
|
|
16948
|
+
}) => {
|
|
16373
16949
|
const tick = useAnimationTick() % TICK_WRAP;
|
|
16374
16950
|
const len = children.length;
|
|
16951
|
+
const palette = variant === "accent" ? ACCENT_PALETTE : NEUTRAL_PALETTE;
|
|
16375
16952
|
const chars = useMemo2(() => Array.from(children), [children]);
|
|
16376
16953
|
const loopLen = len + LOOP_PAD;
|
|
16377
16954
|
const rawPos = (tick * SWEEP_SPEED + phase * loopLen) % loopLen;
|
|
@@ -16380,8 +16957,8 @@ var ShimmerText = memo8(({ children, bold, phase = 0 }) => {
|
|
|
16380
16957
|
return /* @__PURE__ */ jsx11(Text9, { bold, children: chars.map((char, i) => {
|
|
16381
16958
|
const dist = Math.abs(i - spotPos);
|
|
16382
16959
|
const brightness = gaussian(dist, sigma);
|
|
16383
|
-
const idx = Math.min(
|
|
16384
|
-
const color =
|
|
16960
|
+
const idx = Math.min(SHIMMER_COLOR_STEPS - 1, Math.floor(brightness * SHIMMER_COLOR_STEPS));
|
|
16961
|
+
const color = palette[idx];
|
|
16385
16962
|
return /* @__PURE__ */ jsx11(Text9, { color, children: char }, i);
|
|
16386
16963
|
}) });
|
|
16387
16964
|
});
|
|
@@ -16420,7 +16997,7 @@ var ProcessingView = ({
|
|
|
16420
16997
|
return /* @__PURE__ */ jsxs8(Box9, { flexDirection: "column", children: [
|
|
16421
16998
|
/* @__PURE__ */ jsxs8(Box9, { children: [
|
|
16422
16999
|
/* @__PURE__ */ jsx12(Box9, { width: 2, flexShrink: 0, children: isActive ? /* @__PURE__ */ jsx12(BlinkingCircle, { color }) : /* @__PURE__ */ jsx12(Text10, { color: THEME.dimGray, children: "\u2022" }) }),
|
|
16423
|
-
isActive ? /* @__PURE__ */ jsx12(ShimmerText, { bold: true, children: stageText }) : /* @__PURE__ */ jsx12(Text10, { bold: true, color: stageColor, children: stageText }),
|
|
17000
|
+
isActive ? /* @__PURE__ */ jsx12(ShimmerText, { bold: true, variant: "accent", children: stageText }) : /* @__PURE__ */ jsx12(Text10, { bold: true, color: stageColor, children: stageText }),
|
|
16424
17001
|
/* @__PURE__ */ jsxs8(Text10, { color: THEME.dimGray, dimColor: true, wrap: "truncate", children: [
|
|
16425
17002
|
" ",
|
|
16426
17003
|
metaSuffix
|
|
@@ -16665,6 +17242,7 @@ var SimpleTextInput = ({
|
|
|
16665
17242
|
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
16666
17243
|
var SecretInputArea = ({
|
|
16667
17244
|
inputRequest,
|
|
17245
|
+
pendingCount = 0,
|
|
16668
17246
|
secretInput,
|
|
16669
17247
|
setSecretInput,
|
|
16670
17248
|
onSecretSubmit
|
|
@@ -16677,7 +17255,8 @@ var SecretInputArea = ({
|
|
|
16677
17255
|
children: [
|
|
16678
17256
|
/* @__PURE__ */ jsxs11(Box12, { children: [
|
|
16679
17257
|
/* @__PURE__ */ jsx16(Text13, { color: THEME.yellow, children: "secure input" }),
|
|
16680
|
-
/* @__PURE__ */ jsx16(Text13, { color: THEME.gray, dimColor: true, children: " hidden in transcript" })
|
|
17258
|
+
/* @__PURE__ */ jsx16(Text13, { color: THEME.gray, dimColor: true, children: " hidden in transcript" }),
|
|
17259
|
+
pendingCount > 0 && /* @__PURE__ */ jsx16(Text13, { color: THEME.gray, dimColor: true, children: ` ${pendingCount} waiting` })
|
|
16681
17260
|
] }),
|
|
16682
17261
|
/* @__PURE__ */ jsxs11(Box12, { flexDirection: "row", children: [
|
|
16683
17262
|
/* @__PURE__ */ jsx16(Box12, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx16(Text13, { color: THEME.yellow, children: "!" }) }),
|
|
@@ -16749,6 +17328,7 @@ var ChatInput = memo10(({
|
|
|
16749
17328
|
queuedPreview = "",
|
|
16750
17329
|
placeholder,
|
|
16751
17330
|
inputRequest,
|
|
17331
|
+
pendingInputCount = 0,
|
|
16752
17332
|
secretInput,
|
|
16753
17333
|
setSecretInput,
|
|
16754
17334
|
onSecretSubmit
|
|
@@ -16879,6 +17459,7 @@ var ChatInput = memo10(({
|
|
|
16879
17459
|
SecretInputArea,
|
|
16880
17460
|
{
|
|
16881
17461
|
inputRequest,
|
|
17462
|
+
pendingCount: pendingInputCount,
|
|
16882
17463
|
secretInput,
|
|
16883
17464
|
setSecretInput: handleSecretChange,
|
|
16884
17465
|
onSecretSubmit: wrappedSecretSubmit
|
|
@@ -17081,6 +17662,7 @@ var BottomRegion = ({
|
|
|
17081
17662
|
recallQueuedInput,
|
|
17082
17663
|
handleSubmit,
|
|
17083
17664
|
inputRequest,
|
|
17665
|
+
pendingInputRequests,
|
|
17084
17666
|
secretInput,
|
|
17085
17667
|
setSecretInput,
|
|
17086
17668
|
handleSecretSubmit,
|
|
@@ -17121,11 +17703,13 @@ var BottomRegion = ({
|
|
|
17121
17703
|
queuedPreview,
|
|
17122
17704
|
placeholder: "Describe the target or type /help",
|
|
17123
17705
|
inputRequest,
|
|
17706
|
+
pendingInputCount: pendingInputRequests,
|
|
17124
17707
|
secretInput,
|
|
17125
17708
|
setSecretInput,
|
|
17126
17709
|
onSecretSubmit: handleSecretSubmit
|
|
17127
17710
|
}
|
|
17128
17711
|
) }),
|
|
17712
|
+
/* @__PURE__ */ jsx21(Box17, { width: "100%", children: /* @__PURE__ */ jsx21(Text18, { dimColor: true, color: THEME.dimGray, children: "\u2500".repeat(Math.max(1, columns - 2)) }) }),
|
|
17129
17713
|
/* @__PURE__ */ jsx21(Box17, { width: "100%", children: /* @__PURE__ */ jsx21(
|
|
17130
17714
|
footer_default,
|
|
17131
17715
|
{
|
|
@@ -17210,6 +17794,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
17210
17794
|
currentTokens,
|
|
17211
17795
|
liveProgress,
|
|
17212
17796
|
inputRequest,
|
|
17797
|
+
pendingInputRequests,
|
|
17213
17798
|
stats,
|
|
17214
17799
|
turnCount,
|
|
17215
17800
|
messageQueue,
|
|
@@ -17250,6 +17835,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
17250
17835
|
recallQueuedInput: handleRecallQueuedInput,
|
|
17251
17836
|
handleSubmit,
|
|
17252
17837
|
inputRequest,
|
|
17838
|
+
pendingInputRequests,
|
|
17253
17839
|
secretInput,
|
|
17254
17840
|
setSecretInput,
|
|
17255
17841
|
handleSecretSubmit,
|
|
@@ -17964,19 +18550,6 @@ var COIN_FRAMES = [
|
|
|
17964
18550
|
|
|
17965
18551
|
// src/platform/tui/components/SplashScreen.tsx
|
|
17966
18552
|
import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
17967
|
-
function hslToHex(h, s, l) {
|
|
17968
|
-
const a = s * Math.min(l, 1 - l);
|
|
17969
|
-
const f = (n) => {
|
|
17970
|
-
const k = (n + h / 30) % 12;
|
|
17971
|
-
const c = l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
|
|
17972
|
-
return Math.round(255 * c).toString(16).padStart(2, "0");
|
|
17973
|
-
};
|
|
17974
|
-
return `#${f(0)}${f(8)}${f(4)}`;
|
|
17975
|
-
}
|
|
17976
|
-
function coinHue(tick) {
|
|
17977
|
-
const t = (Math.sin(tick * (Math.PI / 960)) + 1) / 2;
|
|
17978
|
-
return hslToHex(210 * (1 - t), 0.85, 0.55);
|
|
17979
|
-
}
|
|
17980
18553
|
var SplashScreen = ({
|
|
17981
18554
|
onComplete,
|
|
17982
18555
|
durationMs = 3e3
|
|
@@ -17998,7 +18571,9 @@ var SplashScreen = ({
|
|
|
17998
18571
|
return () => clearInterval(interval);
|
|
17999
18572
|
}, [durationMs, onComplete]);
|
|
18000
18573
|
const frame = COIN_FRAMES[tick % COIN_FRAMES.length];
|
|
18574
|
+
const normalizedFrame = normalizeFrameLines(frame);
|
|
18001
18575
|
const coinColor = coinHue(tick);
|
|
18576
|
+
const titleTone = getSplashPulseTone(tick);
|
|
18002
18577
|
const isFading = elapsed > durationMs - 500;
|
|
18003
18578
|
return /* @__PURE__ */ jsx23(
|
|
18004
18579
|
Box19,
|
|
@@ -18009,10 +18584,19 @@ var SplashScreen = ({
|
|
|
18009
18584
|
alignItems: "center",
|
|
18010
18585
|
justifyContent: "center",
|
|
18011
18586
|
children: /* @__PURE__ */ jsxs18(Box19, { flexDirection: "column", alignItems: "center", flexShrink: 0, children: [
|
|
18012
|
-
/* @__PURE__ */ jsx23(Box19, { flexDirection: "column", alignItems: "center", children:
|
|
18013
|
-
return /* @__PURE__ */ jsx23(Box19, { flexShrink: 0, height: 1, children: /* @__PURE__ */ jsx23(Text19, { color: coinColor, bold: !isFading, dimColor: isFading, wrap: "truncate-end", children: line }) }, i);
|
|
18587
|
+
/* @__PURE__ */ jsx23(Box19, { flexDirection: "column", alignItems: "center", children: normalizedFrame.lines.map((line, i) => {
|
|
18588
|
+
return /* @__PURE__ */ jsx23(Box19, { flexShrink: 0, height: 1, width: normalizedFrame.width, children: /* @__PURE__ */ jsx23(Text19, { color: coinColor, bold: !isFading, dimColor: isFading, wrap: "truncate-end", children: line }) }, i);
|
|
18014
18589
|
}) }),
|
|
18015
|
-
/* @__PURE__ */ jsx23(Box19, { marginTop: 2, flexShrink: 0, children: /* @__PURE__ */ jsx23(Text19, { bold: true, dimColor:
|
|
18590
|
+
/* @__PURE__ */ jsx23(Box19, { marginTop: 2, flexShrink: 0, children: isFading ? /* @__PURE__ */ jsx23(Text19, { bold: true, dimColor: true, children: "Pentesting Agent Starting..." }) : /* @__PURE__ */ jsx23(ShimmerText, { bold: true, variant: "accent", children: "Pentesting Agent Starting..." }) }),
|
|
18591
|
+
/* @__PURE__ */ jsx23(Box19, { marginTop: 1, flexShrink: 0, children: /* @__PURE__ */ jsx23(
|
|
18592
|
+
Text19,
|
|
18593
|
+
{
|
|
18594
|
+
color: titleTone.color,
|
|
18595
|
+
bold: titleTone.bold && !isFading,
|
|
18596
|
+
dimColor: isFading || titleTone.dimColor,
|
|
18597
|
+
children: "Initializing autonomous workflow"
|
|
18598
|
+
}
|
|
18599
|
+
) })
|
|
18016
18600
|
] })
|
|
18017
18601
|
}
|
|
18018
18602
|
);
|
|
@@ -18075,14 +18659,14 @@ async function runAction(objective, options) {
|
|
|
18075
18659
|
console.log(chalk2.hex(HEX.gray)("\n[+] Assessment complete!\n"));
|
|
18076
18660
|
console.log(result);
|
|
18077
18661
|
if (options.output) {
|
|
18078
|
-
const
|
|
18662
|
+
const fs3 = await import("fs/promises");
|
|
18079
18663
|
const { dirname: dirname2 } = await import("path");
|
|
18080
18664
|
const outputDir = dirname2(options.output);
|
|
18081
18665
|
if (outputDir && outputDir !== ".") {
|
|
18082
|
-
await
|
|
18666
|
+
await fs3.mkdir(outputDir, { recursive: true }).catch(() => {
|
|
18083
18667
|
});
|
|
18084
18668
|
}
|
|
18085
|
-
await
|
|
18669
|
+
await fs3.writeFile(options.output, JSON.stringify({ result }, null, 2));
|
|
18086
18670
|
console.log(chalk2.hex(HEX.primary)(`
|
|
18087
18671
|
[+] Report saved to: ${options.output}`));
|
|
18088
18672
|
}
|