pentesting 0.2.3 → 0.2.5
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 +149 -121
- package/dist/index.js +235 -182
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,130 +1,125 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
```
|
|
2
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
3
|
+
║ ║
|
|
4
|
+
║ ██████╗ ███████╗███╗ ██╗████████╗███████╗███████╗████████╗║
|
|
5
|
+
║ ██╔══██╗██╔════╝████╗ ██║╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝║
|
|
6
|
+
║ ██████╔╝█████╗ ██╔██╗ ██║ ██║ █████╗ ███████╗ ██║ ║
|
|
7
|
+
║ ██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██╔══╝ ╚════██║ ██║ ║
|
|
8
|
+
║ ██║ ███████╗██║ ╚████║ ██║ ███████╗███████║ ██║ ║
|
|
9
|
+
║ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚══════╝ ╚═╝ ║
|
|
10
|
+
║ ║
|
|
11
|
+
║ 🎯 DEF CON-level Autonomous Pentesting Agent ║
|
|
12
|
+
║ ║
|
|
13
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
14
|
+
```
|
|
8
15
|
|
|
9
16
|
[](https://www.npmjs.com/package/pentesting)
|
|
10
17
|
[](https://hub.docker.com/r/agnusdei1207/pentesting-tools)
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- **7-Phase Attack Workflow**: Recon → Scan → Enum → Vuln Analysis → Exploitation → PrivEsc → Reporting
|
|
15
|
-
- **9 Specialized Agents**: Built-in experts for each security domain
|
|
16
|
-
- **Ralph Loop**: Autonomous iteration until objective is achieved
|
|
17
|
-
- **Streaming Responses**: Real-time output from Claude
|
|
18
|
-
- **Session Persistence**: Save/resume pentesting sessions
|
|
19
|
-
- **Tool Approval**: Manual confirmation for dangerous commands
|
|
20
|
-
- **MCP Integration**: Extend with Model Context Protocol tools
|
|
21
|
-
- **Docker Toolkit**: 50+ pre-installed pentesting tools
|
|
22
|
-
|
|
23
|
-
## Quick Start
|
|
19
|
+
---
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
## 🚀 Quick Start
|
|
26
22
|
|
|
27
23
|
```bash
|
|
24
|
+
# Install
|
|
28
25
|
npm install -g pentesting
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Configure
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
# Required: API Key (either works)
|
|
27
|
+
# Configure
|
|
35
28
|
export PENTEST_API_KEY=your_api_key
|
|
36
|
-
# or
|
|
37
|
-
export ANTHROPIC_API_KEY=your_api_key
|
|
38
|
-
|
|
39
|
-
# For other providers (GLM, OpenRouter, etc.)
|
|
40
29
|
export PENTEST_BASE_URL=https://your-api-endpoint.com/v1
|
|
41
30
|
export PENTEST_MODEL=your-model-name
|
|
42
|
-
export PENTEST_MAX_TOKENS=16384
|
|
43
|
-
```
|
|
44
31
|
|
|
45
|
-
|
|
32
|
+
export PENTEST_API_KEY="key"
|
|
33
|
+
export PENTEST_BASE_URL="https://api.z.ai/api/anthropic"
|
|
34
|
+
export PENTEST_MODEL="glm-4.7"
|
|
46
35
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
pentesting
|
|
36
|
+
|
|
37
|
+
# Run
|
|
38
|
+
pentesting
|
|
50
39
|
```
|
|
51
40
|
|
|
52
|
-
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## ✨ Features
|
|
44
|
+
|
|
45
|
+
- **10-Phase Attack Workflow**: Recon → Scan → Enum → Vuln Analysis → Exploitation → PrivEsc → Pivot → Persist → Exfil → Report
|
|
46
|
+
- **9 Specialized Agents**: Built-in experts for each security domain
|
|
47
|
+
- **Ralph Loop**: Autonomous iteration until objective is achieved
|
|
48
|
+
- **Streaming Responses**: Real-time LLM output
|
|
49
|
+
- **Session Persistence**: Save/resume pentesting sessions
|
|
50
|
+
- **Tool Approval**: Manual confirmation for dangerous commands
|
|
51
|
+
- **MCP Integration**: Extend with Model Context Protocol tools
|
|
52
|
+
- **Docker Toolkit**: 50+ pre-installed pentesting tools
|
|
53
|
+
- **Provider Agnostic**: Works with any OpenAI-compatible API
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 📖 CLI Commands
|
|
53
58
|
|
|
54
59
|
```bash
|
|
60
|
+
# Target & Session
|
|
55
61
|
/target <ip> Set target
|
|
56
62
|
/start [objective] Start autonomous pentest
|
|
63
|
+
/sessions List saved sessions
|
|
64
|
+
/resume [id] Resume a session
|
|
65
|
+
|
|
66
|
+
# Scanning & Enumeration
|
|
57
67
|
/scan <target> Quick enumeration
|
|
68
|
+
/web <url> Web application testing
|
|
69
|
+
|
|
70
|
+
# Exploitation
|
|
58
71
|
/exploit <service> Search for exploits
|
|
59
72
|
/privesc [os] Check privilege escalation vectors
|
|
60
|
-
/web <url> Web application testing
|
|
61
|
-
/hash <hash> Identify and crack hashes
|
|
62
73
|
/attack <objective> Execute attack chain
|
|
74
|
+
/hash <hash> Identify and crack hashes
|
|
75
|
+
|
|
76
|
+
# Reporting
|
|
63
77
|
/report Generate pentest report
|
|
64
|
-
/
|
|
65
|
-
|
|
78
|
+
/findings Show findings
|
|
79
|
+
|
|
80
|
+
# Control
|
|
66
81
|
/yolo Toggle auto-approve mode
|
|
67
82
|
/approve /deny Approve/deny tool execution
|
|
68
|
-
/findings Show findings
|
|
69
83
|
/clear Clear screen
|
|
70
84
|
/exit Exit
|
|
71
85
|
```
|
|
72
86
|
|
|
73
|
-
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 🤖 Built-in Agents
|
|
74
90
|
|
|
75
91
|
| Agent | Specialty |
|
|
76
92
|
|-------|-----------|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
87
|
-
## Architecture
|
|
93
|
+
| `target-explorer` | Network reconnaissance, service enumeration |
|
|
94
|
+
| `exploit-researcher` | CVE research, exploit development |
|
|
95
|
+
| `privesc-master` | Linux/Windows privilege escalation |
|
|
96
|
+
| `web-hacker` | OWASP Top 10, SQLi, XSS, SSRF |
|
|
97
|
+
| `crypto-solver` | Hash cracking, cipher analysis |
|
|
98
|
+
| `forensics-analyst` | Memory forensics, file carving |
|
|
99
|
+
| `reverse-engineer` | Binary analysis, exploit development |
|
|
100
|
+
| `attack-architect` | Attack strategy planning |
|
|
101
|
+
| `finding-reviewer` | Vulnerability validation |
|
|
88
102
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
│ - Streaming text display │
|
|
93
|
-
│ - Tool approval prompts │
|
|
94
|
-
│ - Session management │
|
|
95
|
-
└──────────────────────────┬──────────────────────────────────┘
|
|
96
|
-
│ Wire Protocol
|
|
97
|
-
┌──────────────────────────▼──────────────────────────────────┐
|
|
98
|
-
│ PentestingAgent (Unified) │
|
|
99
|
-
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
100
|
-
│ │ RalphLoop │ │ Streaming │ │ Session │ │
|
|
101
|
-
│ │ (Auto-iter) │ │ Handler │ │ Manager │ │
|
|
102
|
-
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
103
|
-
│ │
|
|
104
|
-
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
105
|
-
│ │ Context │ │ Retry │ │ Approval │ │
|
|
106
|
-
│ │ Compaction │ │ Handler │ │ Manager │ │
|
|
107
|
-
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
108
|
-
│ │
|
|
109
|
-
│ ┌──────────────────────────────────────────────────┐ │
|
|
110
|
-
│ │ AutonomousHackingAgent (Core) │ │
|
|
111
|
-
│ │ ┌──────────────────────────────────────────┐ │ │
|
|
112
|
-
│ │ │ 9 Built-in Specialized Agents │ │ │
|
|
113
|
-
│ │ │ (No plugins needed) │ │ │
|
|
114
|
-
│ │ └──────────────────────────────────────────┘ │ │
|
|
115
|
-
│ │ - Hook System │ │
|
|
116
|
-
│ │ - MCP Client for Extended Tools │ │
|
|
117
|
-
│ └──────────────────────────────────────────────────┘ │
|
|
118
|
-
└──────────────────────────┬──────────────────────────────────┘
|
|
119
|
-
│
|
|
120
|
-
┌────────────────┼────────────────┐
|
|
121
|
-
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
|
|
122
|
-
│ Tool │ │ Bash │ │ MCP │
|
|
123
|
-
│Executor │ │ Commands│ │ Servers │
|
|
124
|
-
└─────────┘ └─────────┘ └─────────┘
|
|
125
|
-
```
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## ⚙️ Configuration
|
|
126
106
|
|
|
127
|
-
|
|
107
|
+
### Environment Variables
|
|
108
|
+
|
|
109
|
+
| Variable | Description | Default |
|
|
110
|
+
|----------|-------------|---------|
|
|
111
|
+
| `PENTEST_API_KEY` | LLM API key | Required |
|
|
112
|
+
| `PENTEST_BASE_URL` | API endpoint URL | - |
|
|
113
|
+
| `PENTEST_MODEL` | Model name | claude-sonnet-4-20250514 |
|
|
114
|
+
| `PENTEST_MAX_TOKENS` | Max response tokens | 16384 |
|
|
115
|
+
| `PENTESTING_DOCKER` | Force Docker execution | 0 |
|
|
116
|
+
| `PENTESTING_CONTAINER` | Docker container name | pentesting-tools |
|
|
117
|
+
|
|
118
|
+
> **Note**: `ANTHROPIC_API_KEY` is also accepted as fallback for `PENTEST_API_KEY`.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 💻 Programmatic Usage
|
|
128
123
|
|
|
129
124
|
```typescript
|
|
130
125
|
import { PentestingAgent, PENTEST_EVENT } from 'pentesting';
|
|
@@ -158,7 +153,9 @@ const scanResult = await agent.chat('/scan 10.10.10.1');
|
|
|
158
153
|
const exploitResult = await agent.chat('/exploit Apache 2.4.49');
|
|
159
154
|
```
|
|
160
155
|
|
|
161
|
-
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 🐳 Docker Environment
|
|
162
159
|
|
|
163
160
|
```bash
|
|
164
161
|
# Pull pre-built toolkit (50+ tools)
|
|
@@ -173,7 +170,9 @@ docker run -d --name pentesting-tools --network host \
|
|
|
173
170
|
docker exec -it pentesting-tools nmap -sCV 10.0.0.1
|
|
174
171
|
```
|
|
175
172
|
|
|
176
|
-
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 🔌 MCP Integration
|
|
177
176
|
|
|
178
177
|
Extend with additional MCP servers:
|
|
179
178
|
|
|
@@ -191,32 +190,50 @@ await agent.addMCPServer('security-tools', 'docker', [
|
|
|
191
190
|
]);
|
|
192
191
|
```
|
|
193
192
|
|
|
194
|
-
|
|
193
|
+
---
|
|
195
194
|
|
|
196
|
-
|
|
195
|
+
## 🏗️ Architecture
|
|
197
196
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
197
|
+
```
|
|
198
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
199
|
+
│ TUI (app.tsx) │
|
|
200
|
+
│ - Streaming text display │
|
|
201
|
+
│ - Tool approval prompts │
|
|
202
|
+
│ - Session management │
|
|
203
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
204
|
+
│ Wire Protocol
|
|
205
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
206
|
+
│ PentestingAgent (Unified) │
|
|
207
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
208
|
+
│ │ RalphLoop │ │ Streaming │ │ Session │ │
|
|
209
|
+
│ │ (Auto-iter) │ │ Handler │ │ Manager │ │
|
|
210
|
+
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
211
|
+
│ │
|
|
212
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
213
|
+
│ │ AutonomousHackingAgent (Core) │ │
|
|
214
|
+
│ │ ┌──────────────────────────────────────────┐ │ │
|
|
215
|
+
│ │ │ 9 Built-in Specialized Agents │ │ │
|
|
216
|
+
│ │ └──────────────────────────────────────────┘ │ │
|
|
217
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
218
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
219
|
+
│
|
|
220
|
+
┌────────────────┼────────────────┐
|
|
221
|
+
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
|
|
222
|
+
│ Tool │ │ Bash │ │ MCP │
|
|
223
|
+
│Executor │ │ Commands│ │ Servers │
|
|
224
|
+
└─────────┘ └─────────┘ └─────────┘
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
206
228
|
|
|
207
|
-
## Project Structure
|
|
229
|
+
## 📁 Project Structure
|
|
208
230
|
|
|
209
231
|
```
|
|
210
232
|
src/
|
|
211
233
|
├── index.tsx # CLI entry point
|
|
212
|
-
├── cli/
|
|
213
|
-
│ └── app.tsx # TUI with streaming, approval, sessions
|
|
234
|
+
├── cli/app.tsx # TUI with streaming, approval, sessions
|
|
214
235
|
├── core/
|
|
215
|
-
│ ├──
|
|
216
|
-
│ ├── agent/
|
|
217
|
-
│ │ ├── pentesting-agent.ts # Unified agent
|
|
218
|
-
│ │ ├── autonomous-agent.ts # Core agent logic
|
|
219
|
-
│ │ └── agent-orchestrator.ts # Parallel agent execution
|
|
236
|
+
│ ├── agent/ # Agent implementations
|
|
220
237
|
│ ├── approval/ # Tool approval system
|
|
221
238
|
│ ├── context/ # Conversation compaction
|
|
222
239
|
│ ├── hooks/ # Event hooks
|
|
@@ -225,17 +242,16 @@ src/
|
|
|
225
242
|
│ ├── streaming/ # Real-time streaming
|
|
226
243
|
│ ├── prompts/ # System prompts
|
|
227
244
|
│ └── tools/ # Tool definitions & executor
|
|
228
|
-
├── agents/
|
|
229
|
-
|
|
230
|
-
├──
|
|
231
|
-
│ └── index.ts # Built-in slash commands
|
|
232
|
-
├── wire/ # Agent-UI communication protocol
|
|
245
|
+
├── agents/index.ts # 9 built-in specialized agents
|
|
246
|
+
├── commands/index.ts # Built-in slash commands
|
|
247
|
+
├── wire/ # Agent-UI communication
|
|
233
248
|
├── mcp/ # MCP client integration
|
|
234
|
-
├── utils/ # Retry logic, utilities
|
|
235
249
|
└── config/ # Constants, theme
|
|
236
250
|
```
|
|
237
251
|
|
|
238
|
-
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## 🛠️ Development
|
|
239
255
|
|
|
240
256
|
```bash
|
|
241
257
|
# Clone
|
|
@@ -252,12 +268,24 @@ npm run build
|
|
|
252
268
|
npm run dev
|
|
253
269
|
```
|
|
254
270
|
|
|
255
|
-
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 📚 Documentation
|
|
256
274
|
|
|
257
|
-
|
|
275
|
+
- [Architecture](docs/architecture.md) - System design and components
|
|
276
|
+
- [API Reference](docs/api-reference.md) - Full API documentation
|
|
277
|
+
- [Troubleshooting](docs/troubleshooting.md) - Common issues
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## ⚠️ Legal
|
|
282
|
+
|
|
283
|
+
**Only use on systems you own or have explicit permission to test.**
|
|
258
284
|
|
|
259
285
|
This tool is for authorized penetration testing and CTF competitions only. Unauthorized access to computer systems is illegal.
|
|
260
286
|
|
|
261
|
-
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 📄 License
|
|
262
290
|
|
|
263
291
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import Spinner from "ink-spinner";
|
|
|
12
12
|
|
|
13
13
|
// src/core/agent/autonomous-agent.ts
|
|
14
14
|
import Anthropic from "@anthropic-ai/sdk";
|
|
15
|
-
import { EventEmitter as
|
|
15
|
+
import { EventEmitter as EventEmitter4 } from "events";
|
|
16
16
|
|
|
17
17
|
// src/core/prompts/autonomous-prompt.ts
|
|
18
18
|
var AUTONOMOUS_HACKING_PROMPT = `You are Hacker-Code, an elite autonomous penetration testing AI designed for CTF competitions and professional security assessments. You operate with minimal human intervention, making intelligent decisions, adapting to obstacles, and persistently pursuing objectives until complete system compromise.
|
|
@@ -251,6 +251,8 @@ var AGENT_EVENT = {
|
|
|
251
251
|
TOOL_CALL: "tool_call",
|
|
252
252
|
TOOL_RESULT: "tool_result",
|
|
253
253
|
COMMAND_EXECUTE: "command_execute",
|
|
254
|
+
APPROVAL_NEEDED: "approval_needed",
|
|
255
|
+
TOKEN_USAGE: "token_usage",
|
|
254
256
|
// State changes
|
|
255
257
|
TARGET_SET: "target_set",
|
|
256
258
|
PHASE_CHANGE: "phase_change",
|
|
@@ -1374,7 +1376,7 @@ const { chromium } = require('playwright');
|
|
|
1374
1376
|
}
|
|
1375
1377
|
|
|
1376
1378
|
// src/config/constants.ts
|
|
1377
|
-
var APP_VERSION = "0.2.
|
|
1379
|
+
var APP_VERSION = "0.2.5";
|
|
1378
1380
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
1379
1381
|
var LLM_API_KEY = process.env.PENTEST_API_KEY || process.env.ANTHROPIC_API_KEY || "";
|
|
1380
1382
|
var LLM_BASE_URL = process.env.PENTEST_BASE_URL || void 0;
|
|
@@ -1732,6 +1734,183 @@ function getMCPManager() {
|
|
|
1732
1734
|
return mcpManager;
|
|
1733
1735
|
}
|
|
1734
1736
|
|
|
1737
|
+
// src/core/approval/approval-manager.ts
|
|
1738
|
+
import { EventEmitter as EventEmitter3 } from "events";
|
|
1739
|
+
var APPROVAL_EVENT = {
|
|
1740
|
+
REQUEST: "approval_request",
|
|
1741
|
+
RESPONSE: "approval_response",
|
|
1742
|
+
TIMEOUT: "approval_timeout"
|
|
1743
|
+
};
|
|
1744
|
+
var CRITICAL_TOOLS = [
|
|
1745
|
+
"execute_command",
|
|
1746
|
+
"write_file",
|
|
1747
|
+
"delete_file",
|
|
1748
|
+
"modify_file",
|
|
1749
|
+
"send_request",
|
|
1750
|
+
"exploit_execute"
|
|
1751
|
+
];
|
|
1752
|
+
var HIGH_RISK_PATTERNS = [
|
|
1753
|
+
/rm\s+-rf/i,
|
|
1754
|
+
/mkfs/i,
|
|
1755
|
+
/dd\s+if=/i,
|
|
1756
|
+
/format/i,
|
|
1757
|
+
/shutdown/i,
|
|
1758
|
+
/reboot/i,
|
|
1759
|
+
/kill\s+-9/i,
|
|
1760
|
+
/pkill/i,
|
|
1761
|
+
/iptables/i,
|
|
1762
|
+
/ufw/i,
|
|
1763
|
+
/firewall/i,
|
|
1764
|
+
/passwd/i,
|
|
1765
|
+
/useradd/i,
|
|
1766
|
+
/userdel/i,
|
|
1767
|
+
/chmod\s+777/i,
|
|
1768
|
+
/chown/i,
|
|
1769
|
+
/sudo/i,
|
|
1770
|
+
/su\s+-/i,
|
|
1771
|
+
/nc\s+-e/i,
|
|
1772
|
+
/bash\s+-i/i,
|
|
1773
|
+
/reverse.*shell/i,
|
|
1774
|
+
/bind.*shell/i,
|
|
1775
|
+
/meterpreter/i,
|
|
1776
|
+
/mimikatz/i
|
|
1777
|
+
];
|
|
1778
|
+
function assessRisk(toolName, toolInput) {
|
|
1779
|
+
const inputStr = JSON.stringify(toolInput).toLowerCase();
|
|
1780
|
+
for (const pattern of HIGH_RISK_PATTERNS) {
|
|
1781
|
+
if (pattern.test(inputStr)) {
|
|
1782
|
+
return "critical";
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
if (CRITICAL_TOOLS.includes(toolName)) {
|
|
1786
|
+
return "high";
|
|
1787
|
+
}
|
|
1788
|
+
if (toolName.includes("script") || toolName.includes("exec")) {
|
|
1789
|
+
return "medium";
|
|
1790
|
+
}
|
|
1791
|
+
if (toolName.includes("scan") || toolName.includes("request")) {
|
|
1792
|
+
return "medium";
|
|
1793
|
+
}
|
|
1794
|
+
return "low";
|
|
1795
|
+
}
|
|
1796
|
+
function generateRequestId() {
|
|
1797
|
+
return `approval_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
|
1798
|
+
}
|
|
1799
|
+
var ApprovalManager = class extends EventEmitter3 {
|
|
1800
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
1801
|
+
autoApprovedTools = /* @__PURE__ */ new Set();
|
|
1802
|
+
autoDeniedTools = /* @__PURE__ */ new Set();
|
|
1803
|
+
yoloMode = false;
|
|
1804
|
+
defaultTimeout = 6e4;
|
|
1805
|
+
// 1 minute
|
|
1806
|
+
constructor(options) {
|
|
1807
|
+
super();
|
|
1808
|
+
this.yoloMode = options?.yoloMode ?? false;
|
|
1809
|
+
this.defaultTimeout = options?.timeout ?? 6e4;
|
|
1810
|
+
}
|
|
1811
|
+
/**
|
|
1812
|
+
* Enable/disable YOLO mode (auto-approve everything)
|
|
1813
|
+
*/
|
|
1814
|
+
setYoloMode(enabled) {
|
|
1815
|
+
this.yoloMode = enabled;
|
|
1816
|
+
this.emit("yolo_mode_changed", enabled);
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Check if approval is required for a tool call
|
|
1820
|
+
*/
|
|
1821
|
+
requiresApproval(toolName, toolInput) {
|
|
1822
|
+
if (this.yoloMode) return false;
|
|
1823
|
+
if (this.autoApprovedTools.has(toolName)) return false;
|
|
1824
|
+
if (this.autoDeniedTools.has(toolName)) return true;
|
|
1825
|
+
const risk = assessRisk(toolName, toolInput);
|
|
1826
|
+
if (risk === "low") return false;
|
|
1827
|
+
return true;
|
|
1828
|
+
}
|
|
1829
|
+
/**
|
|
1830
|
+
* Request approval for a tool call
|
|
1831
|
+
*/
|
|
1832
|
+
async requestApproval(toolName, toolInput, reason) {
|
|
1833
|
+
if (this.autoDeniedTools.has(toolName)) {
|
|
1834
|
+
return "deny";
|
|
1835
|
+
}
|
|
1836
|
+
if (this.autoApprovedTools.has(toolName)) {
|
|
1837
|
+
return "approve";
|
|
1838
|
+
}
|
|
1839
|
+
const risk = assessRisk(toolName, toolInput);
|
|
1840
|
+
const request = {
|
|
1841
|
+
id: generateRequestId(),
|
|
1842
|
+
toolName,
|
|
1843
|
+
toolInput,
|
|
1844
|
+
reason: reason || `Tool "${toolName}" requires approval (${risk} risk)`,
|
|
1845
|
+
riskLevel: risk,
|
|
1846
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1847
|
+
};
|
|
1848
|
+
this.pendingRequests.set(request.id, request);
|
|
1849
|
+
this.emit(APPROVAL_EVENT.REQUEST, request);
|
|
1850
|
+
return new Promise((resolve) => {
|
|
1851
|
+
const timeout = setTimeout(() => {
|
|
1852
|
+
this.pendingRequests.delete(request.id);
|
|
1853
|
+
this.emit(APPROVAL_EVENT.TIMEOUT, request.id);
|
|
1854
|
+
resolve("deny");
|
|
1855
|
+
}, this.defaultTimeout);
|
|
1856
|
+
const responseHandler = (response) => {
|
|
1857
|
+
if (response.requestId === request.id) {
|
|
1858
|
+
clearTimeout(timeout);
|
|
1859
|
+
this.pendingRequests.delete(request.id);
|
|
1860
|
+
this.removeListener(APPROVAL_EVENT.RESPONSE, responseHandler);
|
|
1861
|
+
if (response.decision === "approve_always") {
|
|
1862
|
+
this.autoApprovedTools.add(toolName);
|
|
1863
|
+
resolve("approve");
|
|
1864
|
+
} else if (response.decision === "deny_always") {
|
|
1865
|
+
this.autoDeniedTools.add(toolName);
|
|
1866
|
+
resolve("deny");
|
|
1867
|
+
} else {
|
|
1868
|
+
resolve(response.decision);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
this.on(APPROVAL_EVENT.RESPONSE, responseHandler);
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Respond to an approval request (called by UI)
|
|
1877
|
+
*/
|
|
1878
|
+
respond(requestId, decision) {
|
|
1879
|
+
const response = {
|
|
1880
|
+
requestId,
|
|
1881
|
+
decision,
|
|
1882
|
+
respondedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1883
|
+
};
|
|
1884
|
+
this.emit(APPROVAL_EVENT.RESPONSE, response);
|
|
1885
|
+
}
|
|
1886
|
+
/**
|
|
1887
|
+
* Get pending requests
|
|
1888
|
+
*/
|
|
1889
|
+
getPendingRequests() {
|
|
1890
|
+
return Array.from(this.pendingRequests.values());
|
|
1891
|
+
}
|
|
1892
|
+
/**
|
|
1893
|
+
* Get auto-approved tools
|
|
1894
|
+
*/
|
|
1895
|
+
getAutoApprovedTools() {
|
|
1896
|
+
return Array.from(this.autoApprovedTools);
|
|
1897
|
+
}
|
|
1898
|
+
/**
|
|
1899
|
+
* Reset all auto decisions
|
|
1900
|
+
*/
|
|
1901
|
+
resetAutoDecisions() {
|
|
1902
|
+
this.autoApprovedTools.clear();
|
|
1903
|
+
this.autoDeniedTools.clear();
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
1906
|
+
var approvalManager = null;
|
|
1907
|
+
function getApprovalManager(options) {
|
|
1908
|
+
if (!approvalManager) {
|
|
1909
|
+
approvalManager = new ApprovalManager(options);
|
|
1910
|
+
}
|
|
1911
|
+
return approvalManager;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1735
1914
|
// src/core/tools/web-search.ts
|
|
1736
1915
|
import { spawn as spawn4 } from "child_process";
|
|
1737
1916
|
async function searchDuckDuckGo(query, options = {}) {
|
|
@@ -2959,7 +3138,7 @@ var DEFAULT_PHASES = [
|
|
|
2959
3138
|
{ id: PHASE_ID.EXFIL, name: "Data Exfiltration", shortName: "Exfil", status: PHASE_STATUS.PENDING, attempts: 0 },
|
|
2960
3139
|
{ id: PHASE_ID.REPORT, name: "Reporting", shortName: "Report", status: PHASE_STATUS.PENDING, attempts: 0 }
|
|
2961
3140
|
];
|
|
2962
|
-
var AutonomousHackingAgent = class extends
|
|
3141
|
+
var AutonomousHackingAgent = class extends EventEmitter4 {
|
|
2963
3142
|
client;
|
|
2964
3143
|
state;
|
|
2965
3144
|
config;
|
|
@@ -2970,6 +3149,13 @@ var AutonomousHackingAgent = class extends EventEmitter3 {
|
|
|
2970
3149
|
hookExecutor;
|
|
2971
3150
|
mcpManager;
|
|
2972
3151
|
contextManager;
|
|
3152
|
+
approvalManager;
|
|
3153
|
+
// Token usage tracking
|
|
3154
|
+
tokenUsage = {
|
|
3155
|
+
input: 0,
|
|
3156
|
+
output: 0,
|
|
3157
|
+
total: 0
|
|
3158
|
+
};
|
|
2973
3159
|
// Rabbit hole detection settings
|
|
2974
3160
|
STUCK_THRESHOLD = 5;
|
|
2975
3161
|
// Same action repeat count
|
|
@@ -2988,6 +3174,7 @@ var AutonomousHackingAgent = class extends EventEmitter3 {
|
|
|
2988
3174
|
this.hookExecutor = getHookExecutor();
|
|
2989
3175
|
this.mcpManager = getMCPManager();
|
|
2990
3176
|
this.contextManager = new ContextManager(this.client);
|
|
3177
|
+
this.approvalManager = getApprovalManager({ yoloMode: config?.autoApprove });
|
|
2991
3178
|
this.state = this.createInitialState();
|
|
2992
3179
|
this.initSystems();
|
|
2993
3180
|
}
|
|
@@ -3399,6 +3586,12 @@ Goal: Deep penetration to obtain root/system privileges, extract internal data,
|
|
|
3399
3586
|
}
|
|
3400
3587
|
}
|
|
3401
3588
|
);
|
|
3589
|
+
if (response.usage) {
|
|
3590
|
+
this.tokenUsage.input += response.usage.input_tokens;
|
|
3591
|
+
this.tokenUsage.output += response.usage.output_tokens;
|
|
3592
|
+
this.tokenUsage.total = this.tokenUsage.input + this.tokenUsage.output;
|
|
3593
|
+
this.emit(AGENT_EVENT.TOKEN_USAGE, this.tokenUsage);
|
|
3594
|
+
}
|
|
3402
3595
|
return this.processResponse(response);
|
|
3403
3596
|
}
|
|
3404
3597
|
buildContextPrompt() {
|
|
@@ -3457,6 +3650,29 @@ Use report_finding tool for important discoveries.
|
|
|
3457
3650
|
this.think(THOUGHT_TYPE.STUCK, `Tool blocked by hook: ${hookCheck.output}`);
|
|
3458
3651
|
continue;
|
|
3459
3652
|
}
|
|
3653
|
+
if (this.approvalManager.requiresApproval(toolName, toolInput)) {
|
|
3654
|
+
const risk = assessRisk(toolName, toolInput);
|
|
3655
|
+
this.emit(AGENT_EVENT.APPROVAL_NEEDED, {
|
|
3656
|
+
id: block.id,
|
|
3657
|
+
toolName,
|
|
3658
|
+
toolInput,
|
|
3659
|
+
riskLevel: risk
|
|
3660
|
+
});
|
|
3661
|
+
const decision = await this.approvalManager.requestApproval(
|
|
3662
|
+
toolName,
|
|
3663
|
+
toolInput,
|
|
3664
|
+
`Executing ${toolName} (${risk} risk)`
|
|
3665
|
+
);
|
|
3666
|
+
if (decision === "deny") {
|
|
3667
|
+
this.think(THOUGHT_TYPE.STUCK, `Tool denied by user: ${toolName}`);
|
|
3668
|
+
this.emit(AGENT_EVENT.TOOL_RESULT, {
|
|
3669
|
+
id: block.id,
|
|
3670
|
+
name: toolName,
|
|
3671
|
+
result: { success: false, output: "Denied by user" }
|
|
3672
|
+
});
|
|
3673
|
+
continue;
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3460
3676
|
const result = await executeToolCall(toolName, toolInput);
|
|
3461
3677
|
await this.hookExecutor.runPostToolUse(toolName, result.output || "");
|
|
3462
3678
|
const resultType = result.success ? "result" : "result";
|
|
@@ -3833,14 +4049,14 @@ Respond helpfully to the user's message. If they ask to perform security testing
|
|
|
3833
4049
|
// src/core/session/session-manager.ts
|
|
3834
4050
|
import * as fs3 from "fs/promises";
|
|
3835
4051
|
import * as path3 from "path";
|
|
3836
|
-
import { EventEmitter as
|
|
4052
|
+
import { EventEmitter as EventEmitter5 } from "events";
|
|
3837
4053
|
var SESSIONS_DIR = ".pentesting/sessions";
|
|
3838
4054
|
function generateSessionId() {
|
|
3839
4055
|
const timestamp = Date.now().toString(36);
|
|
3840
4056
|
const random = Math.random().toString(36).substring(2, 8);
|
|
3841
4057
|
return `session_${timestamp}_${random}`;
|
|
3842
4058
|
}
|
|
3843
|
-
var SessionManager = class extends
|
|
4059
|
+
var SessionManager = class extends EventEmitter5 {
|
|
3844
4060
|
sessionsDir;
|
|
3845
4061
|
currentSession = null;
|
|
3846
4062
|
constructor(baseDir) {
|
|
@@ -4015,183 +4231,6 @@ function getSessionManager() {
|
|
|
4015
4231
|
return sessionManager;
|
|
4016
4232
|
}
|
|
4017
4233
|
|
|
4018
|
-
// src/core/approval/approval-manager.ts
|
|
4019
|
-
import { EventEmitter as EventEmitter5 } from "events";
|
|
4020
|
-
var APPROVAL_EVENT = {
|
|
4021
|
-
REQUEST: "approval_request",
|
|
4022
|
-
RESPONSE: "approval_response",
|
|
4023
|
-
TIMEOUT: "approval_timeout"
|
|
4024
|
-
};
|
|
4025
|
-
var CRITICAL_TOOLS = [
|
|
4026
|
-
"execute_command",
|
|
4027
|
-
"write_file",
|
|
4028
|
-
"delete_file",
|
|
4029
|
-
"modify_file",
|
|
4030
|
-
"send_request",
|
|
4031
|
-
"exploit_execute"
|
|
4032
|
-
];
|
|
4033
|
-
var HIGH_RISK_PATTERNS = [
|
|
4034
|
-
/rm\s+-rf/i,
|
|
4035
|
-
/mkfs/i,
|
|
4036
|
-
/dd\s+if=/i,
|
|
4037
|
-
/format/i,
|
|
4038
|
-
/shutdown/i,
|
|
4039
|
-
/reboot/i,
|
|
4040
|
-
/kill\s+-9/i,
|
|
4041
|
-
/pkill/i,
|
|
4042
|
-
/iptables/i,
|
|
4043
|
-
/ufw/i,
|
|
4044
|
-
/firewall/i,
|
|
4045
|
-
/passwd/i,
|
|
4046
|
-
/useradd/i,
|
|
4047
|
-
/userdel/i,
|
|
4048
|
-
/chmod\s+777/i,
|
|
4049
|
-
/chown/i,
|
|
4050
|
-
/sudo/i,
|
|
4051
|
-
/su\s+-/i,
|
|
4052
|
-
/nc\s+-e/i,
|
|
4053
|
-
/bash\s+-i/i,
|
|
4054
|
-
/reverse.*shell/i,
|
|
4055
|
-
/bind.*shell/i,
|
|
4056
|
-
/meterpreter/i,
|
|
4057
|
-
/mimikatz/i
|
|
4058
|
-
];
|
|
4059
|
-
function assessRisk(toolName, toolInput) {
|
|
4060
|
-
const inputStr = JSON.stringify(toolInput).toLowerCase();
|
|
4061
|
-
for (const pattern of HIGH_RISK_PATTERNS) {
|
|
4062
|
-
if (pattern.test(inputStr)) {
|
|
4063
|
-
return "critical";
|
|
4064
|
-
}
|
|
4065
|
-
}
|
|
4066
|
-
if (CRITICAL_TOOLS.includes(toolName)) {
|
|
4067
|
-
return "high";
|
|
4068
|
-
}
|
|
4069
|
-
if (toolName.includes("script") || toolName.includes("exec")) {
|
|
4070
|
-
return "medium";
|
|
4071
|
-
}
|
|
4072
|
-
if (toolName.includes("scan") || toolName.includes("request")) {
|
|
4073
|
-
return "medium";
|
|
4074
|
-
}
|
|
4075
|
-
return "low";
|
|
4076
|
-
}
|
|
4077
|
-
function generateRequestId() {
|
|
4078
|
-
return `approval_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
|
4079
|
-
}
|
|
4080
|
-
var ApprovalManager = class extends EventEmitter5 {
|
|
4081
|
-
pendingRequests = /* @__PURE__ */ new Map();
|
|
4082
|
-
autoApprovedTools = /* @__PURE__ */ new Set();
|
|
4083
|
-
autoDeniedTools = /* @__PURE__ */ new Set();
|
|
4084
|
-
yoloMode = false;
|
|
4085
|
-
defaultTimeout = 6e4;
|
|
4086
|
-
// 1 minute
|
|
4087
|
-
constructor(options) {
|
|
4088
|
-
super();
|
|
4089
|
-
this.yoloMode = options?.yoloMode ?? false;
|
|
4090
|
-
this.defaultTimeout = options?.timeout ?? 6e4;
|
|
4091
|
-
}
|
|
4092
|
-
/**
|
|
4093
|
-
* Enable/disable YOLO mode (auto-approve everything)
|
|
4094
|
-
*/
|
|
4095
|
-
setYoloMode(enabled) {
|
|
4096
|
-
this.yoloMode = enabled;
|
|
4097
|
-
this.emit("yolo_mode_changed", enabled);
|
|
4098
|
-
}
|
|
4099
|
-
/**
|
|
4100
|
-
* Check if approval is required for a tool call
|
|
4101
|
-
*/
|
|
4102
|
-
requiresApproval(toolName, toolInput) {
|
|
4103
|
-
if (this.yoloMode) return false;
|
|
4104
|
-
if (this.autoApprovedTools.has(toolName)) return false;
|
|
4105
|
-
if (this.autoDeniedTools.has(toolName)) return true;
|
|
4106
|
-
const risk = assessRisk(toolName, toolInput);
|
|
4107
|
-
if (risk === "low") return false;
|
|
4108
|
-
return true;
|
|
4109
|
-
}
|
|
4110
|
-
/**
|
|
4111
|
-
* Request approval for a tool call
|
|
4112
|
-
*/
|
|
4113
|
-
async requestApproval(toolName, toolInput, reason) {
|
|
4114
|
-
if (this.autoDeniedTools.has(toolName)) {
|
|
4115
|
-
return "deny";
|
|
4116
|
-
}
|
|
4117
|
-
if (this.autoApprovedTools.has(toolName)) {
|
|
4118
|
-
return "approve";
|
|
4119
|
-
}
|
|
4120
|
-
const risk = assessRisk(toolName, toolInput);
|
|
4121
|
-
const request = {
|
|
4122
|
-
id: generateRequestId(),
|
|
4123
|
-
toolName,
|
|
4124
|
-
toolInput,
|
|
4125
|
-
reason: reason || `Tool "${toolName}" requires approval (${risk} risk)`,
|
|
4126
|
-
riskLevel: risk,
|
|
4127
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4128
|
-
};
|
|
4129
|
-
this.pendingRequests.set(request.id, request);
|
|
4130
|
-
this.emit(APPROVAL_EVENT.REQUEST, request);
|
|
4131
|
-
return new Promise((resolve) => {
|
|
4132
|
-
const timeout = setTimeout(() => {
|
|
4133
|
-
this.pendingRequests.delete(request.id);
|
|
4134
|
-
this.emit(APPROVAL_EVENT.TIMEOUT, request.id);
|
|
4135
|
-
resolve("deny");
|
|
4136
|
-
}, this.defaultTimeout);
|
|
4137
|
-
const responseHandler = (response) => {
|
|
4138
|
-
if (response.requestId === request.id) {
|
|
4139
|
-
clearTimeout(timeout);
|
|
4140
|
-
this.pendingRequests.delete(request.id);
|
|
4141
|
-
this.removeListener(APPROVAL_EVENT.RESPONSE, responseHandler);
|
|
4142
|
-
if (response.decision === "approve_always") {
|
|
4143
|
-
this.autoApprovedTools.add(toolName);
|
|
4144
|
-
resolve("approve");
|
|
4145
|
-
} else if (response.decision === "deny_always") {
|
|
4146
|
-
this.autoDeniedTools.add(toolName);
|
|
4147
|
-
resolve("deny");
|
|
4148
|
-
} else {
|
|
4149
|
-
resolve(response.decision);
|
|
4150
|
-
}
|
|
4151
|
-
}
|
|
4152
|
-
};
|
|
4153
|
-
this.on(APPROVAL_EVENT.RESPONSE, responseHandler);
|
|
4154
|
-
});
|
|
4155
|
-
}
|
|
4156
|
-
/**
|
|
4157
|
-
* Respond to an approval request (called by UI)
|
|
4158
|
-
*/
|
|
4159
|
-
respond(requestId, decision) {
|
|
4160
|
-
const response = {
|
|
4161
|
-
requestId,
|
|
4162
|
-
decision,
|
|
4163
|
-
respondedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4164
|
-
};
|
|
4165
|
-
this.emit(APPROVAL_EVENT.RESPONSE, response);
|
|
4166
|
-
}
|
|
4167
|
-
/**
|
|
4168
|
-
* Get pending requests
|
|
4169
|
-
*/
|
|
4170
|
-
getPendingRequests() {
|
|
4171
|
-
return Array.from(this.pendingRequests.values());
|
|
4172
|
-
}
|
|
4173
|
-
/**
|
|
4174
|
-
* Get auto-approved tools
|
|
4175
|
-
*/
|
|
4176
|
-
getAutoApprovedTools() {
|
|
4177
|
-
return Array.from(this.autoApprovedTools);
|
|
4178
|
-
}
|
|
4179
|
-
/**
|
|
4180
|
-
* Reset all auto decisions
|
|
4181
|
-
*/
|
|
4182
|
-
resetAutoDecisions() {
|
|
4183
|
-
this.autoApprovedTools.clear();
|
|
4184
|
-
this.autoDeniedTools.clear();
|
|
4185
|
-
}
|
|
4186
|
-
};
|
|
4187
|
-
var approvalManager = null;
|
|
4188
|
-
function getApprovalManager(options) {
|
|
4189
|
-
if (!approvalManager) {
|
|
4190
|
-
approvalManager = new ApprovalManager(options);
|
|
4191
|
-
}
|
|
4192
|
-
return approvalManager;
|
|
4193
|
-
}
|
|
4194
|
-
|
|
4195
4234
|
// src/config/theme.ts
|
|
4196
4235
|
var THEME = {
|
|
4197
4236
|
// Primary backgrounds (dark purple tones)
|
|
@@ -4287,6 +4326,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4287
4326
|
const [currentStatus, setCurrentStatus] = useState("");
|
|
4288
4327
|
const [elapsedTime, setElapsedTime] = useState(0);
|
|
4289
4328
|
const [pendingApproval, setPendingApproval] = useState(null);
|
|
4329
|
+
const [tokenUsage, setTokenUsage] = useState({ input: 0, output: 0, total: 0 });
|
|
4290
4330
|
const [agent] = useState(() => new AutonomousHackingAgent(void 0, { autoApprove }));
|
|
4291
4331
|
const sessionManager2 = getSessionManager();
|
|
4292
4332
|
const approvalManager2 = getApprovalManager({ yoloMode: autoApprove });
|
|
@@ -4350,6 +4390,18 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4350
4390
|
agent.on(AGENT_EVENT.CONTEXT_COMPACTED, () => {
|
|
4351
4391
|
addMessage(MESSAGE_TYPE.SYSTEM, "\u{1F4BE} Context compacted to save tokens");
|
|
4352
4392
|
});
|
|
4393
|
+
agent.on(AGENT_EVENT.TOKEN_USAGE, (usage) => {
|
|
4394
|
+
setTokenUsage(usage);
|
|
4395
|
+
});
|
|
4396
|
+
agent.on(AGENT_EVENT.APPROVAL_NEEDED, (data) => {
|
|
4397
|
+
setPendingApproval({
|
|
4398
|
+
id: data.id,
|
|
4399
|
+
toolName: data.toolName,
|
|
4400
|
+
riskLevel: data.riskLevel
|
|
4401
|
+
});
|
|
4402
|
+
addMessage(MESSAGE_TYPE.SYSTEM, `\u26A0\uFE0F APPROVAL NEEDED: ${data.toolName} (${data.riskLevel} risk)`);
|
|
4403
|
+
addMessage(MESSAGE_TYPE.SYSTEM, " Type /approve or /deny");
|
|
4404
|
+
});
|
|
4353
4405
|
agent.on(AGENT_EVENT.COMPLETE, () => {
|
|
4354
4406
|
const duration = stopTimer();
|
|
4355
4407
|
addMessage(MESSAGE_TYPE.SYSTEM, `\u2713 Complete (${duration}s)`);
|
|
@@ -4622,6 +4674,7 @@ var App = ({ autoApprove = false, target }) => {
|
|
|
4622
4674
|
" findings \u2502",
|
|
4623
4675
|
state.credentials.length,
|
|
4624
4676
|
" creds \u2502",
|
|
4677
|
+
tokenUsage.total > 0 && `${(tokenUsage.total / 1e3).toFixed(1)}k tokens \u2502`,
|
|
4625
4678
|
state.currentPhase !== AGENT_STATUS.IDLE && ` ${state.currentPhase} \u2502`
|
|
4626
4679
|
] }),
|
|
4627
4680
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|