htpx-cli 0.1.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 +274 -0
- package/dist/cli/commands/clear.d.ts +3 -0
- package/dist/cli/commands/clear.d.ts.map +1 -0
- package/dist/cli/commands/clear.js +30 -0
- package/dist/cli/commands/clear.js.map +1 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +25 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/intercept.d.ts +8 -0
- package/dist/cli/commands/intercept.d.ts.map +1 -0
- package/dist/cli/commands/intercept.js +59 -0
- package/dist/cli/commands/intercept.js.map +1 -0
- package/dist/cli/commands/project.d.ts +3 -0
- package/dist/cli/commands/project.d.ts.map +1 -0
- package/dist/cli/commands/project.js +13 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/commands/status.d.ts +3 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +36 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +3 -0
- package/dist/cli/commands/stop.d.ts.map +1 -0
- package/dist/cli/commands/stop.js +27 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/commands/tui.d.ts +3 -0
- package/dist/cli/commands/tui.d.ts.map +1 -0
- package/dist/cli/commands/tui.js +27 -0
- package/dist/cli/commands/tui.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +20 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/tui/App.d.ts +10 -0
- package/dist/cli/tui/App.d.ts.map +1 -0
- package/dist/cli/tui/App.js +96 -0
- package/dist/cli/tui/App.js.map +1 -0
- package/dist/cli/tui/components/BodyView.d.ts +14 -0
- package/dist/cli/tui/components/BodyView.d.ts.map +1 -0
- package/dist/cli/tui/components/BodyView.js +39 -0
- package/dist/cli/tui/components/BodyView.js.map +1 -0
- package/dist/cli/tui/components/HeadersView.d.ts +13 -0
- package/dist/cli/tui/components/HeadersView.d.ts.map +1 -0
- package/dist/cli/tui/components/HeadersView.js +8 -0
- package/dist/cli/tui/components/HeadersView.js.map +1 -0
- package/dist/cli/tui/components/RequestDetails.d.ts +13 -0
- package/dist/cli/tui/components/RequestDetails.d.ts.map +1 -0
- package/dist/cli/tui/components/RequestDetails.js +19 -0
- package/dist/cli/tui/components/RequestDetails.js.map +1 -0
- package/dist/cli/tui/components/RequestList.d.ts +15 -0
- package/dist/cli/tui/components/RequestList.d.ts.map +1 -0
- package/dist/cli/tui/components/RequestList.js +17 -0
- package/dist/cli/tui/components/RequestList.js.map +1 -0
- package/dist/cli/tui/components/RequestListItem.d.ts +13 -0
- package/dist/cli/tui/components/RequestListItem.d.ts.map +1 -0
- package/dist/cli/tui/components/RequestListItem.js +53 -0
- package/dist/cli/tui/components/RequestListItem.js.map +1 -0
- package/dist/cli/tui/components/StatusBar.d.ts +10 -0
- package/dist/cli/tui/components/StatusBar.d.ts.map +1 -0
- package/dist/cli/tui/components/StatusBar.js +18 -0
- package/dist/cli/tui/components/StatusBar.js.map +1 -0
- package/dist/cli/tui/hooks/useExport.d.ts +18 -0
- package/dist/cli/tui/hooks/useExport.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useExport.js +58 -0
- package/dist/cli/tui/hooks/useExport.js.map +1 -0
- package/dist/cli/tui/hooks/useRequests.d.ts +20 -0
- package/dist/cli/tui/hooks/useRequests.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useRequests.js +85 -0
- package/dist/cli/tui/hooks/useRequests.js.map +1 -0
- package/dist/cli/tui/hooks/useStdoutDimensions.d.ts +11 -0
- package/dist/cli/tui/hooks/useStdoutDimensions.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useStdoutDimensions.js +29 -0
- package/dist/cli/tui/hooks/useStdoutDimensions.js.map +1 -0
- package/dist/cli/tui/utils/curl.d.ts +9 -0
- package/dist/cli/tui/utils/curl.d.ts.map +1 -0
- package/dist/cli/tui/utils/curl.js +47 -0
- package/dist/cli/tui/utils/curl.js.map +1 -0
- package/dist/cli/tui/utils/formatters.d.ts +36 -0
- package/dist/cli/tui/utils/formatters.d.ts.map +1 -0
- package/dist/cli/tui/utils/formatters.js +108 -0
- package/dist/cli/tui/utils/formatters.js.map +1 -0
- package/dist/cli/tui/utils/har.d.ts +75 -0
- package/dist/cli/tui/utils/har.d.ts.map +1 -0
- package/dist/cli/tui/utils/har.js +139 -0
- package/dist/cli/tui/utils/har.js.map +1 -0
- package/dist/daemon/control.d.ts +63 -0
- package/dist/daemon/control.d.ts.map +1 -0
- package/dist/daemon/control.js +260 -0
- package/dist/daemon/control.js.map +1 -0
- package/dist/daemon/index.d.ts +3 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +107 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/proxy.d.ts +19 -0
- package/dist/daemon/proxy.d.ts.map +1 -0
- package/dist/daemon/proxy.js +89 -0
- package/dist/daemon/proxy.js.map +1 -0
- package/dist/daemon/storage.d.ts +60 -0
- package/dist/daemon/storage.d.ts.map +1 -0
- package/dist/daemon/storage.js +215 -0
- package/dist/daemon/storage.js.map +1 -0
- package/dist/shared/daemon.d.ts +14 -0
- package/dist/shared/daemon.d.ts.map +1 -0
- package/dist/shared/daemon.js +161 -0
- package/dist/shared/daemon.js.map +1 -0
- package/dist/shared/project.d.ts +61 -0
- package/dist/shared/project.d.ts.map +1 -0
- package/dist/shared/project.js +143 -0
- package/dist/shared/project.js.map +1 -0
- package/dist/shared/types.d.ts +32 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +5 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +89 -0
package/README.md
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# htpx
|
|
2
|
+
|
|
3
|
+
A terminal-based HTTP interception toolkit with project-scoped isolation and a lazygit-style TUI.
|
|
4
|
+
|
|
5
|
+
Capture HTTP/HTTPS traffic through a MITM proxy and inspect it in an interactive terminal interface. No browser extensions, no separate apps—just your terminal.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Project-scoped isolation** — Each project gets its own `.htpx/` directory, keeping traffic separate
|
|
10
|
+
- **Interactive TUI** — Browse, inspect, and export requests with vim-style keybindings
|
|
11
|
+
- **Full HTTPS support** — Automatic CA certificate generation and trust
|
|
12
|
+
- **Session labelling** — Tag and filter traffic by session for organised debugging
|
|
13
|
+
- **Export anywhere** — Generate curl commands or HAR files from captured requests
|
|
14
|
+
- **Zero config** — Works out of the box with curl, wget, Node.js, Python, and more
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install globally
|
|
20
|
+
npm install -g htpx-cli
|
|
21
|
+
|
|
22
|
+
# One-time shell setup (add to ~/.zshrc or ~/.bashrc)
|
|
23
|
+
eval "$(htpx init)"
|
|
24
|
+
|
|
25
|
+
# Start intercepting in your project directory
|
|
26
|
+
htpx intercept
|
|
27
|
+
|
|
28
|
+
# Make some requests...
|
|
29
|
+
curl https://api.example.com/users
|
|
30
|
+
|
|
31
|
+
# Open the TUI to inspect
|
|
32
|
+
htpx tui
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install -g htpx-cli
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Requirements:** Node.js 20 or later
|
|
42
|
+
|
|
43
|
+
### Shell Setup
|
|
44
|
+
|
|
45
|
+
Add the following to your `~/.zshrc` or `~/.bashrc`:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
eval "$(htpx init)"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This creates a shell function that properly sets up proxy environment variables in your current session.
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### Start Intercepting
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Basic interception
|
|
59
|
+
htpx intercept
|
|
60
|
+
|
|
61
|
+
# With a session label for filtering
|
|
62
|
+
htpx intercept --label api-tests
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This auto-starts the daemon, sets up the proxy, and configures your shell to route HTTP traffic through htpx.
|
|
66
|
+
|
|
67
|
+
### Browse Captured Traffic
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# View all requests
|
|
71
|
+
htpx tui
|
|
72
|
+
|
|
73
|
+
# Filter by session label
|
|
74
|
+
htpx tui --label api-tests
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### TUI Keybindings
|
|
78
|
+
|
|
79
|
+
| Key | Action |
|
|
80
|
+
|-----|--------|
|
|
81
|
+
| `j` / `↓` | Navigate down |
|
|
82
|
+
| `k` / `↑` | Navigate up |
|
|
83
|
+
| `Tab` | Switch between list and details panes |
|
|
84
|
+
| `c` | Export selected request as curl command |
|
|
85
|
+
| `h` | Export all requests as HAR file |
|
|
86
|
+
| `r` | Refresh request list |
|
|
87
|
+
| `q` | Quit |
|
|
88
|
+
|
|
89
|
+
### Other Commands
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
htpx status # Check daemon status
|
|
93
|
+
htpx stop # Stop the daemon
|
|
94
|
+
htpx clear # Clear captured requests
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## How It Works
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
101
|
+
│ Your Shell │
|
|
102
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
103
|
+
│ │ curl, wget, node, python... │ │
|
|
104
|
+
│ │ │ │ │
|
|
105
|
+
│ │ ▼ │ │
|
|
106
|
+
│ │ HTTP_PROXY=localhost:54321 │ │
|
|
107
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
108
|
+
│ │ │
|
|
109
|
+
└──────────────────────────┼──────────────────────────────────┘
|
|
110
|
+
▼
|
|
111
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
112
|
+
│ htpx daemon │
|
|
113
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
114
|
+
│ │ MITM Proxy │───▶│ SQLite │◀───│ Control API │ │
|
|
115
|
+
│ │ (mockttp) │ │ requests │ │ (unix sock) │ │
|
|
116
|
+
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|
117
|
+
└─────────────────────────────────────────────────────────────┘
|
|
118
|
+
▲
|
|
119
|
+
│
|
|
120
|
+
┌──────────────────────────┼──────────────────────────────────┐
|
|
121
|
+
│ htpx tui │ │
|
|
122
|
+
│ ┌───────────────────────┴─────────────────────────────┐ │
|
|
123
|
+
│ │ ● POST /api/users │ POST https://api.example.com │ │
|
|
124
|
+
│ │ GET /health │ Status: 200 │ Duration: 45ms │ │
|
|
125
|
+
│ │ POST /login │ │ │
|
|
126
|
+
│ │ │ Request Headers: │ │
|
|
127
|
+
│ │ │ Content-Type: application/ │ │
|
|
128
|
+
│ └─────────────────────┴───────────────────────────────┘ │
|
|
129
|
+
└─────────────────────────────────────────────────────────────┘
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
When you run `htpx intercept`:
|
|
133
|
+
|
|
134
|
+
1. A daemon starts in the background with a MITM proxy
|
|
135
|
+
2. Environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, etc.) are set in your shell
|
|
136
|
+
3. HTTP clients that respect these variables route traffic through the proxy
|
|
137
|
+
4. Requests are captured and stored in a local SQLite database
|
|
138
|
+
5. The TUI connects via Unix socket to display captured traffic
|
|
139
|
+
|
|
140
|
+
### Project Isolation
|
|
141
|
+
|
|
142
|
+
htpx creates a `.htpx/` directory in your project root (detected by `.git` or existing `.htpx`):
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
your-project/
|
|
146
|
+
├── .htpx/
|
|
147
|
+
│ ├── proxy.port # Proxy TCP port
|
|
148
|
+
│ ├── control.sock # IPC socket
|
|
149
|
+
│ ├── requests.db # Captured traffic
|
|
150
|
+
│ ├── ca.pem # CA certificate
|
|
151
|
+
│ └── daemon.pid # Process ID
|
|
152
|
+
└── src/...
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Different projects have completely separate daemons, databases, and certificates.
|
|
156
|
+
|
|
157
|
+
## Supported HTTP Clients
|
|
158
|
+
|
|
159
|
+
htpx works with any client that respects the `HTTP_PROXY` environment variable:
|
|
160
|
+
|
|
161
|
+
| Client | Support |
|
|
162
|
+
|--------|---------|
|
|
163
|
+
| curl | ✅ Automatic |
|
|
164
|
+
| wget | ✅ Automatic |
|
|
165
|
+
| Node.js (fetch, axios, etc.) | ✅ With `NODE_EXTRA_CA_CERTS` |
|
|
166
|
+
| Python (requests, httpx) | ✅ With `REQUESTS_CA_BUNDLE` |
|
|
167
|
+
| Go | ✅ Automatic |
|
|
168
|
+
| Rust (reqwest) | ✅ Automatic |
|
|
169
|
+
|
|
170
|
+
## Export Formats
|
|
171
|
+
|
|
172
|
+
### curl
|
|
173
|
+
|
|
174
|
+
Press `c` in the TUI to copy a request as a curl command:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
curl -X POST 'https://api.example.com/users' \
|
|
178
|
+
-H 'Content-Type: application/json' \
|
|
179
|
+
-H 'Authorization: Bearer token123' \
|
|
180
|
+
-d '{"name": "test"}'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### HAR
|
|
184
|
+
|
|
185
|
+
Press `h` to export all captured requests as a HAR file, compatible with browser dev tools and HTTP analysis tools.
|
|
186
|
+
|
|
187
|
+
## CLI Reference
|
|
188
|
+
|
|
189
|
+
### `htpx init`
|
|
190
|
+
|
|
191
|
+
Output shell configuration for your `.zshrc`/`.bashrc`.
|
|
192
|
+
|
|
193
|
+
### `htpx intercept [options]`
|
|
194
|
+
|
|
195
|
+
Start intercepting HTTP traffic.
|
|
196
|
+
|
|
197
|
+
| Option | Description |
|
|
198
|
+
|--------|-------------|
|
|
199
|
+
| `-l, --label <label>` | Label this session for filtering |
|
|
200
|
+
|
|
201
|
+
### `htpx tui [options]`
|
|
202
|
+
|
|
203
|
+
Open the interactive TUI.
|
|
204
|
+
|
|
205
|
+
| Option | Description |
|
|
206
|
+
|--------|-------------|
|
|
207
|
+
| `-l, --label <label>` | Filter to requests from labelled sessions |
|
|
208
|
+
|
|
209
|
+
### `htpx status`
|
|
210
|
+
|
|
211
|
+
Show daemon status, including proxy port, active sessions, and request count.
|
|
212
|
+
|
|
213
|
+
### `htpx stop`
|
|
214
|
+
|
|
215
|
+
Stop the daemon gracefully.
|
|
216
|
+
|
|
217
|
+
### `htpx clear`
|
|
218
|
+
|
|
219
|
+
Clear all captured requests from the database.
|
|
220
|
+
|
|
221
|
+
### `htpx project init`
|
|
222
|
+
|
|
223
|
+
Manually initialise a `.htpx` directory in the current location.
|
|
224
|
+
|
|
225
|
+
## Development
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# Clone and install
|
|
229
|
+
git clone https://github.com/mtford90/htpx.git
|
|
230
|
+
cd htpx
|
|
231
|
+
npm install
|
|
232
|
+
|
|
233
|
+
# Build
|
|
234
|
+
npm run build
|
|
235
|
+
|
|
236
|
+
# Run tests
|
|
237
|
+
npm test
|
|
238
|
+
|
|
239
|
+
# Type check and lint
|
|
240
|
+
npm run typecheck
|
|
241
|
+
npm run lint
|
|
242
|
+
|
|
243
|
+
# Development mode (watch)
|
|
244
|
+
npm run dev
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Troubleshooting
|
|
248
|
+
|
|
249
|
+
### Certificate errors
|
|
250
|
+
|
|
251
|
+
Some tools need explicit CA certificate configuration. htpx sets common environment variables automatically, but you may need to configure your specific tool:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# The CA certificate is at:
|
|
255
|
+
cat .htpx/ca.pem
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Daemon won't start
|
|
259
|
+
|
|
260
|
+
Check if another process is using the socket:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
htpx status
|
|
264
|
+
htpx stop
|
|
265
|
+
htpx intercept
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Requests not appearing
|
|
269
|
+
|
|
270
|
+
Ensure your HTTP client respects proxy environment variables. Some clients (like browsers) ignore `HTTP_PROXY` by default.
|
|
271
|
+
|
|
272
|
+
## Licence
|
|
273
|
+
|
|
274
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/clear.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,YAAY,SA0BrB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { findProjectRoot, getHtpxPaths } from "../../shared/project.js";
|
|
3
|
+
import { isDaemonRunning } from "../../shared/daemon.js";
|
|
4
|
+
import { ControlClient } from "../../daemon/control.js";
|
|
5
|
+
export const clearCommand = new Command("clear")
|
|
6
|
+
.description("Clear all captured requests")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
const projectRoot = findProjectRoot();
|
|
9
|
+
if (!projectRoot) {
|
|
10
|
+
console.log("Not in a project directory (no .htpx or .git found)");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const paths = getHtpxPaths(projectRoot);
|
|
14
|
+
const running = await isDaemonRunning(projectRoot);
|
|
15
|
+
if (!running) {
|
|
16
|
+
console.log("Daemon is not running");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const client = new ControlClient(paths.controlSocketFile);
|
|
21
|
+
await client.clearRequests();
|
|
22
|
+
console.log("Requests cleared");
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
26
|
+
console.error(`Error clearing requests: ${message}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=clear.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear.js","sourceRoot":"","sources":["../../../src/cli/commands/clear.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAExC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC1D,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,4BAA4B,OAAO,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
/**
|
|
3
|
+
* Generate the shell function for htpx.
|
|
4
|
+
* This function wraps htpx intercept with eval so that environment
|
|
5
|
+
* variables can be set in the current shell.
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateShellFunction(): string;
|
|
8
|
+
export declare const initCommand: Command;
|
|
9
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAY9C;AAED,eAAO,MAAM,WAAW,SAIpB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
/**
|
|
3
|
+
* Generate the shell function for htpx.
|
|
4
|
+
* This function wraps htpx intercept with eval so that environment
|
|
5
|
+
* variables can be set in the current shell.
|
|
6
|
+
*/
|
|
7
|
+
export function generateShellFunction() {
|
|
8
|
+
const lines = [
|
|
9
|
+
"htpx() {",
|
|
10
|
+
' if [[ "$1" == "intercept" ]]; then',
|
|
11
|
+
" shift",
|
|
12
|
+
' eval "$(command htpx intercept "$@")"',
|
|
13
|
+
" else",
|
|
14
|
+
' command htpx "$@"',
|
|
15
|
+
" fi",
|
|
16
|
+
"}",
|
|
17
|
+
];
|
|
18
|
+
return lines.join("\n");
|
|
19
|
+
}
|
|
20
|
+
export const initCommand = new Command("init")
|
|
21
|
+
.description("Output shell function for .zshrc/.bashrc (one-time setup)")
|
|
22
|
+
.action(() => {
|
|
23
|
+
console.log(generateShellFunction());
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,sCAAsC;QACtC,WAAW;QACX,2CAA2C;QAC3C,QAAQ;QACR,uBAAuB;QACvB,MAAM;QACN,GAAG;KACJ,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,2DAA2D,CAAC;KACxE,MAAM,CAAC,GAAG,EAAE;IACX,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
/**
|
|
3
|
+
* Format environment variable exports for shell evaluation.
|
|
4
|
+
* Each line is a shell export statement.
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatEnvVars(vars: Record<string, string>): string;
|
|
7
|
+
export declare const interceptCommand: Command;
|
|
8
|
+
//# sourceMappingURL=intercept.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intercept.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/intercept.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAIlE;AAED,eAAO,MAAM,gBAAgB,SAmDzB,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { findOrCreateProjectRoot, ensureHtpxDir, getHtpxPaths } from "../../shared/project.js";
|
|
3
|
+
import { startDaemon } from "../../shared/daemon.js";
|
|
4
|
+
import { ControlClient } from "../../daemon/control.js";
|
|
5
|
+
/**
|
|
6
|
+
* Format environment variable exports for shell evaluation.
|
|
7
|
+
* Each line is a shell export statement.
|
|
8
|
+
*/
|
|
9
|
+
export function formatEnvVars(vars) {
|
|
10
|
+
return Object.entries(vars)
|
|
11
|
+
.map(([key, value]) => `export ${key}="${value}"`)
|
|
12
|
+
.join("\n");
|
|
13
|
+
}
|
|
14
|
+
export const interceptCommand = new Command("intercept")
|
|
15
|
+
.description("Output environment variables to intercept HTTP traffic")
|
|
16
|
+
.option("-l, --label <label>", "Label for this session")
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
const label = options.label;
|
|
19
|
+
// Find project root (auto-creates .htpx if needed)
|
|
20
|
+
const projectRoot = findOrCreateProjectRoot();
|
|
21
|
+
ensureHtpxDir(projectRoot);
|
|
22
|
+
const paths = getHtpxPaths(projectRoot);
|
|
23
|
+
try {
|
|
24
|
+
// Start daemon if not already running
|
|
25
|
+
const proxyPort = await startDaemon(projectRoot);
|
|
26
|
+
const proxyUrl = `http://127.0.0.1:${proxyPort}`;
|
|
27
|
+
// Register session with daemon
|
|
28
|
+
const client = new ControlClient(paths.controlSocketFile);
|
|
29
|
+
const session = await client.registerSession(label, process.ppid);
|
|
30
|
+
// Build environment variables
|
|
31
|
+
const envVars = {
|
|
32
|
+
HTTP_PROXY: proxyUrl,
|
|
33
|
+
HTTPS_PROXY: proxyUrl,
|
|
34
|
+
// Python requests library
|
|
35
|
+
SSL_CERT_FILE: paths.caCertFile,
|
|
36
|
+
REQUESTS_CA_BUNDLE: paths.caCertFile,
|
|
37
|
+
// Node.js
|
|
38
|
+
NODE_EXTRA_CA_CERTS: paths.caCertFile,
|
|
39
|
+
// htpx session tracking
|
|
40
|
+
HTPX_SESSION_ID: session.id,
|
|
41
|
+
};
|
|
42
|
+
if (label) {
|
|
43
|
+
envVars["HTPX_LABEL"] = label;
|
|
44
|
+
}
|
|
45
|
+
// Output env vars for eval
|
|
46
|
+
console.log(formatEnvVars(envVars));
|
|
47
|
+
// Output confirmation as a comment (shown but not executed)
|
|
48
|
+
const labelInfo = label ? ` (label: ${label})` : "";
|
|
49
|
+
console.log(`# htpx: intercepting traffic${labelInfo}`);
|
|
50
|
+
console.log(`# Proxy: ${proxyUrl}`);
|
|
51
|
+
console.log(`# Session: ${session.id}`);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
55
|
+
console.error(`# htpx error: ${message}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=intercept.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intercept.js","sourceRoot":"","sources":["../../../src/cli/commands/intercept.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAA4B;IACxD,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SACxB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,UAAU,GAAG,KAAK,KAAK,GAAG,CAAC;SACjD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC;KACrD,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC;KACvD,MAAM,CAAC,KAAK,EAAE,OAA2B,EAAE,EAAE;IAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAE5B,mDAAmD;IACnD,MAAM,WAAW,GAAG,uBAAuB,EAAE,CAAC;IAC9C,aAAa,CAAC,WAAW,CAAC,CAAC;IAE3B,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAExC,IAAI,CAAC;QACH,sCAAsC;QACtC,MAAM,SAAS,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,oBAAoB,SAAS,EAAE,CAAC;QAEjD,+BAA+B;QAC/B,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAElE,8BAA8B;QAC9B,MAAM,OAAO,GAA2B;YACtC,UAAU,EAAE,QAAQ;YACpB,WAAW,EAAE,QAAQ;YACrB,0BAA0B;YAC1B,aAAa,EAAE,KAAK,CAAC,UAAU;YAC/B,kBAAkB,EAAE,KAAK,CAAC,UAAU;YACpC,UAAU;YACV,mBAAmB,EAAE,KAAK,CAAC,UAAU;YACrC,wBAAwB;YACxB,eAAe,EAAE,OAAO,CAAC,EAAE;SAC5B,CAAC;QAEF,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC;QAChC,CAAC;QAED,2BAA2B;QAC3B,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;QAEpC,4DAA4D;QAC5D,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,YAAY,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,+BAA+B,SAAS,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,YAAY,QAAQ,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,iBAAiB,OAAO,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,cAAc,SAA0E,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { ensureHtpxDir, getHtpxDir } from "../../shared/project.js";
|
|
3
|
+
export const projectCommand = new Command("project").description("Manage htpx project configuration");
|
|
4
|
+
projectCommand
|
|
5
|
+
.command("init")
|
|
6
|
+
.description("Initialise htpx in the current directory")
|
|
7
|
+
.action(() => {
|
|
8
|
+
const projectRoot = process.cwd();
|
|
9
|
+
const htpxDir = getHtpxDir(projectRoot);
|
|
10
|
+
ensureHtpxDir(projectRoot);
|
|
11
|
+
console.log(`Created ${htpxDir}`);
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../../src/cli/commands/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEpE,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,mCAAmC,CAAC,CAAC;AAEtG,cAAc;KACX,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAExC,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,aAAa,SAiCtB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { findProjectRoot, getHtpxPaths } from "../../shared/project.js";
|
|
3
|
+
import { isDaemonRunning } from "../../shared/daemon.js";
|
|
4
|
+
import { ControlClient } from "../../daemon/control.js";
|
|
5
|
+
export const statusCommand = new Command("status")
|
|
6
|
+
.description("Show daemon status")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
// Find project root
|
|
9
|
+
const projectRoot = findProjectRoot();
|
|
10
|
+
if (!projectRoot) {
|
|
11
|
+
console.log("Not in a project directory (no .htpx or .git found)");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
const paths = getHtpxPaths(projectRoot);
|
|
15
|
+
// Check if daemon is running
|
|
16
|
+
const running = await isDaemonRunning(projectRoot);
|
|
17
|
+
if (!running) {
|
|
18
|
+
console.log("Daemon is not running");
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
// Query daemon for status
|
|
23
|
+
const client = new ControlClient(paths.controlSocketFile);
|
|
24
|
+
const status = await client.status();
|
|
25
|
+
console.log("Daemon is running");
|
|
26
|
+
console.log(` Proxy port: ${status.proxyPort}`);
|
|
27
|
+
console.log(` Sessions: ${status.sessionCount}`);
|
|
28
|
+
console.log(` Requests captured: ${status.requestCount}`);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
32
|
+
console.error(`Error querying daemon: ${message}`);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,oBAAoB,CAAC;KACjC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,oBAAoB;IACpB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAExC,6BAA6B;IAC7B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,0BAA0B;QAC1B,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QAErC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,wBAAwB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,WAAW,SAuBtB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { findProjectRoot } from "../../shared/project.js";
|
|
3
|
+
import { isDaemonRunning, stopDaemon } from "../../shared/daemon.js";
|
|
4
|
+
export const stopCommand = new Command("stop").description("Stop the daemon").action(async () => {
|
|
5
|
+
// Find project root
|
|
6
|
+
const projectRoot = findProjectRoot();
|
|
7
|
+
if (!projectRoot) {
|
|
8
|
+
console.log("Not in a project directory (no .htpx or .git found)");
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
// Check if daemon is running
|
|
12
|
+
const running = await isDaemonRunning(projectRoot);
|
|
13
|
+
if (!running) {
|
|
14
|
+
console.log("Daemon is not running");
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
await stopDaemon(projectRoot);
|
|
19
|
+
console.log("Daemon stopped");
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
23
|
+
console.error(`Error stopping daemon: ${message}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=stop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../../../src/cli/commands/stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAErE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;IAC9F,oBAAoB;IACpB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,6BAA6B;IAC7B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/tui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,UAAU,SAyBnB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { render } from "ink";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { App } from "../tui/App.js";
|
|
5
|
+
export const tuiCommand = new Command("tui")
|
|
6
|
+
.description("Browse captured HTTP traffic")
|
|
7
|
+
.option("-l, --label <label>", "Filter by session label")
|
|
8
|
+
.option("--ci", "CI mode: render once and exit after a short delay (for testing)")
|
|
9
|
+
.action((options) => {
|
|
10
|
+
const { waitUntilExit, unmount } = render(React.createElement(App, { label: options.label }));
|
|
11
|
+
// In CI mode, exit after a short delay to allow initial render
|
|
12
|
+
if (options.ci) {
|
|
13
|
+
setTimeout(() => {
|
|
14
|
+
unmount();
|
|
15
|
+
}, 500);
|
|
16
|
+
}
|
|
17
|
+
void waitUntilExit().then(() => {
|
|
18
|
+
// Print curl command if one was exported
|
|
19
|
+
const curl = globalThis["__htpxCurl"];
|
|
20
|
+
if (typeof curl === "string") {
|
|
21
|
+
console.log("\n--- Exported curl command ---\n");
|
|
22
|
+
console.log(curl);
|
|
23
|
+
console.log();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=tui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui.js","sourceRoot":"","sources":["../../../src/cli/commands/tui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEpC,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC;KACzC,WAAW,CAAC,8BAA8B,CAAC;KAC3C,MAAM,CAAC,qBAAqB,EAAE,yBAAyB,CAAC;KACxD,MAAM,CAAC,MAAM,EAAE,iEAAiE,CAAC;KACjF,MAAM,CAAC,CAAC,OAAyC,EAAE,EAAE;IACpD,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,MAAM,CACvC,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CACnD,CAAC;IAEF,+DAA+D;IAC/D,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;QACf,UAAU,CAAC,GAAG,EAAE;YACd,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAED,KAAK,aAAa,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QAC7B,yCAAyC;QACzC,MAAM,IAAI,GAAI,UAAsC,CAAC,YAAY,CAAC,CAAC;QACnE,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;YACjD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import { clearCommand } from "./commands/clear.js";
|
|
4
|
+
import { initCommand } from "./commands/init.js";
|
|
5
|
+
import { interceptCommand } from "./commands/intercept.js";
|
|
6
|
+
import { projectCommand } from "./commands/project.js";
|
|
7
|
+
import { tuiCommand } from "./commands/tui.js";
|
|
8
|
+
import { statusCommand } from "./commands/status.js";
|
|
9
|
+
import { stopCommand } from "./commands/stop.js";
|
|
10
|
+
program.name("htpx").description("Terminal HTTP interception toolkit").version("0.1.0");
|
|
11
|
+
program.addCommand(clearCommand);
|
|
12
|
+
program.addCommand(initCommand);
|
|
13
|
+
program.addCommand(interceptCommand);
|
|
14
|
+
program.addCommand(projectCommand);
|
|
15
|
+
program.addCommand(tuiCommand);
|
|
16
|
+
program.addCommand(statusCommand);
|
|
17
|
+
program.addCommand(stopCommand);
|
|
18
|
+
program.parse();
|
|
19
|
+
// test
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAExF,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC/B,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAEhC,OAAO,CAAC,KAAK,EAAE,CAAC;AAChB,OAAO"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root TUI component for browsing captured HTTP traffic.
|
|
3
|
+
*/
|
|
4
|
+
import React from "react";
|
|
5
|
+
interface AppProps {
|
|
6
|
+
label?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function App({ label }: AppProps): React.ReactElement;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=App.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/App.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAgC,MAAM,OAAO,CAAC;AASrD,UAAU,QAAQ;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,wBAAgB,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,GAAG,KAAK,CAAC,YAAY,CAyI3D"}
|