pentesting 0.44.1 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/main.js +441 -190
- package/dist/prompts/base.md +16 -18
- package/dist/prompts/exploit.md +268 -12
- package/dist/prompts/orchestrator.md +49 -0
- package/dist/prompts/strategy.md +205 -0
- package/dist/prompts/web.md +96 -0
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -12,11 +12,11 @@ import { Command } from "commander";
|
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
|
|
14
14
|
// src/platform/tui/app.tsx
|
|
15
|
-
import { useState as
|
|
15
|
+
import { useState as useState5, useCallback as useCallback4, useEffect as useEffect4, useRef as useRef5 } from "react";
|
|
16
16
|
import { Box as Box6, useInput as useInput2, useApp } from "ink";
|
|
17
17
|
|
|
18
18
|
// src/platform/tui/hooks/useAgent.ts
|
|
19
|
-
import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2, useRef as
|
|
19
|
+
import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2, useRef as useRef3 } from "react";
|
|
20
20
|
|
|
21
21
|
// src/shared/constants/timing.ts
|
|
22
22
|
var TOOL_TIMEOUTS = {
|
|
@@ -311,7 +311,7 @@ var ORPHAN_PROCESS_NAMES = [
|
|
|
311
311
|
|
|
312
312
|
// src/shared/constants/agent.ts
|
|
313
313
|
var APP_NAME = "Pentest AI";
|
|
314
|
-
var APP_VERSION = "0.
|
|
314
|
+
var APP_VERSION = "0.46.0";
|
|
315
315
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
316
316
|
var LLM_ROLES = {
|
|
317
317
|
SYSTEM: "system",
|
|
@@ -676,6 +676,7 @@ var EVENT_TYPES = {
|
|
|
676
676
|
REASONING_START: "reasoning_start",
|
|
677
677
|
REASONING_DELTA: "reasoning_delta",
|
|
678
678
|
REASONING_END: "reasoning_end",
|
|
679
|
+
AI_RESPONSE: "ai_response",
|
|
679
680
|
TOOL_CALL: "tool_call",
|
|
680
681
|
TOOL_RESULT: "tool_result",
|
|
681
682
|
ERROR: "error",
|
|
@@ -3450,6 +3451,10 @@ var SharedState = class {
|
|
|
3450
3451
|
// --- Targets ---
|
|
3451
3452
|
addTarget(target) {
|
|
3452
3453
|
this.data.targets.set(target.ip, target);
|
|
3454
|
+
this.attackGraph.addHost(target.ip, target.hostname);
|
|
3455
|
+
for (const port of target.ports) {
|
|
3456
|
+
this.attackGraph.addService(target.ip, port.port, port.service, port.version);
|
|
3457
|
+
}
|
|
3453
3458
|
}
|
|
3454
3459
|
getTarget(ip) {
|
|
3455
3460
|
return this.data.targets.get(ip);
|
|
@@ -3903,6 +3908,21 @@ var NOISE_CLASSIFICATION = {
|
|
|
3903
3908
|
"gobuster",
|
|
3904
3909
|
"dirsearch",
|
|
3905
3910
|
"feroxbuster"
|
|
3911
|
+
],
|
|
3912
|
+
LOW_VISIBILITY: [
|
|
3913
|
+
// State management — pure bookkeeping, zero operator value
|
|
3914
|
+
"update_mission",
|
|
3915
|
+
"get_state",
|
|
3916
|
+
"update_phase",
|
|
3917
|
+
"update_todo",
|
|
3918
|
+
"add_target",
|
|
3919
|
+
"add_finding",
|
|
3920
|
+
"add_loot",
|
|
3921
|
+
"set_scope",
|
|
3922
|
+
// Resource health checks — noisy periodic calls
|
|
3923
|
+
"bg_status",
|
|
3924
|
+
"bg_cleanup",
|
|
3925
|
+
"health_check"
|
|
3906
3926
|
]
|
|
3907
3927
|
};
|
|
3908
3928
|
|
|
@@ -5014,6 +5034,7 @@ The target will be tracked in SharedState and available for all agents.`,
|
|
|
5014
5034
|
state: np.state || "open",
|
|
5015
5035
|
notes: []
|
|
5016
5036
|
});
|
|
5037
|
+
state.attackGraph.addService(ip, np.port, np.service || "unknown", np.version);
|
|
5017
5038
|
}
|
|
5018
5039
|
}
|
|
5019
5040
|
if (p.hostname) existing.hostname = p.hostname;
|
|
@@ -5034,9 +5055,6 @@ The target will be tracked in SharedState and available for all agents.`,
|
|
|
5034
5055
|
tags: p.tags || [],
|
|
5035
5056
|
firstSeen: Date.now()
|
|
5036
5057
|
});
|
|
5037
|
-
for (const port of ports) {
|
|
5038
|
-
state.attackGraph.addService(ip, port.port, port.service, port.version);
|
|
5039
|
-
}
|
|
5040
5058
|
return { success: true, output: `Target ${ip} added.${p.hostname ? ` Hostname: ${p.hostname}` : ""} Ports: ${ports.length}` };
|
|
5041
5059
|
}
|
|
5042
5060
|
},
|
|
@@ -5138,7 +5156,9 @@ var ENV_KEYS = {
|
|
|
5138
5156
|
BASE_URL: "PENTEST_BASE_URL",
|
|
5139
5157
|
MODEL: "PENTEST_MODEL",
|
|
5140
5158
|
SEARCH_API_KEY: "SEARCH_API_KEY",
|
|
5141
|
-
SEARCH_API_URL: "SEARCH_API_URL"
|
|
5159
|
+
SEARCH_API_URL: "SEARCH_API_URL",
|
|
5160
|
+
THINKING: "PENTEST_THINKING",
|
|
5161
|
+
THINKING_BUDGET: "PENTEST_THINKING_BUDGET"
|
|
5142
5162
|
};
|
|
5143
5163
|
var DEFAULT_SEARCH_API_URL = "https://api.search.brave.com/res/v1/web/search";
|
|
5144
5164
|
function getApiKey() {
|
|
@@ -5156,6 +5176,13 @@ function getSearchApiKey() {
|
|
|
5156
5176
|
function getSearchApiUrl() {
|
|
5157
5177
|
return process.env[ENV_KEYS.SEARCH_API_URL] || DEFAULT_SEARCH_API_URL;
|
|
5158
5178
|
}
|
|
5179
|
+
function isThinkingEnabled() {
|
|
5180
|
+
return process.env[ENV_KEYS.THINKING] === "true";
|
|
5181
|
+
}
|
|
5182
|
+
function getThinkingBudget() {
|
|
5183
|
+
const val = parseInt(process.env[ENV_KEYS.THINKING_BUDGET] || "", 10);
|
|
5184
|
+
return isNaN(val) ? 8e3 : Math.max(1024, val);
|
|
5185
|
+
}
|
|
5159
5186
|
function isBrowserHeadless() {
|
|
5160
5187
|
return true;
|
|
5161
5188
|
}
|
|
@@ -8818,6 +8845,8 @@ var LLM_BLOCK_TYPE = {
|
|
|
8818
8845
|
var LLM_DELTA_TYPE = {
|
|
8819
8846
|
TEXT_DELTA: "text_delta",
|
|
8820
8847
|
THINKING_DELTA: "thinking_delta",
|
|
8848
|
+
REASONING_DELTA: "reasoning_delta",
|
|
8849
|
+
// Used by some providers (GLM, DeepSeek)
|
|
8821
8850
|
INPUT_JSON_DELTA: "input_json_delta"
|
|
8822
8851
|
};
|
|
8823
8852
|
|
|
@@ -8967,6 +8996,8 @@ var LLMClient = class {
|
|
|
8967
8996
|
headers: {
|
|
8968
8997
|
[LLM_HEADER.CONTENT_TYPE]: LLM_CONTENT_TYPE.JSON,
|
|
8969
8998
|
[LLM_HEADER.API_KEY]: this.apiKey,
|
|
8999
|
+
// Also send as Bearer for OpenAI-compat proxies (z.ai, GLM, etc.)
|
|
9000
|
+
[LLM_HEADER.AUTHORIZATION]: `${LLM_HEADER.BEARER_PREFIX} ${this.apiKey}`,
|
|
8970
9001
|
[LLM_HEADER.ANTHROPIC_VERSION]: LLM_API.VERSION
|
|
8971
9002
|
},
|
|
8972
9003
|
body: JSON.stringify(body),
|
|
@@ -8981,14 +9012,16 @@ var LLMClient = class {
|
|
|
8981
9012
|
return response;
|
|
8982
9013
|
}
|
|
8983
9014
|
async executeNonStream(messages, tools, systemPrompt) {
|
|
9015
|
+
const thinking = isThinkingEnabled() ? { type: "enabled", budget_tokens: getThinkingBudget() } : void 0;
|
|
8984
9016
|
const requestBody = {
|
|
8985
9017
|
model: this.model,
|
|
8986
9018
|
max_tokens: LLM_LIMITS.nonStreamMaxTokens,
|
|
8987
9019
|
system: systemPrompt,
|
|
8988
9020
|
messages: this.convertMessages(messages),
|
|
8989
|
-
tools
|
|
9021
|
+
tools,
|
|
9022
|
+
...thinking && { thinking }
|
|
8990
9023
|
};
|
|
8991
|
-
debugLog("llm", "Non-stream request", { model: this.model, toolCount: tools?.length });
|
|
9024
|
+
debugLog("llm", "Non-stream request", { model: this.model, toolCount: tools?.length, thinking: !!thinking });
|
|
8992
9025
|
const response = await this.makeRequest(requestBody);
|
|
8993
9026
|
const data = await response.json();
|
|
8994
9027
|
const textBlock = data.content.find((b) => b.type === "text");
|
|
@@ -9004,15 +9037,17 @@ var LLMClient = class {
|
|
|
9004
9037
|
async executeStream(messages, tools, systemPrompt, callbacks) {
|
|
9005
9038
|
this.requestCount++;
|
|
9006
9039
|
const requestId = this.requestCount;
|
|
9040
|
+
const thinking = isThinkingEnabled() ? { type: "enabled", budget_tokens: getThinkingBudget() } : void 0;
|
|
9007
9041
|
const requestBody = {
|
|
9008
9042
|
model: this.model,
|
|
9009
9043
|
max_tokens: LLM_LIMITS.streamMaxTokens,
|
|
9010
9044
|
system: systemPrompt,
|
|
9011
9045
|
messages: this.convertMessages(messages),
|
|
9012
9046
|
tools,
|
|
9013
|
-
stream: true
|
|
9047
|
+
stream: true,
|
|
9048
|
+
...thinking && { thinking }
|
|
9014
9049
|
};
|
|
9015
|
-
debugLog("llm", `[${requestId}] Stream request START`, { model: this.model, toolCount: tools?.length, toolNames: tools?.map((t) => t.name) });
|
|
9050
|
+
debugLog("llm", `[${requestId}] Stream request START`, { model: this.model, toolCount: tools?.length, toolNames: tools?.map((t) => t.name), thinking: !!thinking });
|
|
9016
9051
|
const response = await this.makeRequest(requestBody, callbacks?.abortSignal);
|
|
9017
9052
|
let fullContent = "";
|
|
9018
9053
|
let fullReasoning = "";
|
|
@@ -9020,6 +9055,7 @@ var LLMClient = class {
|
|
|
9020
9055
|
let usage = { input_tokens: 0, output_tokens: 0 };
|
|
9021
9056
|
let totalChars = 0;
|
|
9022
9057
|
let wasAborted = false;
|
|
9058
|
+
const currentBlockRef = { value: null };
|
|
9023
9059
|
const reader = response.body?.getReader();
|
|
9024
9060
|
if (!reader) throw new Error("Response body is not readable");
|
|
9025
9061
|
const decoder = new TextDecoder();
|
|
@@ -9070,7 +9106,8 @@ var LLMClient = class {
|
|
|
9070
9106
|
onUsage: (u) => {
|
|
9071
9107
|
usage = u;
|
|
9072
9108
|
},
|
|
9073
|
-
getTotalChars: () => totalChars
|
|
9109
|
+
getTotalChars: () => totalChars,
|
|
9110
|
+
currentBlockRef
|
|
9074
9111
|
});
|
|
9075
9112
|
} catch {
|
|
9076
9113
|
}
|
|
@@ -9100,28 +9137,53 @@ var LLMClient = class {
|
|
|
9100
9137
|
toolCalls.push({ id: toolCall.id, name: toolCall.name, input: toolCall.input });
|
|
9101
9138
|
}
|
|
9102
9139
|
debugLog("llm", `[${requestId}] FINAL toolCalls`, { count: toolCalls.length, tools: toolCalls.map((t) => ({ id: t.id, name: t.name, input: t.input })) });
|
|
9140
|
+
const stripped = this.stripThinkTags(fullContent, fullReasoning);
|
|
9103
9141
|
return {
|
|
9104
|
-
content:
|
|
9142
|
+
content: stripped.cleanText,
|
|
9105
9143
|
toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
9106
9144
|
rawResponse: null,
|
|
9107
|
-
reasoning:
|
|
9145
|
+
reasoning: stripped.extractedReasoning || void 0,
|
|
9108
9146
|
usage: usage.input_tokens > 0 || usage.output_tokens > 0 ? usage : void 0,
|
|
9109
9147
|
error: wasAborted ? { type: LLM_ERROR_TYPES.UNKNOWN, message: "Stream aborted", isRetryable: false } : void 0
|
|
9110
9148
|
};
|
|
9111
9149
|
}
|
|
9150
|
+
/**
|
|
9151
|
+
* Strip inline <think>...</think> XML reasoning tags from LLM text output.
|
|
9152
|
+
*
|
|
9153
|
+
* WHY: Some providers (GLM, DeepSeek, Qwen) output reasoning inline
|
|
9154
|
+
* in text deltas as <think>content</think> instead of separate SSE blocks.
|
|
9155
|
+
* Without stripping, raw tags like "</think>" appear literally in TUI output.
|
|
9156
|
+
*
|
|
9157
|
+
* @param text - Raw text content potentially containing think tags
|
|
9158
|
+
* @param existingReasoning - Accumulated reasoning from SSE reasoning blocks
|
|
9159
|
+
* @returns cleanText (tags removed) and extractedReasoning (tag content appended)
|
|
9160
|
+
*/
|
|
9161
|
+
stripThinkTags(text, existingReasoning) {
|
|
9162
|
+
let cleanText = text;
|
|
9163
|
+
let extractedReasoning = existingReasoning;
|
|
9164
|
+
cleanText = cleanText.replace(/<think>([\s\S]*?)<\/think>/gi, (_match, inner) => {
|
|
9165
|
+
extractedReasoning += inner;
|
|
9166
|
+
return "";
|
|
9167
|
+
});
|
|
9168
|
+
cleanText = cleanText.replace(/<\/?think>/gi, "");
|
|
9169
|
+
return { cleanText, extractedReasoning };
|
|
9170
|
+
}
|
|
9112
9171
|
processStreamEvent(event, requestId, context) {
|
|
9113
|
-
const { toolCallsMap, callbacks, onTextStart, onReasoningStart, onTextEnd, onReasoningEnd, onContent, onReasoning, onUsage, getTotalChars } = context;
|
|
9172
|
+
const { toolCallsMap, callbacks, onTextStart, onReasoningStart, onTextEnd, onReasoningEnd, onContent, onReasoning, onUsage, getTotalChars, currentBlockRef } = context;
|
|
9114
9173
|
switch (event.type) {
|
|
9115
9174
|
case LLM_SSE_EVENT.CONTENT_BLOCK_START:
|
|
9116
9175
|
if (event.content_block) {
|
|
9117
9176
|
const blockType = event.content_block.type;
|
|
9118
9177
|
if (blockType === LLM_BLOCK_TYPE.TEXT) {
|
|
9178
|
+
currentBlockRef.value = "text";
|
|
9119
9179
|
onTextStart();
|
|
9120
9180
|
callbacks?.onOutputStart?.();
|
|
9121
9181
|
} else if (blockType === LLM_BLOCK_TYPE.THINKING || blockType === LLM_BLOCK_TYPE.REASONING) {
|
|
9182
|
+
currentBlockRef.value = "reasoning";
|
|
9122
9183
|
onReasoningStart();
|
|
9123
9184
|
callbacks?.onReasoningStart?.();
|
|
9124
9185
|
} else if (blockType === LLM_BLOCK_TYPE.TOOL_USE) {
|
|
9186
|
+
currentBlockRef.value = "tool_use";
|
|
9125
9187
|
toolCallsMap.set(event.content_block.id || "", {
|
|
9126
9188
|
id: event.content_block.id || "",
|
|
9127
9189
|
name: event.content_block.name || "",
|
|
@@ -9137,9 +9199,13 @@ var LLMClient = class {
|
|
|
9137
9199
|
if (event.delta.type === LLM_DELTA_TYPE.TEXT_DELTA && event.delta.text) {
|
|
9138
9200
|
onContent(event.delta.text);
|
|
9139
9201
|
callbacks?.onOutputDelta?.(event.delta.text);
|
|
9140
|
-
} else if (
|
|
9141
|
-
|
|
9142
|
-
|
|
9202
|
+
} else if (
|
|
9203
|
+
// Anthropic: thinking_delta / GLM-DeepSeek: reasoning_delta
|
|
9204
|
+
event.delta.type === LLM_DELTA_TYPE.THINKING_DELTA && event.delta.thinking || event.delta.type === LLM_DELTA_TYPE.REASONING_DELTA && event.delta.reasoning
|
|
9205
|
+
) {
|
|
9206
|
+
const chunk = event.delta.thinking || event.delta.reasoning || "";
|
|
9207
|
+
onReasoning(chunk);
|
|
9208
|
+
callbacks?.onReasoningDelta?.(chunk);
|
|
9143
9209
|
} else if (event.delta.type === LLM_DELTA_TYPE.INPUT_JSON_DELTA && event.delta.partial_json) {
|
|
9144
9210
|
const index = event.index;
|
|
9145
9211
|
if (index !== void 0) {
|
|
@@ -9156,12 +9222,18 @@ var LLMClient = class {
|
|
|
9156
9222
|
callbacks?.onUsageUpdate?.({ input_tokens: 0, output_tokens: estimatedOutput });
|
|
9157
9223
|
}
|
|
9158
9224
|
break;
|
|
9159
|
-
case LLM_SSE_EVENT.CONTENT_BLOCK_STOP:
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9225
|
+
case LLM_SSE_EVENT.CONTENT_BLOCK_STOP: {
|
|
9226
|
+
const stoppedType = currentBlockRef.value;
|
|
9227
|
+
currentBlockRef.value = null;
|
|
9228
|
+
if (stoppedType === "text") {
|
|
9229
|
+
onTextEnd();
|
|
9230
|
+
callbacks?.onOutputEnd?.();
|
|
9231
|
+
} else if (stoppedType === "reasoning") {
|
|
9232
|
+
onReasoningEnd();
|
|
9233
|
+
callbacks?.onReasoningEnd?.();
|
|
9234
|
+
}
|
|
9164
9235
|
break;
|
|
9236
|
+
}
|
|
9165
9237
|
case LLM_SSE_EVENT.MESSAGE_START:
|
|
9166
9238
|
if (event.message?.usage) {
|
|
9167
9239
|
onUsage({ input_tokens: event.message.usage.input_tokens || 0, output_tokens: event.message.usage.output_tokens || 0 });
|
|
@@ -10130,7 +10202,7 @@ Please decide how to handle this error and continue.`;
|
|
|
10130
10202
|
async step(iteration, messages, systemPrompt, progress) {
|
|
10131
10203
|
const phase = this.state.getPhase();
|
|
10132
10204
|
const stepStartTime = Date.now();
|
|
10133
|
-
this.emitThink(iteration);
|
|
10205
|
+
this.emitThink(iteration, progress);
|
|
10134
10206
|
const callbacks = this.buildStreamCallbacks(phase);
|
|
10135
10207
|
const response = await this.llm.generateResponseStream(
|
|
10136
10208
|
messages,
|
|
@@ -10138,12 +10210,24 @@ Please decide how to handle this error and continue.`;
|
|
|
10138
10210
|
systemPrompt,
|
|
10139
10211
|
callbacks
|
|
10140
10212
|
);
|
|
10213
|
+
if (response.reasoning && !callbacks.hadReasoningEnd()) {
|
|
10214
|
+
this.emitReasoningStart(phase);
|
|
10215
|
+
this.emitReasoningDelta(response.reasoning, phase);
|
|
10216
|
+
this.emitReasoningEnd(phase);
|
|
10217
|
+
}
|
|
10218
|
+
if (response.content?.trim()) {
|
|
10219
|
+
this.events.emit({
|
|
10220
|
+
type: EVENT_TYPES.AI_RESPONSE,
|
|
10221
|
+
timestamp: Date.now(),
|
|
10222
|
+
data: { content: response.content.trim(), phase }
|
|
10223
|
+
});
|
|
10224
|
+
}
|
|
10141
10225
|
messages.push({ role: LLM_ROLES.ASSISTANT, content: response.content });
|
|
10142
10226
|
const stepDuration = Date.now() - stepStartTime;
|
|
10143
10227
|
const tokens = response.usage ? { input: response.usage.input_tokens, output: response.usage.output_tokens } : void 0;
|
|
10144
10228
|
if (!response.toolCalls?.length) {
|
|
10145
|
-
const
|
|
10146
|
-
if (
|
|
10229
|
+
const hasDoneMeaningfulWork = (progress?.totalToolsExecuted ?? 0) > 0;
|
|
10230
|
+
if (hasDoneMeaningfulWork) {
|
|
10147
10231
|
this.emitComplete(response.content, iteration, 0, stepDuration, tokens);
|
|
10148
10232
|
return { output: response.content, toolsExecuted: 0, isCompleted: true };
|
|
10149
10233
|
}
|
|
@@ -10157,11 +10241,26 @@ Please decide how to handle this error and continue.`;
|
|
|
10157
10241
|
// SUBSECTION: Callback Builder
|
|
10158
10242
|
// ─────────────────────────────────────────────────────────────────
|
|
10159
10243
|
buildStreamCallbacks(phase) {
|
|
10160
|
-
|
|
10244
|
+
let _reasoningEndFired = false;
|
|
10245
|
+
let _outputBuffer = "";
|
|
10246
|
+
const callbacks = {
|
|
10161
10247
|
onReasoningStart: () => this.emitReasoningStart(phase),
|
|
10162
10248
|
onReasoningDelta: (content) => this.emitReasoningDelta(content, phase),
|
|
10163
|
-
onReasoningEnd: () =>
|
|
10164
|
-
|
|
10249
|
+
onReasoningEnd: () => {
|
|
10250
|
+
_reasoningEndFired = true;
|
|
10251
|
+
this.emitReasoningEnd(phase);
|
|
10252
|
+
},
|
|
10253
|
+
// WHY: Show AI text as it streams, not after completion.
|
|
10254
|
+
// The user sees what the AI is writing in real-time via the status bar.
|
|
10255
|
+
onOutputDelta: (text) => {
|
|
10256
|
+
_outputBuffer += text;
|
|
10257
|
+
const firstLine = _outputBuffer.split("\n")[0]?.slice(0, 120) || "";
|
|
10258
|
+
this.events.emit({
|
|
10259
|
+
type: EVENT_TYPES.THINK,
|
|
10260
|
+
timestamp: Date.now(),
|
|
10261
|
+
data: { thought: `Writing\u2026 ${_outputBuffer.length} chars
|
|
10262
|
+
${firstLine}`, phase }
|
|
10263
|
+
});
|
|
10165
10264
|
},
|
|
10166
10265
|
onRetry: (attempt, maxRetries, delayMs, error) => {
|
|
10167
10266
|
this.events.emit({
|
|
@@ -10177,19 +10276,40 @@ Please decide how to handle this error and continue.`;
|
|
|
10177
10276
|
data: { inputTokens: usage.input_tokens, outputTokens: usage.output_tokens }
|
|
10178
10277
|
});
|
|
10179
10278
|
},
|
|
10180
|
-
abortSignal: this.abortController?.signal
|
|
10279
|
+
abortSignal: this.abortController?.signal,
|
|
10280
|
+
// WHY: Used by step() to detect if SSE reasoning blocks fired.
|
|
10281
|
+
// If not, we know it was an inline <think> model and must emit post-stream.
|
|
10282
|
+
hadReasoningEnd: () => _reasoningEndFired
|
|
10181
10283
|
};
|
|
10284
|
+
return callbacks;
|
|
10182
10285
|
}
|
|
10183
10286
|
// ─────────────────────────────────────────────────────────────────
|
|
10184
10287
|
// SUBSECTION: Event Emitters
|
|
10185
10288
|
// ─────────────────════════════════════════════════════════════
|
|
10186
|
-
emitThink(iteration) {
|
|
10289
|
+
emitThink(iteration, progress) {
|
|
10290
|
+
const phase = this.state.getPhase();
|
|
10291
|
+
const targets = this.state.getTargets().size;
|
|
10292
|
+
const findings = this.state.getFindings().length;
|
|
10293
|
+
const toolsUsed = progress?.totalToolsExecuted ?? 0;
|
|
10294
|
+
const hasErrors = (progress?.toolErrors ?? 0) > 0;
|
|
10295
|
+
let thought;
|
|
10296
|
+
if (iteration === 0) {
|
|
10297
|
+
thought = targets > 0 ? `Analyzing ${targets} target${targets > 1 ? "s" : ""} \xB7 Planning ${phase} approach` : `Reviewing task \xB7 Building ${phase} strategy`;
|
|
10298
|
+
} else if (toolsUsed === 0) {
|
|
10299
|
+
thought = `Iteration ${iteration + 1} \xB7 No actions yet \xB7 Reconsidering approach`;
|
|
10300
|
+
} else if (hasErrors) {
|
|
10301
|
+
thought = `Iteration ${iteration + 1} \xB7 [${phase}] ${toolsUsed} tools \xB7 ${progress?.toolErrors} error${(progress?.toolErrors ?? 0) > 1 ? "s" : ""} \xB7 Adapting strategy`;
|
|
10302
|
+
} else if (findings > 0) {
|
|
10303
|
+
thought = `Iteration ${iteration + 1} \xB7 [${phase}] ${findings} finding${findings > 1 ? "s" : ""} \xB7 ${toolsUsed} tools \xB7 Continuing`;
|
|
10304
|
+
} else {
|
|
10305
|
+
thought = `Iteration ${iteration + 1} \xB7 [${phase}] ${toolsUsed} tool${toolsUsed !== 1 ? "s" : ""} executed \xB7 Evaluating results`;
|
|
10306
|
+
}
|
|
10187
10307
|
this.events.emit({
|
|
10188
10308
|
type: EVENT_TYPES.THINK,
|
|
10189
10309
|
timestamp: Date.now(),
|
|
10190
10310
|
data: {
|
|
10191
|
-
thought
|
|
10192
|
-
phase
|
|
10311
|
+
thought,
|
|
10312
|
+
phase
|
|
10193
10313
|
}
|
|
10194
10314
|
});
|
|
10195
10315
|
}
|
|
@@ -11461,63 +11581,56 @@ import { useState, useRef, useCallback } from "react";
|
|
|
11461
11581
|
|
|
11462
11582
|
// src/shared/constants/theme.ts
|
|
11463
11583
|
var HEX = {
|
|
11464
|
-
primary: "#
|
|
11465
|
-
|
|
11466
|
-
|
|
11584
|
+
primary: "#2496ED",
|
|
11585
|
+
// Docker blue
|
|
11586
|
+
cyan: "#58C4F0",
|
|
11587
|
+
// bright sky blue
|
|
11588
|
+
teal: "#4EC9B0",
|
|
11589
|
+
// mint-teal (success states)
|
|
11590
|
+
yellow: "#E0AF68",
|
|
11591
|
+
// warm amber (warning)
|
|
11592
|
+
gray: "#C8C8C8",
|
|
11593
|
+
// secondary text
|
|
11594
|
+
white: "#FFFFFF",
|
|
11595
|
+
red: "#F7768E"
|
|
11596
|
+
// pastel red (error)
|
|
11467
11597
|
};
|
|
11468
11598
|
var COLORS = {
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
// Orange (ANSI 215)
|
|
11478
|
-
orange: "ansi256(215)",
|
|
11479
|
-
// Bright white for main text
|
|
11599
|
+
primary: "ansi256(33)",
|
|
11600
|
+
// Docker blue (#0087ff) — closest to #2496ED
|
|
11601
|
+
cyan: "ansi256(74)",
|
|
11602
|
+
// bright sky blue (#5fafd7)
|
|
11603
|
+
teal: "ansi256(79)",
|
|
11604
|
+
// mint-teal (#5fd7af) — success states
|
|
11605
|
+
yellow: "ansi256(179)",
|
|
11606
|
+
// warm amber (warning)
|
|
11480
11607
|
white: "white",
|
|
11481
|
-
//
|
|
11482
|
-
gray: "ansi256(
|
|
11483
|
-
//
|
|
11484
|
-
|
|
11608
|
+
// main text — unchanged
|
|
11609
|
+
gray: "ansi256(250)",
|
|
11610
|
+
// secondary text — bright enough to read
|
|
11611
|
+
dimGray: "ansi256(240)",
|
|
11612
|
+
// dimmer text for sub-lines
|
|
11613
|
+
red: "ansi256(204)"
|
|
11614
|
+
// pastel red (error)
|
|
11485
11615
|
};
|
|
11486
11616
|
var THEME = {
|
|
11487
11617
|
...COLORS,
|
|
11488
|
-
bg: {
|
|
11489
|
-
primary: "#050505",
|
|
11490
|
-
input: "#020617"
|
|
11491
|
-
},
|
|
11492
|
-
text: {
|
|
11493
|
-
primary: COLORS.white,
|
|
11494
|
-
// AI responses - main text
|
|
11495
|
-
secondary: COLORS.gray,
|
|
11496
|
-
// Secondary info
|
|
11497
|
-
muted: COLORS.gray,
|
|
11498
|
-
// Metadata, hints
|
|
11499
|
-
accent: COLORS.gray
|
|
11500
|
-
// Very subtle
|
|
11501
|
-
},
|
|
11502
11618
|
status: {
|
|
11503
|
-
success: COLORS.
|
|
11504
|
-
//
|
|
11619
|
+
success: COLORS.teal,
|
|
11620
|
+
// teal for success
|
|
11505
11621
|
warning: COLORS.yellow,
|
|
11506
|
-
//
|
|
11507
|
-
error: COLORS.red
|
|
11508
|
-
//
|
|
11509
|
-
running: COLORS.gray
|
|
11510
|
-
// Processing indicator
|
|
11622
|
+
// amber for warnings
|
|
11623
|
+
error: COLORS.red
|
|
11624
|
+
// red for errors
|
|
11511
11625
|
},
|
|
11512
11626
|
border: {
|
|
11513
|
-
|
|
11514
|
-
|
|
11627
|
+
default: "ansi256(25)",
|
|
11628
|
+
// muted Docker blue border (#005faf)
|
|
11515
11629
|
focus: COLORS.primary,
|
|
11516
11630
|
error: COLORS.red
|
|
11517
11631
|
},
|
|
11518
11632
|
gradient: {
|
|
11519
|
-
|
|
11520
|
-
cyber: [HEX.primary, HEX.pink, HEX.peach]
|
|
11633
|
+
cyber: [HEX.primary, HEX.cyan, HEX.teal]
|
|
11521
11634
|
},
|
|
11522
11635
|
spinner: COLORS.primary
|
|
11523
11636
|
};
|
|
@@ -11537,9 +11650,8 @@ var ICONS = {
|
|
|
11537
11650
|
info: "\u2139",
|
|
11538
11651
|
running: "\u25C9",
|
|
11539
11652
|
thinking: "\u25D0",
|
|
11540
|
-
// Actions
|
|
11653
|
+
// Actions
|
|
11541
11654
|
target: "\u25C8",
|
|
11542
|
-
// Diamond for target
|
|
11543
11655
|
scan: "\u25CE",
|
|
11544
11656
|
exploit: "\u2607",
|
|
11545
11657
|
shell: "\u276F",
|
|
@@ -11557,9 +11669,7 @@ var ICONS = {
|
|
|
11557
11669
|
unlock: "\u2B1A",
|
|
11558
11670
|
key: "\u26B7",
|
|
11559
11671
|
flag: "\u2691",
|
|
11560
|
-
// Simple flag
|
|
11561
11672
|
pwned: "\u25C8"
|
|
11562
|
-
// Compromised
|
|
11563
11673
|
};
|
|
11564
11674
|
|
|
11565
11675
|
// src/platform/tui/constants/display.ts
|
|
@@ -11570,7 +11680,11 @@ var TUI_DISPLAY_LIMITS = {
|
|
|
11570
11680
|
reasoningPreview: 500,
|
|
11571
11681
|
/** Reasoning history slice for display */
|
|
11572
11682
|
reasoningHistorySlice: 1e3,
|
|
11573
|
-
/**
|
|
11683
|
+
/** Max number of output lines shown from a tool result (success) */
|
|
11684
|
+
toolOutputLines: 20,
|
|
11685
|
+
/** Max number of output lines shown from a tool result (error — show more) */
|
|
11686
|
+
errorOutputLines: 25,
|
|
11687
|
+
/** Tool output preview length (for command display) */
|
|
11574
11688
|
toolInputPreview: 200,
|
|
11575
11689
|
/** Tool input truncated length */
|
|
11576
11690
|
toolInputTruncated: 197,
|
|
@@ -11601,7 +11715,11 @@ var TUI_DISPLAY_LIMITS = {
|
|
|
11601
11715
|
/** Max flow nodes to display */
|
|
11602
11716
|
maxFlowNodes: 50,
|
|
11603
11717
|
/** Max stopped processes to show */
|
|
11604
|
-
maxStoppedProcesses: 3
|
|
11718
|
+
maxStoppedProcesses: 3,
|
|
11719
|
+
/** Max chars for live reasoning preview in status sub-line */
|
|
11720
|
+
reasoningPreviewChars: 100,
|
|
11721
|
+
/** Max chars for thinking block first-line summary */
|
|
11722
|
+
thinkingSummaryChars: 72
|
|
11605
11723
|
};
|
|
11606
11724
|
var MESSAGE_STYLES = {
|
|
11607
11725
|
colors: {
|
|
@@ -11619,8 +11737,10 @@ var MESSAGE_STYLES = {
|
|
|
11619
11737
|
// Tool commands - light gray
|
|
11620
11738
|
result: THEME.gray,
|
|
11621
11739
|
// Tool results - light gray
|
|
11622
|
-
status: THEME.primary
|
|
11623
|
-
// Status -
|
|
11740
|
+
status: THEME.primary,
|
|
11741
|
+
// Status - teal accent
|
|
11742
|
+
thinking: THEME.cyan
|
|
11743
|
+
// Extended reasoning — sky blue (distinct from primary)
|
|
11624
11744
|
},
|
|
11625
11745
|
prefixes: {
|
|
11626
11746
|
user: "\u276F",
|
|
@@ -11630,7 +11750,9 @@ var MESSAGE_STYLES = {
|
|
|
11630
11750
|
error: "\u2717",
|
|
11631
11751
|
tool: "\u23BF",
|
|
11632
11752
|
result: "\u21B3",
|
|
11633
|
-
status: "\u25C8"
|
|
11753
|
+
status: "\u25C8",
|
|
11754
|
+
thinking: "\u25D0"
|
|
11755
|
+
// Thinking/reasoning icon
|
|
11634
11756
|
}
|
|
11635
11757
|
};
|
|
11636
11758
|
var COMMAND_DEFINITIONS = [
|
|
@@ -11753,7 +11875,7 @@ var useAgentState = () => {
|
|
|
11753
11875
|
};
|
|
11754
11876
|
|
|
11755
11877
|
// src/platform/tui/hooks/useAgentEvents.ts
|
|
11756
|
-
import { useEffect } from "react";
|
|
11878
|
+
import { useEffect, useRef as useRef2 } from "react";
|
|
11757
11879
|
var useAgentEvents = (agent, eventsRef, state) => {
|
|
11758
11880
|
const {
|
|
11759
11881
|
addMessage,
|
|
@@ -11769,35 +11891,51 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11769
11891
|
lastStepTokensRef,
|
|
11770
11892
|
clearAllTimers
|
|
11771
11893
|
} = state;
|
|
11894
|
+
const reasoningBufferRef = useRef2("");
|
|
11772
11895
|
useEffect(() => {
|
|
11773
11896
|
const events = eventsRef.current;
|
|
11774
11897
|
const onToolCall = (e) => {
|
|
11775
|
-
|
|
11898
|
+
if (NOISE_CLASSIFICATION.LOW_VISIBILITY.includes(e.data.toolName)) return;
|
|
11899
|
+
setCurrentStatus(`${e.data.toolName}\u2026`);
|
|
11776
11900
|
const inputStr = formatToolInput(e.data.toolName, e.data.input);
|
|
11777
|
-
|
|
11901
|
+
const label = inputStr ? `${toDisplayName(e.data.toolName)}(${inputStr})` : `${toDisplayName(e.data.toolName)}`;
|
|
11902
|
+
addMessage("tool", label);
|
|
11778
11903
|
};
|
|
11779
11904
|
const onToolResult = (e) => {
|
|
11905
|
+
if (NOISE_CLASSIFICATION.LOW_VISIBILITY.includes(e.data.toolName)) {
|
|
11906
|
+
return;
|
|
11907
|
+
}
|
|
11780
11908
|
const icon = e.data.success ? "\u2713" : "\u2717";
|
|
11781
|
-
const
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11909
|
+
const rawContent = e.data.success ? e.data.outputSummary || e.data.output || "" : e.data.error || e.data.output || "Unknown error";
|
|
11910
|
+
if (!rawContent.trim()) {
|
|
11911
|
+
addMessage("result", `${icon}`);
|
|
11912
|
+
return;
|
|
11913
|
+
}
|
|
11914
|
+
const lines = rawContent.replace(/^\s*-n\s+/gm, "").split("\n").map((l) => l.trimEnd()).filter((l, i, arr) => {
|
|
11915
|
+
if (l === "" && arr[i - 1] === "") return false;
|
|
11916
|
+
return true;
|
|
11917
|
+
});
|
|
11918
|
+
addMessage("result", `${icon} ${lines.join("\n")}`);
|
|
11786
11919
|
};
|
|
11787
11920
|
const onComplete = (e) => {
|
|
11788
|
-
|
|
11921
|
+
const meta = formatMeta(e.data.durationMs || 0, (e.data.tokens?.input || 0) + (e.data.tokens?.output || 0));
|
|
11922
|
+
addMessage("system", `\u2713 Done ${meta}`);
|
|
11789
11923
|
lastResponseMetaRef.current = { durationMs: e.data.durationMs, tokens: e.data.tokens };
|
|
11790
11924
|
};
|
|
11791
11925
|
const onRetry = (e) => {
|
|
11792
11926
|
handleRetry(e, addMessage, setRetryState, retryCountdownRef, retryCountRef);
|
|
11793
11927
|
};
|
|
11794
11928
|
const onThink = (e) => {
|
|
11795
|
-
|
|
11796
|
-
setCurrentStatus(t.length > TUI_DISPLAY_LIMITS.statusThoughtPreview ? t.substring(0, TUI_DISPLAY_LIMITS.statusThoughtTruncated) + "..." : t);
|
|
11929
|
+
setCurrentStatus(e.data.thought);
|
|
11797
11930
|
};
|
|
11798
11931
|
const onError = (e) => {
|
|
11799
11932
|
addMessage("error", e.data.message || "An error occurred");
|
|
11800
11933
|
};
|
|
11934
|
+
const onAIResponse = (e) => {
|
|
11935
|
+
if (e.data.content?.trim()) {
|
|
11936
|
+
addMessage("ai", e.data.content.trim());
|
|
11937
|
+
}
|
|
11938
|
+
};
|
|
11801
11939
|
const onUsageUpdate = (e) => {
|
|
11802
11940
|
const stepTokens = e.data.inputTokens + e.data.outputTokens;
|
|
11803
11941
|
if (stepTokens < lastStepTokensRef.current) {
|
|
@@ -11810,7 +11948,7 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11810
11948
|
addMessage("system", `[FLAG] ${e.data.flag} (total: ${e.data.totalFlags})`);
|
|
11811
11949
|
};
|
|
11812
11950
|
const onPhaseChange = (e) => {
|
|
11813
|
-
addMessage("system", `
|
|
11951
|
+
addMessage("system", `Phase ${e.data.fromPhase} \u2192 ${e.data.toPhase} (${e.data.reason})`);
|
|
11814
11952
|
const s = agent.getState();
|
|
11815
11953
|
setStats({
|
|
11816
11954
|
phase: e.data.toPhase,
|
|
@@ -11819,6 +11957,25 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11819
11957
|
todo: s.getTodo().length
|
|
11820
11958
|
});
|
|
11821
11959
|
};
|
|
11960
|
+
const onReasoningStart = () => {
|
|
11961
|
+
reasoningBufferRef.current = "";
|
|
11962
|
+
setCurrentStatus("Thinking\u2026");
|
|
11963
|
+
};
|
|
11964
|
+
const onReasoningDelta = (e) => {
|
|
11965
|
+
reasoningBufferRef.current += e.data.content;
|
|
11966
|
+
const chars = reasoningBufferRef.current.length;
|
|
11967
|
+
const firstLine = reasoningBufferRef.current.split("\n")[0]?.slice(0, TUI_DISPLAY_LIMITS.reasoningPreviewChars) || "";
|
|
11968
|
+
setCurrentStatus(`Thinking\u2026 ${chars} chars
|
|
11969
|
+
${firstLine}`);
|
|
11970
|
+
};
|
|
11971
|
+
const onReasoningEnd = () => {
|
|
11972
|
+
const text = reasoningBufferRef.current.trim();
|
|
11973
|
+
reasoningBufferRef.current = "";
|
|
11974
|
+
setCurrentStatus("");
|
|
11975
|
+
if (text) {
|
|
11976
|
+
addMessage("thinking", text);
|
|
11977
|
+
}
|
|
11978
|
+
};
|
|
11822
11979
|
setInputHandler((p) => {
|
|
11823
11980
|
return new Promise((resolve) => {
|
|
11824
11981
|
const isPassword = /password|passphrase/i.test(p);
|
|
@@ -11850,9 +12007,11 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11850
12007
|
});
|
|
11851
12008
|
});
|
|
11852
12009
|
setCommandEventEmitter((event) => {
|
|
12010
|
+
if (event.type === COMMAND_EVENT_TYPES.COMMAND_START || event.type === COMMAND_EVENT_TYPES.COMMAND_SUCCESS) {
|
|
12011
|
+
return;
|
|
12012
|
+
}
|
|
11853
12013
|
const icon = getCommandEventIcon(event.type);
|
|
11854
|
-
const msg = event.detail ? `${icon} ${event.message}
|
|
11855
|
-
${event.detail}` : `${icon} ${event.message}`;
|
|
12014
|
+
const msg = event.detail ? `${icon} ${event.message} ${event.detail}` : `${icon} ${event.message}`;
|
|
11856
12015
|
addMessage("system", msg);
|
|
11857
12016
|
});
|
|
11858
12017
|
const updateStats = () => {
|
|
@@ -11875,6 +12034,10 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11875
12034
|
events.on(EVENT_TYPES.PHASE_CHANGE, onPhaseChange);
|
|
11876
12035
|
events.on(EVENT_TYPES.STATE_CHANGE, updateStats);
|
|
11877
12036
|
events.on(EVENT_TYPES.START, updateStats);
|
|
12037
|
+
events.on(EVENT_TYPES.REASONING_START, onReasoningStart);
|
|
12038
|
+
events.on(EVENT_TYPES.REASONING_DELTA, onReasoningDelta);
|
|
12039
|
+
events.on(EVENT_TYPES.REASONING_END, onReasoningEnd);
|
|
12040
|
+
events.on(EVENT_TYPES.AI_RESPONSE, onAIResponse);
|
|
11878
12041
|
updateStats();
|
|
11879
12042
|
return () => {
|
|
11880
12043
|
events.removeAllListeners();
|
|
@@ -11900,6 +12063,16 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11900
12063
|
eventsRef
|
|
11901
12064
|
]);
|
|
11902
12065
|
};
|
|
12066
|
+
function toDisplayName(toolName) {
|
|
12067
|
+
const MAP = {
|
|
12068
|
+
[TOOL_NAMES.RUN_CMD]: "Bash",
|
|
12069
|
+
[TOOL_NAMES.BG_PROCESS]: "Process",
|
|
12070
|
+
[TOOL_NAMES.READ_FILE]: "Read",
|
|
12071
|
+
[TOOL_NAMES.WRITE_FILE]: "Write",
|
|
12072
|
+
[TOOL_NAMES.ASK_USER]: "Input"
|
|
12073
|
+
};
|
|
12074
|
+
return MAP[toolName] ?? toolName.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
12075
|
+
}
|
|
11903
12076
|
function formatToolInput(toolName, input) {
|
|
11904
12077
|
if (!input || Object.keys(input).length === 0) return "";
|
|
11905
12078
|
try {
|
|
@@ -11955,24 +12128,24 @@ Options: ${request.options.join(", ")}`;
|
|
|
11955
12128
|
}
|
|
11956
12129
|
function getCommandEventIcon(eventType) {
|
|
11957
12130
|
const icons = {
|
|
11958
|
-
[COMMAND_EVENT_TYPES.TOOL_MISSING]: "
|
|
11959
|
-
[COMMAND_EVENT_TYPES.TOOL_INSTALL]: "
|
|
11960
|
-
[COMMAND_EVENT_TYPES.TOOL_INSTALLED]: "
|
|
11961
|
-
[COMMAND_EVENT_TYPES.TOOL_INSTALL_FAILED]: "
|
|
11962
|
-
[COMMAND_EVENT_TYPES.TOOL_RETRY]: "
|
|
11963
|
-
[COMMAND_EVENT_TYPES.COMMAND_START]: "
|
|
11964
|
-
[COMMAND_EVENT_TYPES.COMMAND_SUCCESS]: "
|
|
11965
|
-
[COMMAND_EVENT_TYPES.COMMAND_FAILED]: "
|
|
11966
|
-
[COMMAND_EVENT_TYPES.COMMAND_ERROR]: "
|
|
11967
|
-
[COMMAND_EVENT_TYPES.INPUT_REQUIRED]: "
|
|
12131
|
+
[COMMAND_EVENT_TYPES.TOOL_MISSING]: "!",
|
|
12132
|
+
[COMMAND_EVENT_TYPES.TOOL_INSTALL]: "\u2193",
|
|
12133
|
+
[COMMAND_EVENT_TYPES.TOOL_INSTALLED]: "\u2713",
|
|
12134
|
+
[COMMAND_EVENT_TYPES.TOOL_INSTALL_FAILED]: "\u2717",
|
|
12135
|
+
[COMMAND_EVENT_TYPES.TOOL_RETRY]: "\u21BA",
|
|
12136
|
+
[COMMAND_EVENT_TYPES.COMMAND_START]: "\u25B6",
|
|
12137
|
+
[COMMAND_EVENT_TYPES.COMMAND_SUCCESS]: "\u2713",
|
|
12138
|
+
[COMMAND_EVENT_TYPES.COMMAND_FAILED]: "\u2717",
|
|
12139
|
+
[COMMAND_EVENT_TYPES.COMMAND_ERROR]: "\u26A0",
|
|
12140
|
+
[COMMAND_EVENT_TYPES.INPUT_REQUIRED]: "\u{1F512}"
|
|
11968
12141
|
};
|
|
11969
|
-
return icons[eventType] || "
|
|
12142
|
+
return icons[eventType] || "\u2022";
|
|
11970
12143
|
}
|
|
11971
12144
|
|
|
11972
12145
|
// src/platform/tui/hooks/useAgent.ts
|
|
11973
12146
|
var useAgent = (shouldAutoApprove, target) => {
|
|
11974
12147
|
const [agent] = useState2(() => AgentFactory.createMainAgent(shouldAutoApprove));
|
|
11975
|
-
const eventsRef =
|
|
12148
|
+
const eventsRef = useRef3(agent.getEventEmitter());
|
|
11976
12149
|
const state = useAgentState();
|
|
11977
12150
|
const {
|
|
11978
12151
|
messages,
|
|
@@ -12025,7 +12198,7 @@ var useAgent = (shouldAutoApprove, target) => {
|
|
|
12025
12198
|
setCurrentStatus("");
|
|
12026
12199
|
addMessage("system", "Interrupted");
|
|
12027
12200
|
}, [agent, addMessage, manageTimer, setIsProcessing, setCurrentStatus]);
|
|
12028
|
-
const inputRequestRef =
|
|
12201
|
+
const inputRequestRef = useRef3(inputRequest);
|
|
12029
12202
|
inputRequestRef.current = inputRequest;
|
|
12030
12203
|
const cancelInputRequest = useCallback2(() => {
|
|
12031
12204
|
const ir = inputRequestRef.current;
|
|
@@ -12244,9 +12417,76 @@ var MessageList = memo(({ messages }) => {
|
|
|
12244
12417
|
}
|
|
12245
12418
|
) }, msg.id);
|
|
12246
12419
|
}
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12420
|
+
return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
|
|
12421
|
+
"\u2022 ",
|
|
12422
|
+
msg.content
|
|
12423
|
+
] }) }, msg.id);
|
|
12424
|
+
}
|
|
12425
|
+
if (msg.type === "thinking") {
|
|
12426
|
+
const lines = msg.content.split("\n");
|
|
12427
|
+
const charCount = msg.content.length;
|
|
12428
|
+
const firstLine = lines[0]?.slice(0, TUI_DISPLAY_LIMITS.thinkingSummaryChars) || "";
|
|
12429
|
+
const isMultiLine = lines.length > 1 || charCount > TUI_DISPLAY_LIMITS.thinkingSummaryChars;
|
|
12430
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 0, marginBottom: 1, children: [
|
|
12431
|
+
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12432
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.cyan, children: "\u25D0 " }),
|
|
12433
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.cyan, bold: true, children: "Thinking" }),
|
|
12434
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: ` (${lines.length} line${lines.length !== 1 ? "s" : ""}, ${charCount} chars)` })
|
|
12435
|
+
] }),
|
|
12436
|
+
lines.map((line, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12437
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.cyan, children: "\u2502 " }),
|
|
12438
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: line })
|
|
12439
|
+
] }, i)),
|
|
12440
|
+
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12441
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.cyan, children: "\u2570\u2500" }),
|
|
12442
|
+
isMultiLine && /* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: ` ${firstLine}\u2026` })
|
|
12443
|
+
] })
|
|
12444
|
+
] }, msg.id);
|
|
12445
|
+
}
|
|
12446
|
+
if (msg.type === "tool") {
|
|
12447
|
+
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12448
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: "\u23BF " }),
|
|
12449
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.primary, children: msg.content })
|
|
12450
|
+
] }, msg.id);
|
|
12451
|
+
}
|
|
12452
|
+
if (msg.type === "result") {
|
|
12453
|
+
const isSuccess = msg.content.startsWith("\u2713");
|
|
12454
|
+
const isFailure = msg.content.startsWith("\u2717");
|
|
12455
|
+
const color = isSuccess ? THEME.primary : isFailure ? THEME.red : THEME.gray;
|
|
12456
|
+
const lines = msg.content.split("\n");
|
|
12457
|
+
const firstLine = lines[0] || "";
|
|
12458
|
+
const restLines = lines.slice(1);
|
|
12459
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
12460
|
+
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12461
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: "\u21B3 " }),
|
|
12462
|
+
/* @__PURE__ */ jsx2(Text2, { color, children: firstLine })
|
|
12463
|
+
] }),
|
|
12464
|
+
restLines.map((line, i) => /* @__PURE__ */ jsx2(Box2, { paddingLeft: 2, children: /* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: line }) }, i))
|
|
12465
|
+
] }, msg.id);
|
|
12466
|
+
}
|
|
12467
|
+
if (msg.type === "ai" || msg.type === "assistant") {
|
|
12468
|
+
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", marginBottom: 0, children: /* @__PURE__ */ jsx2(Text2, { color: THEME.white, children: msg.content }) }, msg.id);
|
|
12469
|
+
}
|
|
12470
|
+
if (msg.type === "error") {
|
|
12471
|
+
return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: THEME.red, children: [
|
|
12472
|
+
"\u2717 ",
|
|
12473
|
+
msg.content
|
|
12474
|
+
] }) }, msg.id);
|
|
12475
|
+
}
|
|
12476
|
+
if (msg.type === "user") {
|
|
12477
|
+
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12478
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.primary, children: "\u276F " }),
|
|
12479
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.white, children: msg.content })
|
|
12480
|
+
] }, msg.id);
|
|
12481
|
+
}
|
|
12482
|
+
if (msg.type === "system") {
|
|
12483
|
+
return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: THEME.gray, children: [
|
|
12484
|
+
"\u2022 ",
|
|
12485
|
+
msg.content
|
|
12486
|
+
] }) }, msg.id);
|
|
12487
|
+
}
|
|
12488
|
+
return /* @__PURE__ */ jsx2(Box2, { children: /* @__PURE__ */ jsxs2(Text2, { color: MESSAGE_STYLES.colors[msg.type] ?? THEME.gray, children: [
|
|
12489
|
+
MESSAGE_STYLES.prefixes[msg.type] ?? "\u2022",
|
|
12250
12490
|
" ",
|
|
12251
12491
|
msg.content
|
|
12252
12492
|
] }) }, msg.id);
|
|
@@ -12287,39 +12527,48 @@ var StatusDisplay = memo3(({
|
|
|
12287
12527
|
return err.length > DISPLAY_LIMITS.RETRY_ERROR_PREVIEW ? err.substring(0, DISPLAY_LIMITS.RETRY_ERROR_TRUNCATED) + "..." : err;
|
|
12288
12528
|
};
|
|
12289
12529
|
const meta = formatMeta(elapsedTime * 1e3, currentTokens);
|
|
12530
|
+
const statusLines = currentStatus ? currentStatus.split("\n").filter(Boolean) : [];
|
|
12531
|
+
const statusMain = statusLines[0] || "Processing...";
|
|
12532
|
+
const statusSub = statusLines.slice(1).join(" ");
|
|
12533
|
+
const isThinkingStatus = statusMain.startsWith("Thinking");
|
|
12290
12534
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 0, children: [
|
|
12291
12535
|
retryState.status === "retrying" && /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
|
|
12292
12536
|
/* @__PURE__ */ jsx4(Text4, { color: THEME.yellow, children: /* @__PURE__ */ jsx4(MusicSpinner, { color: THEME.yellow }) }),
|
|
12293
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.yellow, children: [
|
|
12537
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.yellow, bold: true, children: [
|
|
12294
12538
|
" \u27F3 Retry #",
|
|
12295
|
-
retryState.attempt
|
|
12539
|
+
retryState.attempt,
|
|
12540
|
+
"/",
|
|
12541
|
+
retryState.maxRetries
|
|
12296
12542
|
] }),
|
|
12297
12543
|
/* @__PURE__ */ jsxs3(Text4, { color: THEME.gray, children: [
|
|
12298
|
-
" \
|
|
12299
|
-
truncateError(retryState.error)
|
|
12300
|
-
] }),
|
|
12301
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.primary, bold: true, children: [
|
|
12302
|
-
" \xB7 ",
|
|
12544
|
+
" \u2014 ",
|
|
12303
12545
|
retryState.countdown,
|
|
12304
|
-
"s"
|
|
12546
|
+
"s \xB7 ",
|
|
12547
|
+
truncateError(retryState.error)
|
|
12305
12548
|
] })
|
|
12306
12549
|
] }),
|
|
12307
|
-
isProcessing && retryState.status !== "retrying" && /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
|
|
12308
|
-
/* @__PURE__ */
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12550
|
+
isProcessing && retryState.status !== "retrying" && /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginBottom: 1, children: [
|
|
12551
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
12552
|
+
/* @__PURE__ */ jsx4(Text4, { color: isThinkingStatus ? THEME.cyan : THEME.primary, children: /* @__PURE__ */ jsx4(MusicSpinner, { color: isThinkingStatus ? THEME.cyan : THEME.primary }) }),
|
|
12553
|
+
/* @__PURE__ */ jsxs3(Text4, { color: isThinkingStatus ? THEME.cyan : THEME.primary, bold: true, children: [
|
|
12554
|
+
" ",
|
|
12555
|
+
statusMain
|
|
12556
|
+
] }),
|
|
12557
|
+
/* @__PURE__ */ jsxs3(Text4, { color: THEME.gray, children: [
|
|
12558
|
+
" ",
|
|
12559
|
+
meta
|
|
12560
|
+
] })
|
|
12312
12561
|
] }),
|
|
12313
|
-
/* @__PURE__ */ jsxs3(Text4, { color: THEME.gray, children: [
|
|
12314
|
-
" ",
|
|
12315
|
-
|
|
12316
|
-
] })
|
|
12562
|
+
statusSub ? /* @__PURE__ */ jsx4(Box3, { paddingLeft: 2, children: /* @__PURE__ */ jsxs3(Text4, { color: isThinkingStatus ? THEME.cyan : THEME.gray, children: [
|
|
12563
|
+
"\u2502 ",
|
|
12564
|
+
statusSub
|
|
12565
|
+
] }) }) : null
|
|
12317
12566
|
] })
|
|
12318
12567
|
] });
|
|
12319
12568
|
});
|
|
12320
12569
|
|
|
12321
12570
|
// src/platform/tui/components/ChatInput.tsx
|
|
12322
|
-
import { useMemo, useCallback as useCallback3, useRef as
|
|
12571
|
+
import { useMemo, useCallback as useCallback3, useRef as useRef4, memo as memo4, useState as useState4 } from "react";
|
|
12323
12572
|
import { Box as Box4, Text as Text5, useInput } from "ink";
|
|
12324
12573
|
import TextInput from "ink-text-input";
|
|
12325
12574
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
@@ -12342,24 +12591,25 @@ var ChatInput = memo4(({
|
|
|
12342
12591
|
return getMatchingCommands(partialCmd).slice(0, MAX_SUGGESTIONS);
|
|
12343
12592
|
}, [isSlashMode, partialCmd, hasArgs]);
|
|
12344
12593
|
const showPreview = isSlashMode && !hasArgs && suggestions.length > 0;
|
|
12345
|
-
const suggestionsRef =
|
|
12594
|
+
const suggestionsRef = useRef4(suggestions);
|
|
12346
12595
|
suggestionsRef.current = suggestions;
|
|
12347
|
-
const isSlashModeRef =
|
|
12596
|
+
const isSlashModeRef = useRef4(isSlashMode);
|
|
12348
12597
|
isSlashModeRef.current = isSlashMode;
|
|
12349
|
-
const hasArgsRef =
|
|
12598
|
+
const hasArgsRef = useRef4(hasArgs);
|
|
12350
12599
|
hasArgsRef.current = hasArgs;
|
|
12351
|
-
const inputRequestRef =
|
|
12600
|
+
const inputRequestRef = useRef4(inputRequest);
|
|
12352
12601
|
inputRequestRef.current = inputRequest;
|
|
12353
|
-
const onChangeRef =
|
|
12602
|
+
const onChangeRef = useRef4(onChange);
|
|
12354
12603
|
onChangeRef.current = onChange;
|
|
12604
|
+
const [inputKey, setInputKey] = useState4(0);
|
|
12355
12605
|
useInput(useCallback3((_input, key) => {
|
|
12356
12606
|
if (inputRequestRef.current.status === "active") return;
|
|
12357
12607
|
if (key.tab && isSlashModeRef.current && !hasArgsRef.current && suggestionsRef.current.length > 0) {
|
|
12358
12608
|
const best = suggestionsRef.current[0];
|
|
12359
12609
|
const argsHint = best.args ? " " : "";
|
|
12360
12610
|
const completed = `/${best.name}${argsHint}`;
|
|
12361
|
-
onChangeRef.current(
|
|
12362
|
-
|
|
12611
|
+
onChangeRef.current(completed);
|
|
12612
|
+
setInputKey((k) => k + 1);
|
|
12363
12613
|
}
|
|
12364
12614
|
}, []));
|
|
12365
12615
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
@@ -12425,7 +12675,8 @@ var ChatInput = memo4(({
|
|
|
12425
12675
|
onChange,
|
|
12426
12676
|
onSubmit,
|
|
12427
12677
|
placeholder
|
|
12428
|
-
}
|
|
12678
|
+
},
|
|
12679
|
+
inputKey
|
|
12429
12680
|
)
|
|
12430
12681
|
] })
|
|
12431
12682
|
}
|
|
@@ -12487,9 +12738,9 @@ var footer_default = Footer;
|
|
|
12487
12738
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
12488
12739
|
var App = ({ autoApprove = false, target }) => {
|
|
12489
12740
|
const { exit } = useApp();
|
|
12490
|
-
const [input, setInput] =
|
|
12491
|
-
const [secretInput, setSecretInput] =
|
|
12492
|
-
const [autoApproveMode, setAutoApproveMode] =
|
|
12741
|
+
const [input, setInput] = useState5("");
|
|
12742
|
+
const [secretInput, setSecretInput] = useState5("");
|
|
12743
|
+
const [autoApproveMode, setAutoApproveMode] = useState5(autoApprove);
|
|
12493
12744
|
const {
|
|
12494
12745
|
agent,
|
|
12495
12746
|
messages,
|
|
@@ -12508,11 +12759,11 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
12508
12759
|
addMessage,
|
|
12509
12760
|
refreshStats
|
|
12510
12761
|
} = useAgent(autoApproveMode, target);
|
|
12511
|
-
const isProcessingRef =
|
|
12762
|
+
const isProcessingRef = useRef5(isProcessing);
|
|
12512
12763
|
isProcessingRef.current = isProcessing;
|
|
12513
|
-
const autoApproveModeRef =
|
|
12764
|
+
const autoApproveModeRef = useRef5(autoApproveMode);
|
|
12514
12765
|
autoApproveModeRef.current = autoApproveMode;
|
|
12515
|
-
const inputRequestRef =
|
|
12766
|
+
const inputRequestRef = useRef5(inputRequest);
|
|
12516
12767
|
inputRequestRef.current = inputRequest;
|
|
12517
12768
|
const handleExit = useCallback4(() => {
|
|
12518
12769
|
const ir = inputRequestRef.current;
|
|
@@ -12755,6 +13006,7 @@ var CLI_SCAN_TYPES = Object.freeze([
|
|
|
12755
13006
|
]);
|
|
12756
13007
|
|
|
12757
13008
|
// src/platform/tui/main.tsx
|
|
13009
|
+
import gradient from "gradient-string";
|
|
12758
13010
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
12759
13011
|
initDebugLogger();
|
|
12760
13012
|
var program = new Command();
|
|
@@ -12763,13 +13015,13 @@ program.command("interactive", { isDefault: true }).alias("i").description("Star
|
|
|
12763
13015
|
const opts = program.opts();
|
|
12764
13016
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12765
13017
|
console.clear();
|
|
12766
|
-
console.log(
|
|
13018
|
+
console.log(gradient([HEX.primary, HEX.cyan, HEX.teal]).multiline(ASCII_BANNER));
|
|
12767
13019
|
console.log(
|
|
12768
|
-
" " + chalk.hex(
|
|
13020
|
+
" " + chalk.hex(HEX.gray)(`v${APP_VERSION}`) + chalk.hex(HEX.gray)(" \u2502 ") + chalk.hex(HEX.primary)("Type /help for commands") + "\n"
|
|
12769
13021
|
);
|
|
12770
13022
|
if (skipPermissions) {
|
|
12771
|
-
console.log(chalk.hex(
|
|
12772
|
-
console.log(chalk.hex(
|
|
13023
|
+
console.log(chalk.hex(HEX.red)("[!] WARNING: Running with --dangerously-skip-permissions"));
|
|
13024
|
+
console.log(chalk.hex(HEX.red)("[!] All tool executions will be auto-approved!\n"));
|
|
12773
13025
|
}
|
|
12774
13026
|
const { waitUntilExit } = render(
|
|
12775
13027
|
/* @__PURE__ */ jsx8(
|
|
@@ -12785,11 +13037,11 @@ program.command("interactive", { isDefault: true }).alias("i").description("Star
|
|
|
12785
13037
|
program.command("run <objective>").alias("r").description("Run a single objective and exit").option("-o, --output <file>", "Output file for results").option("--max-steps <n>", "Maximum number of steps", String(CLI_DEFAULT.MAX_STEPS)).action(async (objective, options) => {
|
|
12786
13038
|
const opts = program.opts();
|
|
12787
13039
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12788
|
-
console.log(
|
|
13040
|
+
console.log(gradient([HEX.primary, HEX.cyan, HEX.teal]).multiline(ASCII_BANNER));
|
|
12789
13041
|
if (skipPermissions) {
|
|
12790
|
-
console.log(chalk.hex(
|
|
13042
|
+
console.log(chalk.hex(HEX.red)("[!] WARNING: Running with --dangerously-skip-permissions\n"));
|
|
12791
13043
|
}
|
|
12792
|
-
console.log(chalk.hex(
|
|
13044
|
+
console.log(chalk.hex(HEX.primary)(`[target] Objective: ${objective}
|
|
12793
13045
|
`));
|
|
12794
13046
|
const agent = AgentFactory.createMainAgent(skipPermissions);
|
|
12795
13047
|
if (skipPermissions) {
|
|
@@ -12806,18 +13058,18 @@ program.command("run <objective>").alias("r").description("Run a single objectiv
|
|
|
12806
13058
|
process.on("SIGTERM", () => shutdown(EXIT_CODES.SIGTERM));
|
|
12807
13059
|
try {
|
|
12808
13060
|
const result2 = await agent.execute(objective);
|
|
12809
|
-
console.log(chalk.hex(
|
|
13061
|
+
console.log(chalk.hex(HEX.gray)("\n[+] Assessment complete!\n"));
|
|
12810
13062
|
console.log(result2);
|
|
12811
13063
|
if (options.output) {
|
|
12812
13064
|
const fs = await import("fs/promises");
|
|
12813
13065
|
await fs.writeFile(options.output, JSON.stringify({ result: result2 }, null, 2));
|
|
12814
|
-
console.log(chalk.hex(
|
|
13066
|
+
console.log(chalk.hex(HEX.primary)(`
|
|
12815
13067
|
[+] Report saved to: ${options.output}`));
|
|
12816
13068
|
}
|
|
12817
13069
|
await shutdown(0);
|
|
12818
13070
|
} catch (error) {
|
|
12819
13071
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
12820
|
-
console.error(chalk.hex(
|
|
13072
|
+
console.error(chalk.hex(HEX.red)(`
|
|
12821
13073
|
[-] Failed: ${errorMessage}`));
|
|
12822
13074
|
await shutdown(1);
|
|
12823
13075
|
}
|
|
@@ -12825,8 +13077,8 @@ program.command("run <objective>").alias("r").description("Run a single objectiv
|
|
|
12825
13077
|
program.command("scan <target>").description("Quick scan a target").option("-s, --scan-type <type>", `Scan type (${CLI_SCAN_TYPES.join("|")})`, CLI_DEFAULT.SCAN_TYPE).option("-p, --ports <ports>", "Specific ports to scan").action(async (target, options) => {
|
|
12826
13078
|
const opts = program.opts();
|
|
12827
13079
|
const skipPermissions = opts.dangerouslySkipPermissions || false;
|
|
12828
|
-
console.log(
|
|
12829
|
-
console.log(chalk.hex(
|
|
13080
|
+
console.log(gradient([HEX.primary, HEX.cyan, HEX.teal]).multiline(ASCII_BANNER));
|
|
13081
|
+
console.log(chalk.hex(HEX.primary)(`
|
|
12830
13082
|
[scan] Target: ${target} (${options.scanType})
|
|
12831
13083
|
`));
|
|
12832
13084
|
const agent = AgentFactory.createMainAgent(skipPermissions);
|
|
@@ -12839,62 +13091,61 @@ program.command("scan <target>").description("Quick scan a target").option("-s,
|
|
|
12839
13091
|
process.on("SIGTERM", () => shutdown(EXIT_CODES.SIGTERM));
|
|
12840
13092
|
try {
|
|
12841
13093
|
await agent.execute(`Perform a ${options.scanType} scan on ${target}${options.ports ? ` focusing on ports ${options.ports}` : ""}. Analyze the results and identify potential vulnerabilities.`);
|
|
12842
|
-
console.log(chalk.hex(
|
|
13094
|
+
console.log(chalk.hex(HEX.gray)("[+] Scan complete!"));
|
|
12843
13095
|
await shutdown(0);
|
|
12844
13096
|
} catch (error) {
|
|
12845
13097
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
12846
|
-
console.error(chalk.hex(
|
|
13098
|
+
console.error(chalk.hex(HEX.red)(`[-] Scan failed: ${errorMessage}`));
|
|
12847
13099
|
await shutdown(1);
|
|
12848
13100
|
}
|
|
12849
13101
|
});
|
|
12850
13102
|
program.command("help-extended").description("Show extended help with examples").action(() => {
|
|
12851
|
-
console.log(
|
|
13103
|
+
console.log(gradient([HEX.primary, HEX.cyan, HEX.teal]).multiline(ASCII_BANNER));
|
|
12852
13104
|
console.log(`
|
|
12853
|
-
${chalk.hex(
|
|
13105
|
+
${chalk.hex(HEX.primary)(APP_NAME + " - Autonomous Penetration Testing AI")}
|
|
12854
13106
|
|
|
12855
|
-
${chalk.hex(
|
|
13107
|
+
${chalk.hex(HEX.yellow)("Usage:")}
|
|
12856
13108
|
|
|
12857
|
-
${chalk.hex(
|
|
12858
|
-
${chalk.hex(
|
|
12859
|
-
${chalk.hex(
|
|
13109
|
+
${chalk.hex(HEX.gray)("$ pentesting")} Start interactive mode
|
|
13110
|
+
${chalk.hex(HEX.gray)("$ pentesting -t 192.168.1.1")} Start with target
|
|
13111
|
+
${chalk.hex(HEX.gray)("$ pentesting --dangerously-skip-permissions")} Auto-approve all tools
|
|
12860
13112
|
|
|
12861
|
-
${chalk.hex(
|
|
13113
|
+
${chalk.hex(HEX.yellow)("Commands:")}
|
|
12862
13114
|
|
|
12863
|
-
${chalk.hex(
|
|
12864
|
-
${chalk.hex(
|
|
12865
|
-
${chalk.hex(
|
|
13115
|
+
${chalk.hex(HEX.primary)("pentesting")} Interactive TUI mode
|
|
13116
|
+
${chalk.hex(HEX.primary)("pentesting run <objective>")} Run single objective
|
|
13117
|
+
${chalk.hex(HEX.primary)("pentesting scan <target>")} Quick scan target
|
|
12866
13118
|
|
|
12867
|
-
${chalk.hex(
|
|
13119
|
+
${chalk.hex(HEX.yellow)("Options:")}
|
|
12868
13120
|
|
|
12869
|
-
${chalk.hex(
|
|
12870
|
-
${chalk.hex(
|
|
12871
|
-
${chalk.hex(
|
|
13121
|
+
${chalk.hex(HEX.primary)("--dangerously-skip-permissions")} Skip all permission prompts
|
|
13122
|
+
${chalk.hex(HEX.primary)("-t, --target <ip>")} Set target
|
|
13123
|
+
${chalk.hex(HEX.primary)("-o, --output <file>")} Save results to file
|
|
12872
13124
|
|
|
12873
|
-
${chalk.hex(
|
|
13125
|
+
${chalk.hex(HEX.yellow)("Interactive Commands:")}
|
|
12874
13126
|
|
|
12875
|
-
${chalk.hex(
|
|
12876
|
-
${chalk.hex(
|
|
12877
|
-
${chalk.hex(
|
|
12878
|
-
${chalk.hex(
|
|
12879
|
-
${chalk.hex(
|
|
12880
|
-
${chalk.hex(THEME.primary)("/reset")} Reset session
|
|
13127
|
+
${chalk.hex(HEX.primary)("/target <ip>")} Set target
|
|
13128
|
+
${chalk.hex(HEX.primary)("/start")} Start autonomous mode
|
|
13129
|
+
${chalk.hex(HEX.primary)("/hint <text>")} Provide hint
|
|
13130
|
+
${chalk.hex(HEX.primary)("/findings")} Show findings
|
|
13131
|
+
${chalk.hex(HEX.primary)("/clear")} Reset session
|
|
12881
13132
|
|
|
12882
|
-
${chalk.hex(
|
|
13133
|
+
${chalk.hex(HEX.yellow)("Examples:")}
|
|
12883
13134
|
|
|
12884
|
-
${chalk.hex(
|
|
13135
|
+
${chalk.hex(HEX.gray)("# Full autonomous mode")}
|
|
12885
13136
|
$ pentesting --dangerously-skip-permissions -t 10.10.10.5
|
|
12886
13137
|
|
|
12887
|
-
${chalk.hex(
|
|
13138
|
+
${chalk.hex(HEX.gray)("# Run specific objective")}
|
|
12888
13139
|
$ pentesting run "Find SQL injection" -t http://target.com -o report.json
|
|
12889
13140
|
|
|
12890
|
-
${chalk.hex(
|
|
13141
|
+
${chalk.hex(HEX.gray)("# Quick vulnerability scan")}
|
|
12891
13142
|
$ pentesting scan 192.168.1.1 -s vuln
|
|
12892
13143
|
|
|
12893
|
-
${chalk.hex(
|
|
13144
|
+
${chalk.hex(HEX.yellow)("Environment:")}
|
|
12894
13145
|
|
|
12895
|
-
${chalk.hex(
|
|
12896
|
-
${chalk.hex(
|
|
12897
|
-
${chalk.hex(
|
|
13146
|
+
${chalk.hex(HEX.primary)("PENTEST_API_KEY")} Required - LLM API key
|
|
13147
|
+
${chalk.hex(HEX.primary)("PENTEST_BASE_URL")} Optional - AI API base URL
|
|
13148
|
+
${chalk.hex(HEX.primary)("PENTEST_MODEL")} Optional - Model override
|
|
12898
13149
|
`);
|
|
12899
13150
|
});
|
|
12900
13151
|
program.parse();
|