@integsec/agentic-pentest-proxy 0.1.1 → 0.2.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.
Files changed (37) hide show
  1. package/README.md +26 -0
  2. package/dist/bin/integsec-agentic-pentest-tui.d.ts +3 -0
  3. package/dist/bin/integsec-agentic-pentest-tui.d.ts.map +1 -0
  4. package/dist/bin/integsec-agentic-pentest-tui.js +37 -0
  5. package/dist/bin/integsec-agentic-pentest-tui.js.map +1 -0
  6. package/dist/src/transports/stdio.d.ts.map +1 -1
  7. package/dist/src/transports/stdio.js +7 -3
  8. package/dist/src/transports/stdio.js.map +1 -1
  9. package/dist/src/tui/App.d.ts +8 -0
  10. package/dist/src/tui/App.d.ts.map +1 -0
  11. package/dist/src/tui/App.js +15 -0
  12. package/dist/src/tui/App.js.map +1 -0
  13. package/dist/src/tui/DecisionRow.d.ts +8 -0
  14. package/dist/src/tui/DecisionRow.d.ts.map +1 -0
  15. package/dist/src/tui/DecisionRow.js +14 -0
  16. package/dist/src/tui/DecisionRow.js.map +1 -0
  17. package/dist/src/tui/EngagementHeader.d.ts +8 -0
  18. package/dist/src/tui/EngagementHeader.d.ts.map +1 -0
  19. package/dist/src/tui/EngagementHeader.js +9 -0
  20. package/dist/src/tui/EngagementHeader.js.map +1 -0
  21. package/dist/src/tui/LiveFeed.d.ts +9 -0
  22. package/dist/src/tui/LiveFeed.d.ts.map +1 -0
  23. package/dist/src/tui/LiveFeed.js +11 -0
  24. package/dist/src/tui/LiveFeed.js.map +1 -0
  25. package/dist/src/tui/StatsPanel.d.ts +8 -0
  26. package/dist/src/tui/StatsPanel.d.ts.map +1 -0
  27. package/dist/src/tui/StatsPanel.js +23 -0
  28. package/dist/src/tui/StatsPanel.js.map +1 -0
  29. package/dist/src/tui/audit-tailer.d.ts +12 -0
  30. package/dist/src/tui/audit-tailer.d.ts.map +1 -0
  31. package/dist/src/tui/audit-tailer.js +47 -0
  32. package/dist/src/tui/audit-tailer.js.map +1 -0
  33. package/dist/src/tui/useAuditWatcher.d.ts +7 -0
  34. package/dist/src/tui/useAuditWatcher.d.ts.map +1 -0
  35. package/dist/src/tui/useAuditWatcher.js +34 -0
  36. package/dist/src/tui/useAuditWatcher.js.map +1 -0
  37. 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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=integsec-agentic-pentest-tui.d.ts.map
@@ -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":"stdio.d.ts","sourceRoot":"","sources":["../../../src/transports/stdio.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,wBAAsB,aAAa,CACjC,KAAK,EAAE,qBAAqB,EAC5B,eAAe,EAAE,MAAM,EACvB,YAAY,GAAE,MAAM,EAAO,GAC1B,OAAO,CAAC,IAAI,CAAC,CAuDf"}
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../../src/transports/stdio.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,wBAAsB,aAAa,CACjC,KAAK,EAAE,qBAAqB,EAC5B,eAAe,EAAE,MAAM,EACvB,YAAY,GAAE,MAAM,EAAO,GAC1B,OAAO,CAAC,IAAI,CAAC,CA2Df"}
@@ -1,9 +1,13 @@
1
1
  import { spawn } from "child_process";
2
2
  import { createInterface } from "readline";
3
3
  export async function runStdioProxy(proxy, upstreamCommand, upstreamArgs = []) {
4
- // On Windows, commands like "npx" are .cmd/.ps1 wrappers that require
5
- // shell resolution. Use shell: true universally for compatibility.
6
- const upstream = spawn(upstreamCommand, upstreamArgs, {
4
+ // On Windows, commands like "npx" are .cmd wrappers that require shell
5
+ // resolution, and paths may contain spaces (e.g. "C:\Program Files\...").
6
+ // Build a single quoted command string and use shell: true with no args
7
+ // array to avoid ENOENT, EINVAL, and DEP0190 issues.
8
+ const quote = (s) => (s.includes(" ") ? `"${s}"` : s);
9
+ const cmdString = [quote(upstreamCommand), ...upstreamArgs.map(quote)].join(" ");
10
+ const upstream = spawn(cmdString, {
7
11
  stdio: ["pipe", "pipe", "inherit"],
8
12
  shell: true,
9
13
  });
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../../src/transports/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG3C,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA4B,EAC5B,eAAuB,EACvB,eAAyB,EAAE;IAE3B,sEAAsE;IACtE,mEAAmE;IACnE,MAAM,QAAQ,GAAiB,KAAK,CAAC,eAAe,EAAE,YAAY,EAAE;QAClE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;QAClC,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;IAC3C,WAAW,CAAC,KAAK,EAAE,CAAC;IAEpB,MAAM,UAAU,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClF,MAAM,cAAc,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IAExF,2BAA2B;IAC3B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACnC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACjE,IAAI,OAAO,EAAE,CAAC;gBACZ,QAAQ,CAAC,KAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,QAAQ,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;YAC/C,QAAQ,CAAC,KAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,gDAAgD;IAChD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACjC,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../../src/transports/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAG3C,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAA4B,EAC5B,eAAuB,EACvB,eAAyB,EAAE;IAE3B,uEAAuE;IACvE,0EAA0E;IAC1E,wEAAwE;IACxE,qDAAqD;IACrD,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAiB,KAAK,CAAC,SAAS,EAAE;QAC9C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;QAClC,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;IAC3C,WAAW,CAAC,KAAK,EAAE,CAAC;IAEpB,MAAM,UAAU,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClF,MAAM,cAAc,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IAExF,2BAA2B;IAC3B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACnC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACjE,IAAI,OAAO,EAAE,CAAC;gBACZ,QAAQ,CAAC,KAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,QAAQ,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;YAC/C,QAAQ,CAAC,KAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,gDAAgD;IAChD,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACjC,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;QAC9B,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ interface AppProps {
3
+ auditDir: string;
4
+ engagementId?: string;
5
+ }
6
+ export declare function App({ auditDir, engagementId }: AppProps): React.ReactElement;
7
+ export {};
8
+ //# sourceMappingURL=App.d.ts.map
@@ -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,7 @@
1
+ import type { AuditEntry } from "../types.js";
2
+ interface WatcherState {
3
+ entries: AuditEntry[];
4
+ }
5
+ export declare function useAuditWatcher(auditDir: string, engagementId?: string): WatcherState;
6
+ export {};
7
+ //# sourceMappingURL=useAuditWatcher.d.ts.map
@@ -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.1",
3
+ "version": "0.2.0",
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
- "zod": "^3.24.0",
41
+ "dotenv": "^16.4.0",
42
+ "ink": "^5.2.1",
43
+ "ink-spinner": "^5.0.0",
41
44
  "ip-cidr": "^4.0.1",
42
- "dotenv": "^16.4.0"
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": {