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.
Files changed (114) hide show
  1. package/README.md +274 -0
  2. package/dist/cli/commands/clear.d.ts +3 -0
  3. package/dist/cli/commands/clear.d.ts.map +1 -0
  4. package/dist/cli/commands/clear.js +30 -0
  5. package/dist/cli/commands/clear.js.map +1 -0
  6. package/dist/cli/commands/init.d.ts +9 -0
  7. package/dist/cli/commands/init.d.ts.map +1 -0
  8. package/dist/cli/commands/init.js +25 -0
  9. package/dist/cli/commands/init.js.map +1 -0
  10. package/dist/cli/commands/intercept.d.ts +8 -0
  11. package/dist/cli/commands/intercept.d.ts.map +1 -0
  12. package/dist/cli/commands/intercept.js +59 -0
  13. package/dist/cli/commands/intercept.js.map +1 -0
  14. package/dist/cli/commands/project.d.ts +3 -0
  15. package/dist/cli/commands/project.d.ts.map +1 -0
  16. package/dist/cli/commands/project.js +13 -0
  17. package/dist/cli/commands/project.js.map +1 -0
  18. package/dist/cli/commands/status.d.ts +3 -0
  19. package/dist/cli/commands/status.d.ts.map +1 -0
  20. package/dist/cli/commands/status.js +36 -0
  21. package/dist/cli/commands/status.js.map +1 -0
  22. package/dist/cli/commands/stop.d.ts +3 -0
  23. package/dist/cli/commands/stop.d.ts.map +1 -0
  24. package/dist/cli/commands/stop.js +27 -0
  25. package/dist/cli/commands/stop.js.map +1 -0
  26. package/dist/cli/commands/tui.d.ts +3 -0
  27. package/dist/cli/commands/tui.d.ts.map +1 -0
  28. package/dist/cli/commands/tui.js +27 -0
  29. package/dist/cli/commands/tui.js.map +1 -0
  30. package/dist/cli/index.d.ts +3 -0
  31. package/dist/cli/index.d.ts.map +1 -0
  32. package/dist/cli/index.js +20 -0
  33. package/dist/cli/index.js.map +1 -0
  34. package/dist/cli/tui/App.d.ts +10 -0
  35. package/dist/cli/tui/App.d.ts.map +1 -0
  36. package/dist/cli/tui/App.js +96 -0
  37. package/dist/cli/tui/App.js.map +1 -0
  38. package/dist/cli/tui/components/BodyView.d.ts +14 -0
  39. package/dist/cli/tui/components/BodyView.d.ts.map +1 -0
  40. package/dist/cli/tui/components/BodyView.js +39 -0
  41. package/dist/cli/tui/components/BodyView.js.map +1 -0
  42. package/dist/cli/tui/components/HeadersView.d.ts +13 -0
  43. package/dist/cli/tui/components/HeadersView.d.ts.map +1 -0
  44. package/dist/cli/tui/components/HeadersView.js +8 -0
  45. package/dist/cli/tui/components/HeadersView.js.map +1 -0
  46. package/dist/cli/tui/components/RequestDetails.d.ts +13 -0
  47. package/dist/cli/tui/components/RequestDetails.d.ts.map +1 -0
  48. package/dist/cli/tui/components/RequestDetails.js +19 -0
  49. package/dist/cli/tui/components/RequestDetails.js.map +1 -0
  50. package/dist/cli/tui/components/RequestList.d.ts +15 -0
  51. package/dist/cli/tui/components/RequestList.d.ts.map +1 -0
  52. package/dist/cli/tui/components/RequestList.js +17 -0
  53. package/dist/cli/tui/components/RequestList.js.map +1 -0
  54. package/dist/cli/tui/components/RequestListItem.d.ts +13 -0
  55. package/dist/cli/tui/components/RequestListItem.d.ts.map +1 -0
  56. package/dist/cli/tui/components/RequestListItem.js +53 -0
  57. package/dist/cli/tui/components/RequestListItem.js.map +1 -0
  58. package/dist/cli/tui/components/StatusBar.d.ts +10 -0
  59. package/dist/cli/tui/components/StatusBar.d.ts.map +1 -0
  60. package/dist/cli/tui/components/StatusBar.js +18 -0
  61. package/dist/cli/tui/components/StatusBar.js.map +1 -0
  62. package/dist/cli/tui/hooks/useExport.d.ts +18 -0
  63. package/dist/cli/tui/hooks/useExport.d.ts.map +1 -0
  64. package/dist/cli/tui/hooks/useExport.js +58 -0
  65. package/dist/cli/tui/hooks/useExport.js.map +1 -0
  66. package/dist/cli/tui/hooks/useRequests.d.ts +20 -0
  67. package/dist/cli/tui/hooks/useRequests.d.ts.map +1 -0
  68. package/dist/cli/tui/hooks/useRequests.js +85 -0
  69. package/dist/cli/tui/hooks/useRequests.js.map +1 -0
  70. package/dist/cli/tui/hooks/useStdoutDimensions.d.ts +11 -0
  71. package/dist/cli/tui/hooks/useStdoutDimensions.d.ts.map +1 -0
  72. package/dist/cli/tui/hooks/useStdoutDimensions.js +29 -0
  73. package/dist/cli/tui/hooks/useStdoutDimensions.js.map +1 -0
  74. package/dist/cli/tui/utils/curl.d.ts +9 -0
  75. package/dist/cli/tui/utils/curl.d.ts.map +1 -0
  76. package/dist/cli/tui/utils/curl.js +47 -0
  77. package/dist/cli/tui/utils/curl.js.map +1 -0
  78. package/dist/cli/tui/utils/formatters.d.ts +36 -0
  79. package/dist/cli/tui/utils/formatters.d.ts.map +1 -0
  80. package/dist/cli/tui/utils/formatters.js +108 -0
  81. package/dist/cli/tui/utils/formatters.js.map +1 -0
  82. package/dist/cli/tui/utils/har.d.ts +75 -0
  83. package/dist/cli/tui/utils/har.d.ts.map +1 -0
  84. package/dist/cli/tui/utils/har.js +139 -0
  85. package/dist/cli/tui/utils/har.js.map +1 -0
  86. package/dist/daemon/control.d.ts +63 -0
  87. package/dist/daemon/control.d.ts.map +1 -0
  88. package/dist/daemon/control.js +260 -0
  89. package/dist/daemon/control.js.map +1 -0
  90. package/dist/daemon/index.d.ts +3 -0
  91. package/dist/daemon/index.d.ts.map +1 -0
  92. package/dist/daemon/index.js +107 -0
  93. package/dist/daemon/index.js.map +1 -0
  94. package/dist/daemon/proxy.d.ts +19 -0
  95. package/dist/daemon/proxy.d.ts.map +1 -0
  96. package/dist/daemon/proxy.js +89 -0
  97. package/dist/daemon/proxy.js.map +1 -0
  98. package/dist/daemon/storage.d.ts +60 -0
  99. package/dist/daemon/storage.d.ts.map +1 -0
  100. package/dist/daemon/storage.js +215 -0
  101. package/dist/daemon/storage.js.map +1 -0
  102. package/dist/shared/daemon.d.ts +14 -0
  103. package/dist/shared/daemon.d.ts.map +1 -0
  104. package/dist/shared/daemon.js +161 -0
  105. package/dist/shared/daemon.js.map +1 -0
  106. package/dist/shared/project.d.ts +61 -0
  107. package/dist/shared/project.d.ts.map +1 -0
  108. package/dist/shared/project.js +143 -0
  109. package/dist/shared/project.js.map +1 -0
  110. package/dist/shared/types.d.ts +32 -0
  111. package/dist/shared/types.d.ts.map +1 -0
  112. package/dist/shared/types.js +5 -0
  113. package/dist/shared/types.js.map +1 -0
  114. package/package.json +89 -0
@@ -0,0 +1,96 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /**
3
+ * Root TUI component for browsing captured HTTP traffic.
4
+ */
5
+ import React, { useState, useCallback } from "react";
6
+ import { Box, Text, useInput, useApp, useStdin } from "ink";
7
+ import { useStdoutDimensions } from "./hooks/useStdoutDimensions.js";
8
+ import { useRequests } from "./hooks/useRequests.js";
9
+ import { useExport } from "./hooks/useExport.js";
10
+ import { RequestList } from "./components/RequestList.js";
11
+ import { RequestDetails } from "./components/RequestDetails.js";
12
+ import { StatusBar } from "./components/StatusBar.js";
13
+ export function App({ label }) {
14
+ const { exit } = useApp();
15
+ const { isRawModeSupported } = useStdin();
16
+ const [columns, rows] = useStdoutDimensions();
17
+ const { requests, isLoading, error, refresh } = useRequests({ label });
18
+ const { exportCurl, exportHar } = useExport();
19
+ const [selectedIndex, setSelectedIndex] = useState(0);
20
+ const [activePanel, setActivePanel] = useState("list");
21
+ const [statusMessage, setStatusMessage] = useState();
22
+ // Get the currently selected request
23
+ const selectedRequest = requests[selectedIndex];
24
+ // Clear status message after a delay
25
+ const showStatus = useCallback((message) => {
26
+ setStatusMessage(message);
27
+ setTimeout(() => setStatusMessage(undefined), 3000);
28
+ }, []);
29
+ // Handle keyboard input (only when raw mode is supported, i.e. running in a TTY)
30
+ useInput((input, key) => {
31
+ // Navigation
32
+ if (input === "j" || key.downArrow) {
33
+ setSelectedIndex((prev) => Math.min(prev + 1, requests.length - 1));
34
+ }
35
+ else if (input === "k" || key.upArrow) {
36
+ setSelectedIndex((prev) => Math.max(prev - 1, 0));
37
+ }
38
+ else if (key.tab) {
39
+ setActivePanel((prev) => (prev === "list" ? "details" : "list"));
40
+ }
41
+ // Actions
42
+ else if (input === "q") {
43
+ exit();
44
+ }
45
+ else if (input === "r") {
46
+ void refresh();
47
+ showStatus("Refreshing...");
48
+ }
49
+ else if (input === "c") {
50
+ if (selectedRequest) {
51
+ const result = exportCurl(selectedRequest);
52
+ if (result.success) {
53
+ // In a real implementation, we'd copy to clipboard or show in a modal
54
+ // For now, just indicate success
55
+ showStatus("Curl copied! Check terminal output after exit.");
56
+ // Store for printing after TUI exits
57
+ globalThis["__htpxCurl"] = result.message;
58
+ }
59
+ else {
60
+ showStatus(`Error: ${result.message}`);
61
+ }
62
+ }
63
+ else {
64
+ showStatus("No request selected");
65
+ }
66
+ }
67
+ else if (input === "h") {
68
+ if (requests.length > 0) {
69
+ const result = exportHar(requests);
70
+ showStatus(result.success ? result.message : `Error: ${result.message}`);
71
+ }
72
+ else {
73
+ showStatus("No requests to export");
74
+ }
75
+ }
76
+ }, { isActive: isRawModeSupported === true });
77
+ // Keep selection in bounds when requests change
78
+ React.useEffect(() => {
79
+ if (selectedIndex >= requests.length && requests.length > 0) {
80
+ setSelectedIndex(requests.length - 1);
81
+ }
82
+ }, [requests.length, selectedIndex]);
83
+ // Calculate layout
84
+ const listWidth = Math.floor(columns * 0.4);
85
+ const contentHeight = rows - 3; // Leave room for status bar
86
+ // Loading state
87
+ if (isLoading && requests.length === 0) {
88
+ return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsx(Box, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: _jsx(Text, { children: "Loading..." }) }), _jsx(StatusBar, {})] }));
89
+ }
90
+ // Error state
91
+ if (error) {
92
+ return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsx(Box, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }), _jsx(StatusBar, { message: "Press 'q' to quit, 'r' to retry" })] }));
93
+ }
94
+ return (_jsxs(Box, { flexDirection: "column", height: rows, children: [_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "htpx" }), label && (_jsxs(_Fragment, { children: [_jsx(Text, { children: " \u2502 " }), _jsx(Text, { dimColor: true, children: "label: " }), _jsx(Text, { color: "yellow", children: label })] }))] }), _jsxs(Box, { flexDirection: "row", flexGrow: 1, children: [_jsx(RequestList, { requests: requests, selectedIndex: selectedIndex, isActive: activePanel === "list", width: listWidth, height: contentHeight }), _jsx(RequestDetails, { request: selectedRequest, isActive: activePanel === "details", height: contentHeight })] }), _jsx(StatusBar, { message: statusMessage })] }));
95
+ }
96
+ //# sourceMappingURL=App.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"App.js","sourceRoot":"","sources":["../../../src/cli/tui/App.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Display HTTP body with JSON pretty-printing.
3
+ */
4
+ import React from "react";
5
+ interface BodyViewProps {
6
+ title: string;
7
+ body: Buffer | undefined;
8
+ contentType?: string;
9
+ maxLines?: number;
10
+ scrollOffset?: number;
11
+ }
12
+ export declare function BodyView({ title, body, contentType, maxLines, scrollOffset, }: BodyViewProps): React.ReactElement;
13
+ export {};
14
+ //# sourceMappingURL=BodyView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BodyView.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/components/BodyView.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAIvC,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgCD,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,YAAgB,GACjB,EAAE,aAAa,GAAG,KAAK,CAAC,YAAY,CA0BpC"}
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Display HTTP body with JSON pretty-printing.
4
+ */
5
+ import { useMemo } from "react";
6
+ import { Box, Text } from "ink";
7
+ import { formatSize } from "../utils/formatters.js";
8
+ /**
9
+ * Attempt to parse and format JSON body.
10
+ */
11
+ function formatBody(body, contentType) {
12
+ if (!body || body.length === 0) {
13
+ return ["(empty)"];
14
+ }
15
+ const bodyStr = body.toString("utf-8");
16
+ // Try JSON formatting if content type suggests JSON or body looks like JSON
17
+ const isJson = contentType?.includes("application/json") ||
18
+ bodyStr.trimStart().startsWith("{") ||
19
+ bodyStr.trimStart().startsWith("[");
20
+ if (isJson) {
21
+ try {
22
+ const parsed = JSON.parse(bodyStr);
23
+ const formatted = JSON.stringify(parsed, null, 2);
24
+ return formatted.split("\n");
25
+ }
26
+ catch {
27
+ // Not valid JSON, show as-is
28
+ }
29
+ }
30
+ // For non-JSON or invalid JSON, show as-is with line breaks
31
+ return bodyStr.split("\n");
32
+ }
33
+ export function BodyView({ title, body, contentType, maxLines, scrollOffset = 0, }) {
34
+ const lines = useMemo(() => formatBody(body, contentType), [body, contentType]);
35
+ const visibleLines = maxLines !== undefined ? lines.slice(scrollOffset, scrollOffset + maxLines) : lines;
36
+ const sizeStr = body ? formatSize(body.length) : "-";
37
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "yellow", children: title }), _jsxs(Text, { dimColor: true, children: [" (", sizeStr, ")"] })] }), visibleLines.map((line, index) => (_jsx(Text, { wrap: "truncate", children: line }, scrollOffset + index))), maxLines !== undefined && lines.length > maxLines + scrollOffset && (_jsxs(Text, { dimColor: true, children: ["... ", lines.length - maxLines - scrollOffset, " more lines"] }))] }));
38
+ }
39
+ //# sourceMappingURL=BodyView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BodyView.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/BodyView.tsx"],"names":[],"mappings":";AAAA;;GAEG;AAEH,OAAc,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAUpD;;GAEG;AACH,SAAS,UAAU,CAAC,IAAwB,EAAE,WAAoB;IAChE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,SAAS,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEvC,4EAA4E;IAC5E,MAAM,MAAM,GACV,WAAW,EAAE,QAAQ,CAAC,kBAAkB,CAAC;QACzC,OAAO,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QACnC,OAAO,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAEtC,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAC;YAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAClD,OAAO,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,6BAA6B;QAC/B,CAAC;IACH,CAAC;IAED,4DAA4D;IAC5D,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EACvB,KAAK,EACL,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,YAAY,GAAG,CAAC,GACF;IACd,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;IAEhF,MAAM,YAAY,GAChB,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAEtF,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAErD,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,QAAQ,YACtB,KAAK,GACD,EACP,MAAC,IAAI,IAAC,QAAQ,yBAAI,OAAO,SAAS,IAC9B,EACL,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CACjC,KAAC,IAAI,IAA4B,IAAI,EAAC,UAAU,YAC7C,IAAI,IADI,YAAY,GAAG,KAAK,CAExB,CACR,CAAC,EACD,QAAQ,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ,GAAG,YAAY,IAAI,CACnE,MAAC,IAAI,IAAC,QAAQ,2BAAM,KAAK,CAAC,MAAM,GAAG,QAAQ,GAAG,YAAY,mBAAmB,CAC9E,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Display HTTP headers in a formatted view.
3
+ */
4
+ import React from "react";
5
+ interface HeadersViewProps {
6
+ title: string;
7
+ headers: Record<string, string> | undefined;
8
+ maxLines?: number;
9
+ scrollOffset?: number;
10
+ }
11
+ export declare function HeadersView({ title, headers, maxLines, scrollOffset, }: HeadersViewProps): React.ReactElement;
12
+ export {};
13
+ //# sourceMappingURL=HeadersView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeadersView.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/components/HeadersView.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,OAAO,EACP,QAAQ,EACR,YAAgB,GACjB,EAAE,gBAAgB,GAAG,KAAK,CAAC,YAAY,CA2BvC"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ export function HeadersView({ title, headers, maxLines, scrollOffset = 0, }) {
4
+ const entries = headers ? Object.entries(headers) : [];
5
+ const visibleEntries = maxLines !== undefined ? entries.slice(scrollOffset, scrollOffset + maxLines) : entries;
6
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: "yellow", children: title }), entries.length === 0 ? (_jsx(Text, { dimColor: true, children: "No headers" })) : (visibleEntries.map(([name, value]) => (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: name }), _jsx(Text, { children: ": " }), _jsx(Text, { children: value })] }, name)))), maxLines !== undefined && entries.length > maxLines && (_jsxs(Text, { dimColor: true, children: ["... and ", entries.length - maxLines, " more"] }))] }));
7
+ }
8
+ //# sourceMappingURL=HeadersView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeadersView.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/HeadersView.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAShC,MAAM,UAAU,WAAW,CAAC,EAC1B,KAAK,EACL,OAAO,EACP,QAAQ,EACR,YAAY,GAAG,CAAC,GACC;IACjB,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEvD,MAAM,cAAc,GAClB,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,EAAE,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE1F,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,QAAQ,YACtB,KAAK,GACD,EACN,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACtB,KAAC,IAAI,IAAC,QAAQ,iCAAkB,CACjC,CAAC,CAAC,CAAC,CACF,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CACpC,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,IAAI,GAAQ,EAChC,KAAC,IAAI,qBAAU,EACf,KAAC,IAAI,cAAE,KAAK,GAAQ,KAHZ,IAAI,CAIR,CACP,CAAC,CACH,EACA,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,QAAQ,IAAI,CACtD,MAAC,IAAI,IAAC,QAAQ,+BAAU,OAAO,CAAC,MAAM,GAAG,QAAQ,aAAa,CAC/D,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Right panel: detailed view of the selected request.
3
+ */
4
+ import React from "react";
5
+ import type { CapturedRequest } from "../../../shared/types.js";
6
+ interface RequestDetailsProps {
7
+ request: CapturedRequest | undefined;
8
+ isActive: boolean;
9
+ height: number;
10
+ }
11
+ export declare function RequestDetails({ request, isActive, height, }: RequestDetailsProps): React.ReactElement;
12
+ export {};
13
+ //# sourceMappingURL=RequestDetails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestDetails.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/components/RequestDetails.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAKhE,UAAU,mBAAmB;IAC3B,OAAO,EAAE,eAAe,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,QAAQ,EACR,MAAM,GACP,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CA2G1C"}
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { HeadersView } from "./HeadersView.js";
4
+ import { BodyView } from "./BodyView.js";
5
+ import { formatRelativeTime, formatDuration } from "../utils/formatters.js";
6
+ export function RequestDetails({ request, isActive, height, }) {
7
+ const borderColour = isActive ? "cyan" : "gray";
8
+ if (!request) {
9
+ return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, height: height, borderStyle: "single", borderColor: borderColour, paddingX: 1, children: [_jsx(Text, { bold: true, color: isActive ? "cyan" : "white", children: "Details" }), _jsx(Box, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: "Select a request to view details" }) })] }));
10
+ }
11
+ // Calculate how much space we have for each section
12
+ const headerHeight = 6; // URL line + timing + separators
13
+ const availableHeight = Math.max(8, height - headerHeight);
14
+ const sectionHeight = Math.floor(availableHeight / 4);
15
+ const reqContentType = request.requestHeaders["content-type"];
16
+ const resContentType = request.responseHeaders?.["content-type"];
17
+ return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, height: height, borderStyle: "single", borderColor: borderColour, paddingX: 1, overflowY: "hidden", children: [_jsx(Text, { bold: true, color: isActive ? "cyan" : "white", children: "Details" }), _jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: "green", bold: true, children: request.method }), _jsx(Text, { children: " " }), _jsx(Text, { children: request.url })] }), _jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { dimColor: true, children: "Status: " }), _jsx(Text, { color: request.responseStatus && request.responseStatus < 400 ? "green" : "red", children: request.responseStatus ?? "pending" }), _jsx(Text, { dimColor: true, children: " \u2502 Duration: " }), _jsx(Text, { children: formatDuration(request.durationMs) }), _jsx(Text, { dimColor: true, children: " \u2502 " }), _jsx(Text, { dimColor: true, children: formatRelativeTime(request.timestamp) })] }), _jsx(Box, { marginBottom: 1, children: _jsx(HeadersView, { title: "Request Headers", headers: request.requestHeaders, maxLines: sectionHeight }) }), request.requestBody && request.requestBody.length > 0 && (_jsx(Box, { marginBottom: 1, children: _jsx(BodyView, { title: "Request Body", body: request.requestBody, contentType: reqContentType, maxLines: sectionHeight }) })), request.responseHeaders && (_jsx(Box, { marginBottom: 1, children: _jsx(HeadersView, { title: "Response Headers", headers: request.responseHeaders, maxLines: sectionHeight }) })), request.responseBody && request.responseBody.length > 0 && (_jsx(Box, { marginBottom: 1, children: _jsx(BodyView, { title: "Response Body", body: request.responseBody, contentType: resContentType, maxLines: sectionHeight }) }))] }));
18
+ }
19
+ //# sourceMappingURL=RequestDetails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestDetails.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/RequestDetails.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Left panel: scrollable list of captured requests.
3
+ */
4
+ import React from "react";
5
+ import type { CapturedRequest } from "../../../shared/types.js";
6
+ interface RequestListProps {
7
+ requests: CapturedRequest[];
8
+ selectedIndex: number;
9
+ isActive: boolean;
10
+ width: number;
11
+ height: number;
12
+ }
13
+ export declare function RequestList({ requests, selectedIndex, isActive, width, height, }: RequestListProps): React.ReactElement;
14
+ export {};
15
+ //# sourceMappingURL=RequestList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestList.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/components/RequestList.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGhE,UAAU,gBAAgB;IACxB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,KAAK,EACL,MAAM,GACP,EAAE,gBAAgB,GAAG,KAAK,CAAC,YAAY,CAqDvC"}
@@ -0,0 +1,17 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { RequestListItem } from "./RequestListItem.js";
4
+ export function RequestList({ requests, selectedIndex, isActive, width, height, }) {
5
+ // Calculate visible window (accounting for border and header)
6
+ const visibleHeight = Math.max(1, height - 3); // Border + header row
7
+ const halfWindow = Math.floor(visibleHeight / 2);
8
+ // Calculate scroll offset to keep selection centered
9
+ let scrollOffset = 0;
10
+ if (requests.length > visibleHeight) {
11
+ scrollOffset = Math.max(0, Math.min(selectedIndex - halfWindow, requests.length - visibleHeight));
12
+ }
13
+ const visibleRequests = requests.slice(scrollOffset, scrollOffset + visibleHeight);
14
+ const borderColour = isActive ? "cyan" : "gray";
15
+ return (_jsxs(Box, { flexDirection: "column", width: width, height: height, borderStyle: "single", borderColor: borderColour, children: [_jsxs(Box, { paddingX: 1, children: [_jsxs(Text, { bold: true, color: isActive ? "cyan" : "white", children: ["Requests (", requests.length, ")"] }), requests.length > visibleHeight && (_jsxs(Text, { dimColor: true, children: [" ", "[", scrollOffset + 1, "-", Math.min(scrollOffset + visibleHeight, requests.length), "]"] }))] }), requests.length === 0 ? (_jsx(Box, { paddingX: 1, paddingY: 1, children: _jsx(Text, { dimColor: true, children: "No requests captured yet" }) })) : (_jsx(Box, { flexDirection: "column", paddingX: 1, children: visibleRequests.map((request, index) => (_jsx(RequestListItem, { request: request, isSelected: scrollOffset + index === selectedIndex, width: width - 4 }, request.id))) }))] }));
16
+ }
17
+ //# sourceMappingURL=RequestList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestList.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/RequestList.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAUvD,MAAM,UAAU,WAAW,CAAC,EAC1B,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,KAAK,EACL,MAAM,GACW;IACjB,8DAA8D;IAC9D,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,sBAAsB;IACrE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;IAEjD,qDAAqD;IACrD,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,QAAQ,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;QACpC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,UAAU,EAAE,QAAQ,CAAC,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC;IACpG,CAAC;IAED,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,YAAY,GAAG,aAAa,CAAC,CAAC;IAEnF,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAEhD,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,WAAW,EAAC,QAAQ,EACpB,WAAW,EAAE,YAAY,aAEzB,MAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,aACd,MAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,2BAChC,QAAQ,CAAC,MAAM,SACrB,EACN,QAAQ,CAAC,MAAM,GAAG,aAAa,IAAI,CAClC,MAAC,IAAI,IAAC,QAAQ,mBACX,GAAG,OACF,YAAY,GAAG,CAAC,OAAG,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,SACvE,CACR,IACG,EAEL,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACvB,KAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,YAC3B,KAAC,IAAI,IAAC,QAAQ,+CAAgC,GAC1C,CACP,CAAC,CAAC,CAAC,CACF,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,YACpC,eAAe,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CACvC,KAAC,eAAe,IAEd,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,YAAY,GAAG,KAAK,KAAK,aAAa,EAClD,KAAK,EAAE,KAAK,GAAG,CAAC,IAHX,OAAO,CAAC,EAAE,CAIf,CACH,CAAC,GACE,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Single request row in the request list.
3
+ */
4
+ import React from "react";
5
+ import type { CapturedRequest } from "../../../shared/types.js";
6
+ interface RequestListItemProps {
7
+ request: CapturedRequest;
8
+ isSelected: boolean;
9
+ width: number;
10
+ }
11
+ export declare function RequestListItem({ request, isSelected, width, }: RequestListItemProps): React.ReactElement;
12
+ export {};
13
+ //# sourceMappingURL=RequestListItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestListItem.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/components/RequestListItem.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGhE,UAAU,oBAAoB;IAC5B,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAyCD,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,UAAU,EACV,KAAK,GACN,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,CA0B3C"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { formatMethod, formatDuration, truncate } from "../utils/formatters.js";
4
+ /**
5
+ * Get colour for HTTP status code.
6
+ */
7
+ function getStatusColour(status) {
8
+ if (status === undefined) {
9
+ return "gray";
10
+ }
11
+ if (status >= 200 && status < 300) {
12
+ return "green";
13
+ }
14
+ if (status >= 300 && status < 400) {
15
+ return "yellow";
16
+ }
17
+ if (status >= 400) {
18
+ return "red";
19
+ }
20
+ return "white";
21
+ }
22
+ /**
23
+ * Get colour for HTTP method.
24
+ */
25
+ function getMethodColour(method) {
26
+ switch (method.toUpperCase()) {
27
+ case "GET":
28
+ return "green";
29
+ case "POST":
30
+ return "blue";
31
+ case "PUT":
32
+ return "yellow";
33
+ case "PATCH":
34
+ return "yellow";
35
+ case "DELETE":
36
+ return "red";
37
+ default:
38
+ return "white";
39
+ }
40
+ }
41
+ export function RequestListItem({ request, isSelected, width, }) {
42
+ const methodWidth = 7;
43
+ const statusWidth = 4;
44
+ const durationWidth = 8;
45
+ const separatorsWidth = 3; // Spaces between columns
46
+ // Calculate remaining width for path
47
+ const pathWidth = Math.max(10, width - methodWidth - statusWidth - durationWidth - separatorsWidth);
48
+ const displayPath = truncate(request.path, pathWidth);
49
+ const statusText = request.responseStatus?.toString() ?? "...";
50
+ const duration = formatDuration(request.durationMs);
51
+ return (_jsxs(Box, { children: [isSelected && _jsx(Text, { color: "cyan", children: "\u276F " }), !isSelected && _jsx(Text, { children: " " }), _jsx(Text, { color: getMethodColour(request.method), children: formatMethod(request.method) }), _jsx(Text, { children: " " }), _jsx(Text, { color: getStatusColour(request.responseStatus), children: statusText.padStart(3) }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: !isSelected, children: displayPath }), _jsx(Box, { flexGrow: 1 }), _jsx(Text, { dimColor: true, children: duration.padStart(durationWidth) })] }));
52
+ }
53
+ //# sourceMappingURL=RequestListItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestListItem.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/RequestListItem.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAQhF;;GAEG;AACH,SAAS,eAAe,CAAC,MAA0B;IACjD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QAClC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QAClC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,QAAQ,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7B,KAAK,KAAK;YACR,OAAO,OAAO,CAAC;QACjB,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,KAAK;YACR,OAAO,QAAQ,CAAC;QAClB,KAAK,OAAO;YACV,OAAO,QAAQ,CAAC;QAClB,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC;QACf;YACE,OAAO,OAAO,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,EAC9B,OAAO,EACP,UAAU,EACV,KAAK,GACgB;IACrB,MAAM,WAAW,GAAG,CAAC,CAAC;IACtB,MAAM,WAAW,GAAG,CAAC,CAAC;IACtB,MAAM,aAAa,GAAG,CAAC,CAAC;IACxB,MAAM,eAAe,GAAG,CAAC,CAAC,CAAC,yBAAyB;IAEpD,qCAAqC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,aAAa,GAAG,eAAe,CAAC,CAAC;IACpG,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAEtD,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,IAAI,KAAK,CAAC;IAC/D,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAEpD,OAAO,CACL,MAAC,GAAG,eACD,UAAU,IAAI,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,wBAAU,EAC1C,CAAC,UAAU,IAAI,KAAC,IAAI,qBAAU,EAC/B,KAAC,IAAI,IAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,YAAG,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,GAAQ,EACnF,KAAC,IAAI,oBAAS,EACd,KAAC,IAAI,IAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,cAAc,CAAC,YAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAQ,EACrF,KAAC,IAAI,oBAAS,EACd,KAAC,IAAI,IAAC,QAAQ,EAAE,CAAC,UAAU,YAAG,WAAW,GAAQ,EACjD,KAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,GAAI,EACpB,KAAC,IAAI,IAAC,QAAQ,kBAAE,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAQ,IACpD,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Status bar showing keybinding hints at the bottom of the TUI.
3
+ */
4
+ import React from "react";
5
+ interface StatusBarProps {
6
+ message?: string;
7
+ }
8
+ export declare function StatusBar({ message }: StatusBarProps): React.ReactElement;
9
+ export {};
10
+ //# sourceMappingURL=StatusBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBar.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/components/StatusBar.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAiB1B,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CA2BzE"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Status bar showing keybinding hints at the bottom of the TUI.
4
+ */
5
+ import React from "react";
6
+ import { Box, Text } from "ink";
7
+ const KEY_HINTS = [
8
+ { key: "j/k", action: "navigate" },
9
+ { key: "Tab", action: "switch panel" },
10
+ { key: "c", action: "curl" },
11
+ { key: "h", action: "HAR" },
12
+ { key: "r", action: "refresh" },
13
+ { key: "q", action: "quit" },
14
+ ];
15
+ export function StatusBar({ message }) {
16
+ return (_jsx(Box, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, paddingX: 1, children: _jsx(Box, { flexGrow: 1, children: message ? (_jsx(Text, { color: "yellow", children: message })) : (KEY_HINTS.map((hint, index) => (_jsxs(React.Fragment, { children: [_jsx(Text, { color: "cyan", bold: true, children: hint.key }), _jsxs(Text, { dimColor: true, children: [" ", hint.action] }), index < KEY_HINTS.length - 1 && _jsx(Text, { children: " \u2502 " })] }, hint.key)))) }) }));
17
+ }
18
+ //# sourceMappingURL=StatusBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBar.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/StatusBar.tsx"],"names":[],"mappings":";AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAOhC,MAAM,SAAS,GAAc;IAC3B,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE;IAClC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE;IACtC,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE;IAC5B,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE;IAC3B,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE;IAC/B,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE;CAC7B,CAAC;AAMF,MAAM,UAAU,SAAS,CAAC,EAAE,OAAO,EAAkB;IACnD,OAAO,CACL,KAAC,GAAG,IACF,WAAW,EAAC,QAAQ,EACpB,SAAS,QACT,YAAY,EAAE,KAAK,EACnB,UAAU,EAAE,KAAK,EACjB,WAAW,EAAE,KAAK,EAClB,QAAQ,EAAE,CAAC,YAEX,KAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,YACb,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,YAAE,OAAO,GAAQ,CACtC,CAAC,CAAC,CAAC,CACF,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC7B,MAAC,KAAK,CAAC,QAAQ,eACb,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,kBACpB,IAAI,CAAC,GAAG,GACJ,EACP,MAAC,IAAI,IAAC,QAAQ,wBAAG,IAAI,CAAC,MAAM,IAAQ,EACnC,KAAK,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,KAAC,IAAI,2BAAW,KAL9B,IAAI,CAAC,GAAG,CAMZ,CAClB,CAAC,CACH,GACG,GACF,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Hook for exporting captured requests to various formats.
3
+ */
4
+ import type { CapturedRequest } from "../../../shared/types.js";
5
+ interface ExportResult {
6
+ success: boolean;
7
+ message: string;
8
+ }
9
+ interface UseExportResult {
10
+ exportCurl: (request: CapturedRequest) => ExportResult;
11
+ exportHar: (requests: CapturedRequest[], filename?: string) => ExportResult;
12
+ }
13
+ /**
14
+ * Hook providing export functionality for captured requests.
15
+ */
16
+ export declare function useExport(): UseExportResult;
17
+ export {};
18
+ //# sourceMappingURL=useExport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExport.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useExport.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAIhE,UAAU,YAAY;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,eAAe;IACvB,UAAU,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,YAAY,CAAC;IACvD,SAAS,EAAE,CAAC,QAAQ,EAAE,eAAe,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,YAAY,CAAC;CAC7E;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,eAAe,CAkD3C"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Hook for exporting captured requests to various formats.
3
+ */
4
+ import { useCallback } from "react";
5
+ import * as fs from "node:fs";
6
+ import * as path from "node:path";
7
+ import { generateCurl } from "../utils/curl.js";
8
+ import { generateHarString } from "../utils/har.js";
9
+ /**
10
+ * Hook providing export functionality for captured requests.
11
+ */
12
+ export function useExport() {
13
+ /**
14
+ * Generate curl command for a request.
15
+ * Returns the curl string to be displayed/copied.
16
+ */
17
+ const exportCurl = useCallback((request) => {
18
+ try {
19
+ const curl = generateCurl(request);
20
+ return {
21
+ success: true,
22
+ message: curl,
23
+ };
24
+ }
25
+ catch (err) {
26
+ return {
27
+ success: false,
28
+ message: err instanceof Error ? err.message : "Failed to generate curl",
29
+ };
30
+ }
31
+ }, []);
32
+ /**
33
+ * Export requests to HAR file.
34
+ */
35
+ const exportHar = useCallback((requests, filename) => {
36
+ try {
37
+ const harFilename = filename ?? `htpx-export-${Date.now()}.har`;
38
+ const harPath = path.resolve(process.cwd(), harFilename);
39
+ const harContent = generateHarString(requests);
40
+ fs.writeFileSync(harPath, harContent, "utf-8");
41
+ return {
42
+ success: true,
43
+ message: `Exported ${requests.length} request(s) to ${harPath}`,
44
+ };
45
+ }
46
+ catch (err) {
47
+ return {
48
+ success: false,
49
+ message: err instanceof Error ? err.message : "Failed to export HAR",
50
+ };
51
+ }
52
+ }, []);
53
+ return {
54
+ exportCurl,
55
+ exportHar,
56
+ };
57
+ }
58
+ //# sourceMappingURL=useExport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExport.js","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useExport.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAYpD;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB;;;OAGG;IACH,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,OAAwB,EAAgB,EAAE;QACxE,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YACnC,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB;aACxE,CAAC;QACJ,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP;;OAEG;IACH,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,QAA2B,EAAE,QAAiB,EAAgB,EAAE;QAC/D,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,QAAQ,IAAI,eAAe,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;YAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;YACzD,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAE/C,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;YAE/C,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,YAAY,QAAQ,CAAC,MAAM,kBAAkB,OAAO,EAAE;aAChE,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB;aACrE,CAAC;QACJ,CAAC;IACH,CAAC,EACD,EAAE,CACH,CAAC;IAEF,OAAO;QACL,UAAU;QACV,SAAS;KACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Hook for fetching and polling captured requests from the daemon.
3
+ */
4
+ import type { CapturedRequest } from "../../../shared/types.js";
5
+ interface UseRequestsOptions {
6
+ label?: string;
7
+ pollInterval?: number;
8
+ }
9
+ interface UseRequestsResult {
10
+ requests: CapturedRequest[];
11
+ isLoading: boolean;
12
+ error: string | null;
13
+ refresh: () => Promise<void>;
14
+ }
15
+ /**
16
+ * Hook to fetch and poll for captured requests.
17
+ */
18
+ export declare function useRequests(options?: UseRequestsOptions): UseRequestsResult;
19
+ export {};
20
+ //# sourceMappingURL=useRequests.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRequests.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useRequests.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAIhE,UAAU,kBAAkB;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,iBAAiB;IACzB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,iBAAiB,CAmF/E"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Hook for fetching and polling captured requests from the daemon.
3
+ */
4
+ import { useState, useEffect, useCallback, useRef } from "react";
5
+ import { ControlClient } from "../../../daemon/control.js";
6
+ import { findProjectRoot, getHtpxPaths } from "../../../shared/project.js";
7
+ /**
8
+ * Hook to fetch and poll for captured requests.
9
+ */
10
+ export function useRequests(options = {}) {
11
+ const { label, pollInterval = 2000 } = options;
12
+ const [requests, setRequests] = useState([]);
13
+ const [isLoading, setIsLoading] = useState(true);
14
+ const [error, setError] = useState(null);
15
+ const clientRef = useRef(null);
16
+ const lastCountRef = useRef(0);
17
+ // Initialise control client
18
+ useEffect(() => {
19
+ const projectRoot = findProjectRoot();
20
+ if (!projectRoot) {
21
+ setError("Not in an htpx project. Run 'htpx init' first.");
22
+ setIsLoading(false);
23
+ return;
24
+ }
25
+ const paths = getHtpxPaths(projectRoot);
26
+ clientRef.current = new ControlClient(paths.controlSocketFile);
27
+ }, []);
28
+ // Fetch requests from daemon
29
+ const fetchRequests = useCallback(async () => {
30
+ const client = clientRef.current;
31
+ if (!client) {
32
+ return;
33
+ }
34
+ try {
35
+ // First check the count to avoid unnecessary data transfer
36
+ const count = await client.countRequests({ label });
37
+ // Only fetch full list if count changed
38
+ if (count !== lastCountRef.current || requests.length === 0) {
39
+ const newRequests = await client.listRequests({
40
+ label,
41
+ limit: 1000,
42
+ });
43
+ setRequests(newRequests);
44
+ lastCountRef.current = count;
45
+ }
46
+ setError(null);
47
+ }
48
+ catch (err) {
49
+ const message = err instanceof Error ? err.message : "Failed to connect to daemon";
50
+ if (message.includes("ENOENT") || message.includes("ECONNREFUSED")) {
51
+ setError("Daemon not running. Start with 'htpx intercept'.");
52
+ }
53
+ else {
54
+ setError(message);
55
+ }
56
+ }
57
+ finally {
58
+ setIsLoading(false);
59
+ }
60
+ }, [label, requests.length]);
61
+ // Manual refresh function
62
+ const refresh = useCallback(async () => {
63
+ setIsLoading(true);
64
+ lastCountRef.current = 0; // Force full refresh
65
+ await fetchRequests();
66
+ }, [fetchRequests]);
67
+ // Initial fetch
68
+ useEffect(() => {
69
+ void fetchRequests();
70
+ }, [fetchRequests]);
71
+ // Polling
72
+ useEffect(() => {
73
+ const interval = setInterval(() => {
74
+ void fetchRequests();
75
+ }, pollInterval);
76
+ return () => clearInterval(interval);
77
+ }, [fetchRequests, pollInterval]);
78
+ return {
79
+ requests,
80
+ isLoading,
81
+ error,
82
+ refresh,
83
+ };
84
+ }
85
+ //# sourceMappingURL=useRequests.js.map