@integsec/agentic-pentest-proxy 0.1.2 → 0.2.1
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 +26 -0
- package/dist/bin/integsec-agentic-pentest-tui.d.ts +3 -0
- package/dist/bin/integsec-agentic-pentest-tui.d.ts.map +1 -0
- package/dist/bin/integsec-agentic-pentest-tui.js +37 -0
- package/dist/bin/integsec-agentic-pentest-tui.js.map +1 -0
- package/dist/src/extractor.d.ts.map +1 -1
- package/dist/src/extractor.js +9 -0
- package/dist/src/extractor.js.map +1 -1
- package/dist/src/tui/App.d.ts +8 -0
- package/dist/src/tui/App.d.ts.map +1 -0
- package/dist/src/tui/App.js +15 -0
- package/dist/src/tui/App.js.map +1 -0
- package/dist/src/tui/DecisionRow.d.ts +8 -0
- package/dist/src/tui/DecisionRow.d.ts.map +1 -0
- package/dist/src/tui/DecisionRow.js +14 -0
- package/dist/src/tui/DecisionRow.js.map +1 -0
- package/dist/src/tui/EngagementHeader.d.ts +8 -0
- package/dist/src/tui/EngagementHeader.d.ts.map +1 -0
- package/dist/src/tui/EngagementHeader.js +9 -0
- package/dist/src/tui/EngagementHeader.js.map +1 -0
- package/dist/src/tui/LiveFeed.d.ts +9 -0
- package/dist/src/tui/LiveFeed.d.ts.map +1 -0
- package/dist/src/tui/LiveFeed.js +11 -0
- package/dist/src/tui/LiveFeed.js.map +1 -0
- package/dist/src/tui/StatsPanel.d.ts +8 -0
- package/dist/src/tui/StatsPanel.d.ts.map +1 -0
- package/dist/src/tui/StatsPanel.js +23 -0
- package/dist/src/tui/StatsPanel.js.map +1 -0
- package/dist/src/tui/audit-tailer.d.ts +12 -0
- package/dist/src/tui/audit-tailer.d.ts.map +1 -0
- package/dist/src/tui/audit-tailer.js +47 -0
- package/dist/src/tui/audit-tailer.js.map +1 -0
- package/dist/src/tui/useAuditWatcher.d.ts +7 -0
- package/dist/src/tui/useAuditWatcher.d.ts.map +1 -0
- package/dist/src/tui/useAuditWatcher.js +34 -0
- package/dist/src/tui/useAuditWatcher.js.map +1 -0
- package/package.json +10 -5
package/README.md
CHANGED
|
@@ -41,6 +41,7 @@ Built by **[IntegSec](https://integsec.com)** — offensive cybersecurity testin
|
|
|
41
41
|
- [Claude Code Integration](#claude-code-integration)
|
|
42
42
|
- [Docker](#docker)
|
|
43
43
|
- [HTTP Mode](#http-mode)
|
|
44
|
+
- [TUI Monitor](#tui-monitor)
|
|
44
45
|
- [How Validation Works](#how-validation-works)
|
|
45
46
|
- [Audit Logging](#audit-logging)
|
|
46
47
|
- [Examples](#examples)
|
|
@@ -354,6 +355,31 @@ docker run --rm \
|
|
|
354
355
|
|
|
355
356
|
---
|
|
356
357
|
|
|
358
|
+
## TUI Monitor
|
|
359
|
+
|
|
360
|
+
A real-time terminal dashboard for monitoring proxy decisions as they happen.
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# Monitor the default audit directory
|
|
364
|
+
integsec-agentic-pentest-tui
|
|
365
|
+
|
|
366
|
+
# Monitor a specific directory
|
|
367
|
+
integsec-agentic-pentest-tui --audit-path /path/to/audit
|
|
368
|
+
|
|
369
|
+
# Filter to a specific engagement
|
|
370
|
+
integsec-agentic-pentest-tui --engagement ENG-2026-TEST-001
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
The TUI displays three panels:
|
|
374
|
+
|
|
375
|
+
- **Engagement Header** — engagement ID, client, operator
|
|
376
|
+
- **Stats Panel** — running allowed/blocked counts, top targets, top tools
|
|
377
|
+
- **Live Feed** — color-coded scrolling decision feed (green = allowed, red = blocked)
|
|
378
|
+
|
|
379
|
+
Run the TUI in a separate terminal while the proxy is active (via Claude Desktop, Claude Code, or CLI). It tails the audit JSONL files and updates in real time.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
357
383
|
## How Validation Works
|
|
358
384
|
|
|
359
385
|
Every `tools/call` JSON-RPC message passes through an 8-step validation pipeline:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integsec-agentic-pentest-tui.d.ts","sourceRoot":"","sources":["../../bin/integsec-agentic-pentest-tui.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { render } from "ink";
|
|
4
|
+
import { App } from "../src/tui/App.js";
|
|
5
|
+
function parseArgs() {
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
let auditDir = process.env.AUDIT_LOG_PATH ?? "./audit";
|
|
8
|
+
let engagementId;
|
|
9
|
+
for (let i = 0; i < args.length; i++) {
|
|
10
|
+
if (args[i] === "--audit-path" && args[i + 1]) {
|
|
11
|
+
auditDir = args[i + 1];
|
|
12
|
+
i++;
|
|
13
|
+
}
|
|
14
|
+
else if (args[i] === "--engagement" && args[i + 1]) {
|
|
15
|
+
engagementId = args[i + 1];
|
|
16
|
+
i++;
|
|
17
|
+
}
|
|
18
|
+
else if (args[i] === "--help" || args[i] === "-h") {
|
|
19
|
+
console.log(`
|
|
20
|
+
IntegSec Agentic Pentest MCP Proxy — TUI Monitor
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
integsec-agentic-pentest-tui [options]
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
--audit-path <dir> Path to audit log directory (default: AUDIT_LOG_PATH or ./audit)
|
|
27
|
+
--engagement <id> Filter to a specific engagement ID
|
|
28
|
+
-h, --help Show this help message
|
|
29
|
+
`);
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { auditDir, engagementId };
|
|
34
|
+
}
|
|
35
|
+
const { auditDir, engagementId } = parseArgs();
|
|
36
|
+
render(_jsx(App, { auditDir: auditDir, engagementId: engagementId }));
|
|
37
|
+
//# sourceMappingURL=integsec-agentic-pentest-tui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integsec-agentic-pentest-tui.js","sourceRoot":"","sources":["../../bin/integsec-agentic-pentest-tui.tsx"],"names":[],"mappings":";;AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAExC,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,SAAS,CAAC;IACvD,IAAI,YAAgC,CAAC;IAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC9C,QAAQ,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACvB,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACrD,YAAY,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3B,CAAC,EAAE,CAAC;QACN,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;CAUjB,CAAC,CAAC;YACG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,SAAS,EAAE,CAAC;AAC/C,MAAM,CAAC,KAAC,GAAG,IAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,GAAI,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf;oDACgD;IAChD,YAAY,EAAE,OAAO,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf;oDACgD;IAChD,YAAY,EAAE,OAAO,CAAC;CACvB;AA+KD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,gBAAgB,GAAG,IAAI,CAmBzB"}
|
package/dist/src/extractor.js
CHANGED
|
@@ -30,6 +30,13 @@ const TOOL_MAPPINGS = [
|
|
|
30
30
|
{ match: "msf_*", params: ["rhost", "rhosts", "target"] },
|
|
31
31
|
{ match: "metasploit", params: ["rhost", "rhosts", "target"] },
|
|
32
32
|
{ match: "nuclei", params: ["target", "targets", "url"] },
|
|
33
|
+
// TurboPentest MCP server tools
|
|
34
|
+
{ match: "start_pentest", params: ["target_url", "url", "domain"] },
|
|
35
|
+
{ match: "get_pentest", params: ["target_url", "domain"] },
|
|
36
|
+
{ match: "get_findings", params: ["target_url", "domain"] },
|
|
37
|
+
{ match: "download_report", params: ["target_url", "domain"] },
|
|
38
|
+
{ match: "list_pentests", params: ["domain"] },
|
|
39
|
+
{ match: "verify_attestation", params: ["target_url", "domain"] },
|
|
33
40
|
];
|
|
34
41
|
/**
|
|
35
42
|
* Fallback parameter names tried (in priority order) when the tool name does
|
|
@@ -37,8 +44,10 @@ const TOOL_MAPPINGS = [
|
|
|
37
44
|
*/
|
|
38
45
|
const FALLBACK_PARAMS = [
|
|
39
46
|
"target",
|
|
47
|
+
"target_url",
|
|
40
48
|
"host",
|
|
41
49
|
"url",
|
|
50
|
+
"domain",
|
|
42
51
|
"rhost",
|
|
43
52
|
"destination",
|
|
44
53
|
"uri",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA2BH,MAAM,aAAa,GAA2B;IAC5C,EAAE,KAAK,EAAE,MAAM,EAAe,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IACnE,EAAE,KAAK,EAAE,WAAW,EAAU,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IACnE,EAAE,KAAK,EAAE,WAAW,EAAU,MAAM,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE;IACzE,EAAE,KAAK,EAAE,kBAAkB,EAAG,MAAM,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE;IACzE,EAAE,KAAK,EAAE,QAAQ,EAAa,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE;IACzD,EAAE,KAAK,EAAE,MAAM,EAAe,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE;IACtD,EAAE,KAAK,EAAE,cAAc,EAAO,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE;IACtD,EAAE,KAAK,EAAE,OAAO,EAAc,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE;IACjE,EAAE,KAAK,EAAE,UAAU,EAAW,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE;IACzD,EAAE,KAAK,EAAE,MAAM,EAAe,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE;IACzD,EAAE,KAAK,EAAE,MAAM,EAAe,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE;IACzD,EAAE,KAAK,EAAE,QAAQ,EAAa,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;IAC1D,EAAE,KAAK,EAAE,IAAI,EAAiB,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;IAC1D,EAAE,KAAK,EAAE,MAAM,EAAe,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;IAC1D,EAAE,KAAK,EAAE,YAAY,EAAS,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;IAC1D,2EAA2E;IAC3E,EAAE,KAAK,EAAE,OAAO,EAAc,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE;IACrE,EAAE,KAAK,EAAE,YAAY,EAAS,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE;IACrE,EAAE,KAAK,EAAE,QAAQ,EAAa,MAAM,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../src/tui/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,UAAU,QAAQ;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,GAAG,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,QAAQ,GAAG,KAAK,CAAC,YAAY,CAe5E"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, useStdout } from "ink";
|
|
3
|
+
import { EngagementHeader } from "./EngagementHeader.js";
|
|
4
|
+
import { StatsPanel } from "./StatsPanel.js";
|
|
5
|
+
import { LiveFeed } from "./LiveFeed.js";
|
|
6
|
+
import { useAuditWatcher } from "./useAuditWatcher.js";
|
|
7
|
+
export function App({ auditDir, engagementId }) {
|
|
8
|
+
const { entries } = useAuditWatcher(auditDir, engagementId);
|
|
9
|
+
const { stdout } = useStdout();
|
|
10
|
+
const termHeight = stdout?.rows ?? 24;
|
|
11
|
+
const feedRows = Math.max(5, termHeight - 12);
|
|
12
|
+
const firstEntry = entries.length > 0 ? entries[0] : null;
|
|
13
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(EngagementHeader, { entry: firstEntry }), _jsx(StatsPanel, { entries: entries }), _jsx(LiveFeed, { entries: entries, maxRows: feedRows })] }));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=App.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.js","sourceRoot":"","sources":["../../../src/tui/App.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAOvD,MAAM,UAAU,GAAG,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAY;IACtD,MAAM,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC5D,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;IAEtC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,EAAE,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE1D,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,gBAAgB,IAAC,KAAK,EAAE,UAAU,GAAI,EACvC,KAAC,UAAU,IAAC,OAAO,EAAE,OAAO,GAAI,EAChC,KAAC,QAAQ,IAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,GAAI,IAC7C,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { AuditEntry } from "../types.js";
|
|
3
|
+
interface DecisionRowProps {
|
|
4
|
+
entry: AuditEntry;
|
|
5
|
+
}
|
|
6
|
+
export declare function DecisionRow({ entry }: DecisionRowProps): React.ReactElement;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=DecisionRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DecisionRow.d.ts","sourceRoot":"","sources":["../../../src/tui/DecisionRow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,UAAU,gBAAgB;IACxB,KAAK,EAAE,UAAU,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,gBAAgB,GAAG,KAAK,CAAC,YAAY,CAiB3E"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from "ink";
|
|
3
|
+
export function DecisionRow({ entry }) {
|
|
4
|
+
const time = entry.timestamp.slice(11, 19);
|
|
5
|
+
const isBlocked = entry.decision.startsWith("BLOCKED");
|
|
6
|
+
const isNoTarget = entry.decision === "ALLOWED_NO_TARGET";
|
|
7
|
+
const icon = isBlocked ? "✗" : "✓";
|
|
8
|
+
const color = isBlocked ? "red" : isNoTarget ? "gray" : "green";
|
|
9
|
+
const shortDecision = entry.decision.replace("BLOCKED_", "");
|
|
10
|
+
const target = entry.extracted_target ?? "—";
|
|
11
|
+
const reason = isBlocked ? ` [${shortDecision}]` : "";
|
|
12
|
+
return (_jsxs(Text, { color: color, children: [time, " ", icon, " ", entry.decision.split("_")[0].padEnd(7), " ", entry.tool_name, " \u2192 ", target, reason, " (", entry.duration_ms, "ms)"] }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=DecisionRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DecisionRow.js","sourceRoot":"","sources":["../../../src/tui/DecisionRow.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAO3B,MAAM,UAAU,WAAW,CAAC,EAAE,KAAK,EAAoB;IACrD,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,KAAK,mBAAmB,CAAC;IAE1D,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACnC,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAEhE,MAAM,aAAa,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,IAAI,GAAG,CAAC;IAC7C,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtD,OAAO,CACL,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,aACf,IAAI,OAAG,IAAI,OAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAG,KAAK,CAAC,SAAS,cAAK,MAAM,EAAE,MAAM,QAAI,KAAK,CAAC,WAAW,WAC1G,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { AuditEntry } from "../types.js";
|
|
3
|
+
interface EngagementHeaderProps {
|
|
4
|
+
entry: AuditEntry | null;
|
|
5
|
+
}
|
|
6
|
+
export declare function EngagementHeader({ entry }: EngagementHeaderProps): React.ReactElement;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=EngagementHeader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EngagementHeader.d.ts","sourceRoot":"","sources":["../../../src/tui/EngagementHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,UAAU,qBAAqB;IAC7B,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE,qBAAqB,GAAG,KAAK,CAAC,YAAY,CAgBrF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
export function EngagementHeader({ entry }) {
|
|
4
|
+
if (!entry) {
|
|
5
|
+
return (_jsx(Box, { borderStyle: "single", paddingX: 1, children: _jsx(Text, { dimColor: true, children: "Waiting for audit data..." }) }));
|
|
6
|
+
}
|
|
7
|
+
return (_jsx(Box, { borderStyle: "single", paddingX: 1, flexDirection: "column", children: _jsxs(Text, { bold: true, children: [entry.engagement_id, " ", _jsx(Text, { dimColor: true, children: "|" }), " ", entry.client, " ", _jsx(Text, { dimColor: true, children: "|" }), " ", entry.operator] }) }));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=EngagementHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EngagementHeader.js","sourceRoot":"","sources":["../../../src/tui/EngagementHeader.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAOhC,MAAM,UAAU,gBAAgB,CAAC,EAAE,KAAK,EAAyB;IAC/D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CACL,KAAC,GAAG,IAAC,WAAW,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,YACnC,KAAC,IAAI,IAAC,QAAQ,gDAAiC,GAC3C,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,KAAC,GAAG,IAAC,WAAW,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,YAC3D,MAAC,IAAI,IAAC,IAAI,mBACP,KAAK,CAAC,aAAa,OAAE,KAAC,IAAI,IAAC,QAAQ,wBAAS,OAAE,KAAK,CAAC,MAAM,OAAE,KAAC,IAAI,IAAC,QAAQ,wBAAS,OAAE,KAAK,CAAC,QAAQ,IAC/F,GACH,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { AuditEntry } from "../types.js";
|
|
3
|
+
interface LiveFeedProps {
|
|
4
|
+
entries: AuditEntry[];
|
|
5
|
+
maxRows: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function LiveFeed({ entries, maxRows }: LiveFeedProps): React.ReactElement;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=LiveFeed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LiveFeed.d.ts","sourceRoot":"","sources":["../../../src/tui/LiveFeed.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,UAAU,aAAa;IACrB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,aAAa,GAAG,KAAK,CAAC,YAAY,CAoBhF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { DecisionRow } from "./DecisionRow.js";
|
|
4
|
+
export function LiveFeed({ entries, maxRows }) {
|
|
5
|
+
const visible = entries.slice(-maxRows);
|
|
6
|
+
if (visible.length === 0) {
|
|
7
|
+
return (_jsxs(Box, { borderStyle: "single", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: " LIVE FEED" }), _jsx(Text, { dimColor: true, children: "No decisions yet..." })] }));
|
|
8
|
+
}
|
|
9
|
+
return (_jsxs(Box, { borderStyle: "single", paddingX: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: " LIVE FEED" }), visible.map((entry, i) => (_jsx(DecisionRow, { entry: entry }, `${entry.timestamp}-${i}`)))] }));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=LiveFeed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LiveFeed.js","sourceRoot":"","sources":["../../../src/tui/LiveFeed.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAO/C,MAAM,UAAU,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,EAAiB;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IAExC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CACL,MAAC,GAAG,IAAC,WAAW,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aAC3D,KAAC,IAAI,IAAC,IAAI,iCAAkB,EAC5B,KAAC,IAAI,IAAC,QAAQ,0CAA2B,IACrC,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,MAAC,GAAG,IAAC,WAAW,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aAC3D,KAAC,IAAI,IAAC,IAAI,iCAAkB,EAC3B,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CACzB,KAAC,WAAW,IAAiC,KAAK,EAAE,KAAK,IAAvC,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,EAAE,CAAkB,CAC9D,CAAC,IACE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { AuditEntry } from "../types.js";
|
|
3
|
+
interface StatsPanelProps {
|
|
4
|
+
entries: AuditEntry[];
|
|
5
|
+
}
|
|
6
|
+
export declare function StatsPanel({ entries }: StatsPanelProps): React.ReactElement;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=StatsPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatsPanel.d.ts","sourceRoot":"","sources":["../../../src/tui/StatsPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,UAAU,eAAe;IACvB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAUD,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,eAAe,GAAG,KAAK,CAAC,YAAY,CA+B3E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
function topN(counts, n) {
|
|
4
|
+
return [...counts.entries()]
|
|
5
|
+
.sort((a, b) => b[1] - a[1])
|
|
6
|
+
.slice(0, n)
|
|
7
|
+
.map(([name, count]) => `${name} (${count})`)
|
|
8
|
+
.join(" ");
|
|
9
|
+
}
|
|
10
|
+
export function StatsPanel({ entries }) {
|
|
11
|
+
const allowed = entries.filter((e) => e.decision.startsWith("ALLOWED")).length;
|
|
12
|
+
const blocked = entries.length - allowed;
|
|
13
|
+
const targetCounts = new Map();
|
|
14
|
+
const toolCounts = new Map();
|
|
15
|
+
for (const e of entries) {
|
|
16
|
+
if (e.extracted_target) {
|
|
17
|
+
targetCounts.set(e.extracted_target, (targetCounts.get(e.extracted_target) ?? 0) + 1);
|
|
18
|
+
}
|
|
19
|
+
toolCounts.set(e.tool_name, (toolCounts.get(e.tool_name) ?? 0) + 1);
|
|
20
|
+
}
|
|
21
|
+
return (_jsxs(Box, { borderStyle: "single", paddingX: 1, flexDirection: "column", children: [_jsxs(Text, { children: [_jsxs(Text, { color: "green", children: ["\u2713 Allowed: ", allowed] }), " ", _jsxs(Text, { color: "red", children: ["\u2717 Blocked: ", blocked] }), " ", _jsxs(Text, { children: ["Total: ", entries.length] })] }), targetCounts.size > 0 && (_jsxs(Text, { dimColor: true, children: ["Targets: ", topN(targetCounts, 3)] })), toolCounts.size > 0 && (_jsxs(Text, { dimColor: true, children: ["Tools: ", topN(toolCounts, 3)] }))] }));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=StatsPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatsPanel.js","sourceRoot":"","sources":["../../../src/tui/StatsPanel.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAOhC,SAAS,IAAI,CAAC,MAA2B,EAAE,CAAS;IAClD,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;SACzB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SAC3B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC;SAC5C,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAmB;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/E,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC;IAEzC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE7C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACvB,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxF,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,CACL,MAAC,GAAG,IAAC,WAAW,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aAC3D,MAAC,IAAI,eACH,MAAC,IAAI,IAAC,KAAK,EAAC,OAAO,iCAAa,OAAO,IAAQ,EAC9C,KAAK,EACN,MAAC,IAAI,IAAC,KAAK,EAAC,KAAK,iCAAa,OAAO,IAAQ,EAC5C,KAAK,EACN,MAAC,IAAI,0BAAS,OAAO,CAAC,MAAM,IAAQ,IAC/B,EACN,YAAY,CAAC,IAAI,GAAG,CAAC,IAAI,CACxB,MAAC,IAAI,IAAC,QAAQ,gCAAW,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,IAAQ,CACvD,EACA,UAAU,CAAC,IAAI,GAAG,CAAC,IAAI,CACtB,MAAC,IAAI,IAAC,QAAQ,8BAAS,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,IAAQ,CACnD,IACG,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AuditEntry } from "../types.js";
|
|
2
|
+
export interface TailResult {
|
|
3
|
+
entries: AuditEntry[];
|
|
4
|
+
newOffset: number;
|
|
5
|
+
}
|
|
6
|
+
export interface ScanResult {
|
|
7
|
+
entries: AuditEntry[];
|
|
8
|
+
offsets: Map<string, number>;
|
|
9
|
+
}
|
|
10
|
+
export declare function readNewEntries(filePath: string, offset: number): TailResult;
|
|
11
|
+
export declare function scanExistingEntries(auditDir: string, engagementId?: string): ScanResult;
|
|
12
|
+
//# sourceMappingURL=audit-tailer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-tailer.d.ts","sourceRoot":"","sources":["../../../src/tui/audit-tailer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CA4B3E;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,UAAU,CAqBZ"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
export function readNewEntries(filePath, offset) {
|
|
4
|
+
if (!fs.existsSync(filePath)) {
|
|
5
|
+
return { entries: [], newOffset: offset };
|
|
6
|
+
}
|
|
7
|
+
const stat = fs.statSync(filePath);
|
|
8
|
+
if (stat.size <= offset) {
|
|
9
|
+
return { entries: [], newOffset: offset };
|
|
10
|
+
}
|
|
11
|
+
const fd = fs.openSync(filePath, "r");
|
|
12
|
+
const buf = Buffer.alloc(stat.size - offset);
|
|
13
|
+
fs.readSync(fd, buf, 0, buf.length, offset);
|
|
14
|
+
fs.closeSync(fd);
|
|
15
|
+
const text = buf.toString("utf-8");
|
|
16
|
+
const lines = text.split("\n").filter((l) => l.trim().length > 0);
|
|
17
|
+
const entries = [];
|
|
18
|
+
for (const line of lines) {
|
|
19
|
+
try {
|
|
20
|
+
entries.push(JSON.parse(line));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Skip malformed lines
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { entries, newOffset: stat.size };
|
|
27
|
+
}
|
|
28
|
+
export function scanExistingEntries(auditDir, engagementId) {
|
|
29
|
+
if (!fs.existsSync(auditDir)) {
|
|
30
|
+
return { entries: [], offsets: new Map() };
|
|
31
|
+
}
|
|
32
|
+
const files = fs.readdirSync(auditDir).filter((f) => f.endsWith(".jsonl"));
|
|
33
|
+
const allEntries = [];
|
|
34
|
+
const offsets = new Map();
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
if (engagementId && file !== `${engagementId}.jsonl`) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const filePath = path.join(auditDir, file);
|
|
40
|
+
const result = readNewEntries(filePath, 0);
|
|
41
|
+
allEntries.push(...result.entries);
|
|
42
|
+
offsets.set(filePath, result.newOffset);
|
|
43
|
+
}
|
|
44
|
+
allEntries.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
45
|
+
return { entries: allEntries, offsets };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=audit-tailer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-tailer.js","sourceRoot":"","sources":["../../../src/tui/audit-tailer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuditWatcher.d.ts","sourceRoot":"","sources":["../../../src/tui/useAuditWatcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,UAAU,YAAY;IACpB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,CAiCrF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { readNewEntries, scanExistingEntries } from "./audit-tailer.js";
|
|
5
|
+
export function useAuditWatcher(auditDir, engagementId) {
|
|
6
|
+
const [entries, setEntries] = useState([]);
|
|
7
|
+
const offsetsRef = useRef(new Map());
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const scan = scanExistingEntries(auditDir, engagementId);
|
|
10
|
+
setEntries(scan.entries);
|
|
11
|
+
offsetsRef.current = scan.offsets;
|
|
12
|
+
if (!fs.existsSync(auditDir)) {
|
|
13
|
+
fs.mkdirSync(auditDir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
const watcher = fs.watch(auditDir, (_event, filename) => {
|
|
16
|
+
if (!filename || !filename.endsWith(".jsonl"))
|
|
17
|
+
return;
|
|
18
|
+
if (engagementId && filename !== `${engagementId}.jsonl`)
|
|
19
|
+
return;
|
|
20
|
+
const filePath = path.join(auditDir, filename);
|
|
21
|
+
const currentOffset = offsetsRef.current.get(filePath) ?? 0;
|
|
22
|
+
const result = readNewEntries(filePath, currentOffset);
|
|
23
|
+
if (result.entries.length > 0) {
|
|
24
|
+
offsetsRef.current.set(filePath, result.newOffset);
|
|
25
|
+
setEntries((prev) => [...prev, ...result.entries]);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return () => {
|
|
29
|
+
watcher.close();
|
|
30
|
+
};
|
|
31
|
+
}, [auditDir, engagementId]);
|
|
32
|
+
return { entries };
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=useAuditWatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuditWatcher.js","sourceRoot":"","sources":["../../../src/tui/useAuditWatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAMxE,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,YAAqB;IACrE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAe,EAAE,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,MAAM,CAAsB,IAAI,GAAG,EAAE,CAAC,CAAC;IAE1D,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QACzD,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAElC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;YACtD,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACtD,IAAI,YAAY,IAAI,QAAQ,KAAK,GAAG,YAAY,QAAQ;gBAAE,OAAO;YAEjE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC/C,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC5D,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YAEvD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;gBACnD,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAE7B,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@integsec/agentic-pentest-proxy",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "IntegSec Agentic Pentest MCP Proxy — enforce penetration testing engagement scope for AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"integsec-agentic-pentest-proxy": "dist/bin/integsec-agentic-pentest-proxy.js"
|
|
7
|
+
"integsec-agentic-pentest-proxy": "dist/bin/integsec-agentic-pentest-proxy.js",
|
|
8
|
+
"integsec-agentic-pentest-tui": "dist/bin/integsec-agentic-pentest-tui.js"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"dist/",
|
|
@@ -37,19 +38,23 @@
|
|
|
37
38
|
"license": "MIT",
|
|
38
39
|
"dependencies": {
|
|
39
40
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
40
|
-
"
|
|
41
|
+
"dotenv": "^16.4.0",
|
|
42
|
+
"ink": "^5.2.1",
|
|
43
|
+
"ink-spinner": "^5.0.0",
|
|
41
44
|
"ip-cidr": "^4.0.1",
|
|
42
|
-
"
|
|
45
|
+
"react": "^18.3.1",
|
|
46
|
+
"zod": "^3.24.0"
|
|
43
47
|
},
|
|
44
48
|
"devDependencies": {
|
|
45
49
|
"@types/node": "^20.0.0",
|
|
50
|
+
"@types/react": "^18.3.28",
|
|
46
51
|
"typescript": "^5.7.0",
|
|
47
52
|
"vitest": "^3.0.0"
|
|
48
53
|
},
|
|
49
54
|
"optionalDependencies": {
|
|
50
55
|
"@aws-sdk/client-cloudwatch-logs": "^3.700.0",
|
|
51
|
-
"@azure/monitor-ingestion": "^1.1.0",
|
|
52
56
|
"@azure/identity": "^4.5.0",
|
|
57
|
+
"@azure/monitor-ingestion": "^1.1.0",
|
|
53
58
|
"@google-cloud/logging": "^11.0.0"
|
|
54
59
|
},
|
|
55
60
|
"engines": {
|