procsi 0.2.6

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 (296) hide show
  1. package/LICENSE +665 -0
  2. package/README.md +587 -0
  3. package/dist/cli/commands/clear.d.ts +3 -0
  4. package/dist/cli/commands/clear.d.ts.map +1 -0
  5. package/dist/cli/commands/clear.js +30 -0
  6. package/dist/cli/commands/clear.js.map +1 -0
  7. package/dist/cli/commands/daemon.d.ts +3 -0
  8. package/dist/cli/commands/daemon.d.ts.map +1 -0
  9. package/dist/cli/commands/daemon.js +59 -0
  10. package/dist/cli/commands/daemon.js.map +1 -0
  11. package/dist/cli/commands/debug-dump.d.ts +27 -0
  12. package/dist/cli/commands/debug-dump.d.ts.map +1 -0
  13. package/dist/cli/commands/debug-dump.js +102 -0
  14. package/dist/cli/commands/debug-dump.js.map +1 -0
  15. package/dist/cli/commands/helpers.d.ts +18 -0
  16. package/dist/cli/commands/helpers.d.ts.map +1 -0
  17. package/dist/cli/commands/helpers.js +34 -0
  18. package/dist/cli/commands/helpers.js.map +1 -0
  19. package/dist/cli/commands/init.d.ts +9 -0
  20. package/dist/cli/commands/init.d.ts.map +1 -0
  21. package/dist/cli/commands/init.js +28 -0
  22. package/dist/cli/commands/init.js.map +1 -0
  23. package/dist/cli/commands/intercept.d.ts +9 -0
  24. package/dist/cli/commands/intercept.d.ts.map +1 -0
  25. package/dist/cli/commands/intercept.js +121 -0
  26. package/dist/cli/commands/intercept.js.map +1 -0
  27. package/dist/cli/commands/interceptors.d.ts +3 -0
  28. package/dist/cli/commands/interceptors.d.ts.map +1 -0
  29. package/dist/cli/commands/interceptors.js +163 -0
  30. package/dist/cli/commands/interceptors.js.map +1 -0
  31. package/dist/cli/commands/mcp.d.ts +3 -0
  32. package/dist/cli/commands/mcp.d.ts.map +1 -0
  33. package/dist/cli/commands/mcp.js +24 -0
  34. package/dist/cli/commands/mcp.js.map +1 -0
  35. package/dist/cli/commands/off.d.ts +8 -0
  36. package/dist/cli/commands/off.d.ts.map +1 -0
  37. package/dist/cli/commands/off.js +34 -0
  38. package/dist/cli/commands/off.js.map +1 -0
  39. package/dist/cli/commands/on.d.ts +9 -0
  40. package/dist/cli/commands/on.d.ts.map +1 -0
  41. package/dist/cli/commands/on.js +121 -0
  42. package/dist/cli/commands/on.js.map +1 -0
  43. package/dist/cli/commands/project.d.ts +3 -0
  44. package/dist/cli/commands/project.d.ts.map +1 -0
  45. package/dist/cli/commands/project.js +15 -0
  46. package/dist/cli/commands/project.js.map +1 -0
  47. package/dist/cli/commands/restart.d.ts +3 -0
  48. package/dist/cli/commands/restart.d.ts.map +1 -0
  49. package/dist/cli/commands/restart.js +35 -0
  50. package/dist/cli/commands/restart.js.map +1 -0
  51. package/dist/cli/commands/status.d.ts +3 -0
  52. package/dist/cli/commands/status.d.ts.map +1 -0
  53. package/dist/cli/commands/status.js +66 -0
  54. package/dist/cli/commands/status.js.map +1 -0
  55. package/dist/cli/commands/stop.d.ts +3 -0
  56. package/dist/cli/commands/stop.d.ts.map +1 -0
  57. package/dist/cli/commands/stop.js +24 -0
  58. package/dist/cli/commands/stop.js.map +1 -0
  59. package/dist/cli/commands/tui.d.ts +3 -0
  60. package/dist/cli/commands/tui.d.ts.map +1 -0
  61. package/dist/cli/commands/tui.js +36 -0
  62. package/dist/cli/commands/tui.js.map +1 -0
  63. package/dist/cli/commands/vars.d.ts +36 -0
  64. package/dist/cli/commands/vars.d.ts.map +1 -0
  65. package/dist/cli/commands/vars.js +207 -0
  66. package/dist/cli/commands/vars.js.map +1 -0
  67. package/dist/cli/index.d.ts +3 -0
  68. package/dist/cli/index.d.ts.map +1 -0
  69. package/dist/cli/index.js +37 -0
  70. package/dist/cli/index.js.map +1 -0
  71. package/dist/cli/tui/App.d.ts +15 -0
  72. package/dist/cli/tui/App.d.ts.map +1 -0
  73. package/dist/cli/tui/App.js +544 -0
  74. package/dist/cli/tui/App.js.map +1 -0
  75. package/dist/cli/tui/components/AccordionContent.d.ts +28 -0
  76. package/dist/cli/tui/components/AccordionContent.d.ts.map +1 -0
  77. package/dist/cli/tui/components/AccordionContent.js +87 -0
  78. package/dist/cli/tui/components/AccordionContent.js.map +1 -0
  79. package/dist/cli/tui/components/AccordionPanel.d.ts +38 -0
  80. package/dist/cli/tui/components/AccordionPanel.d.ts.map +1 -0
  81. package/dist/cli/tui/components/AccordionPanel.js +110 -0
  82. package/dist/cli/tui/components/AccordionPanel.js.map +1 -0
  83. package/dist/cli/tui/components/AccordionSection.d.ts +32 -0
  84. package/dist/cli/tui/components/AccordionSection.d.ts.map +1 -0
  85. package/dist/cli/tui/components/AccordionSection.js +41 -0
  86. package/dist/cli/tui/components/AccordionSection.js.map +1 -0
  87. package/dist/cli/tui/components/BodyView.d.ts +14 -0
  88. package/dist/cli/tui/components/BodyView.d.ts.map +1 -0
  89. package/dist/cli/tui/components/BodyView.js +39 -0
  90. package/dist/cli/tui/components/BodyView.js.map +1 -0
  91. package/dist/cli/tui/components/ExportModal.d.ts +34 -0
  92. package/dist/cli/tui/components/ExportModal.d.ts.map +1 -0
  93. package/dist/cli/tui/components/ExportModal.js +109 -0
  94. package/dist/cli/tui/components/ExportModal.js.map +1 -0
  95. package/dist/cli/tui/components/FilterBar.d.ts +21 -0
  96. package/dist/cli/tui/components/FilterBar.d.ts.map +1 -0
  97. package/dist/cli/tui/components/FilterBar.js +155 -0
  98. package/dist/cli/tui/components/FilterBar.js.map +1 -0
  99. package/dist/cli/tui/components/HeadersView.d.ts +13 -0
  100. package/dist/cli/tui/components/HeadersView.d.ts.map +1 -0
  101. package/dist/cli/tui/components/HeadersView.js +8 -0
  102. package/dist/cli/tui/components/HeadersView.js.map +1 -0
  103. package/dist/cli/tui/components/HelpModal.d.ts +13 -0
  104. package/dist/cli/tui/components/HelpModal.d.ts.map +1 -0
  105. package/dist/cli/tui/components/HelpModal.js +78 -0
  106. package/dist/cli/tui/components/HelpModal.js.map +1 -0
  107. package/dist/cli/tui/components/HintContent.d.ts +25 -0
  108. package/dist/cli/tui/components/HintContent.d.ts.map +1 -0
  109. package/dist/cli/tui/components/HintContent.js +44 -0
  110. package/dist/cli/tui/components/HintContent.js.map +1 -0
  111. package/dist/cli/tui/components/InfoModal.d.ts +15 -0
  112. package/dist/cli/tui/components/InfoModal.d.ts.map +1 -0
  113. package/dist/cli/tui/components/InfoModal.js +17 -0
  114. package/dist/cli/tui/components/InfoModal.js.map +1 -0
  115. package/dist/cli/tui/components/JsonExplorerModal.d.ts +24 -0
  116. package/dist/cli/tui/components/JsonExplorerModal.d.ts.map +1 -0
  117. package/dist/cli/tui/components/JsonExplorerModal.js +311 -0
  118. package/dist/cli/tui/components/JsonExplorerModal.js.map +1 -0
  119. package/dist/cli/tui/components/Modal.d.ts +26 -0
  120. package/dist/cli/tui/components/Modal.d.ts.map +1 -0
  121. package/dist/cli/tui/components/Modal.js +15 -0
  122. package/dist/cli/tui/components/Modal.js.map +1 -0
  123. package/dist/cli/tui/components/Panel.d.ts +19 -0
  124. package/dist/cli/tui/components/Panel.d.ts.map +1 -0
  125. package/dist/cli/tui/components/Panel.js +37 -0
  126. package/dist/cli/tui/components/Panel.js.map +1 -0
  127. package/dist/cli/tui/components/RequestDetails.d.ts +16 -0
  128. package/dist/cli/tui/components/RequestDetails.d.ts.map +1 -0
  129. package/dist/cli/tui/components/RequestDetails.js +23 -0
  130. package/dist/cli/tui/components/RequestDetails.js.map +1 -0
  131. package/dist/cli/tui/components/RequestList.d.ts +21 -0
  132. package/dist/cli/tui/components/RequestList.d.ts.map +1 -0
  133. package/dist/cli/tui/components/RequestList.js +30 -0
  134. package/dist/cli/tui/components/RequestList.js.map +1 -0
  135. package/dist/cli/tui/components/RequestListItem.d.ts +36 -0
  136. package/dist/cli/tui/components/RequestListItem.d.ts.map +1 -0
  137. package/dist/cli/tui/components/RequestListItem.js +130 -0
  138. package/dist/cli/tui/components/RequestListItem.js.map +1 -0
  139. package/dist/cli/tui/components/SaveModal.d.ts +30 -0
  140. package/dist/cli/tui/components/SaveModal.d.ts.map +1 -0
  141. package/dist/cli/tui/components/SaveModal.js +95 -0
  142. package/dist/cli/tui/components/SaveModal.js.map +1 -0
  143. package/dist/cli/tui/components/StatusBar.d.ts +39 -0
  144. package/dist/cli/tui/components/StatusBar.d.ts.map +1 -0
  145. package/dist/cli/tui/components/StatusBar.js +53 -0
  146. package/dist/cli/tui/components/StatusBar.js.map +1 -0
  147. package/dist/cli/tui/components/TextViewerModal.d.ts +19 -0
  148. package/dist/cli/tui/components/TextViewerModal.d.ts.map +1 -0
  149. package/dist/cli/tui/components/TextViewerModal.js +227 -0
  150. package/dist/cli/tui/components/TextViewerModal.js.map +1 -0
  151. package/dist/cli/tui/hooks/useBodyExport.d.ts +26 -0
  152. package/dist/cli/tui/hooks/useBodyExport.d.ts.map +1 -0
  153. package/dist/cli/tui/hooks/useBodyExport.js +173 -0
  154. package/dist/cli/tui/hooks/useBodyExport.js.map +1 -0
  155. package/dist/cli/tui/hooks/useExport.d.ts +29 -0
  156. package/dist/cli/tui/hooks/useExport.d.ts.map +1 -0
  157. package/dist/cli/tui/hooks/useExport.js +64 -0
  158. package/dist/cli/tui/hooks/useExport.js.map +1 -0
  159. package/dist/cli/tui/hooks/useRequests.d.ts +26 -0
  160. package/dist/cli/tui/hooks/useRequests.d.ts.map +1 -0
  161. package/dist/cli/tui/hooks/useRequests.js +131 -0
  162. package/dist/cli/tui/hooks/useRequests.js.map +1 -0
  163. package/dist/cli/tui/hooks/useSaveBinary.d.ts +26 -0
  164. package/dist/cli/tui/hooks/useSaveBinary.d.ts.map +1 -0
  165. package/dist/cli/tui/hooks/useSaveBinary.js +165 -0
  166. package/dist/cli/tui/hooks/useSaveBinary.js.map +1 -0
  167. package/dist/cli/tui/hooks/useSpinner.d.ts +5 -0
  168. package/dist/cli/tui/hooks/useSpinner.d.ts.map +1 -0
  169. package/dist/cli/tui/hooks/useSpinner.js +25 -0
  170. package/dist/cli/tui/hooks/useSpinner.js.map +1 -0
  171. package/dist/cli/tui/hooks/useStdoutDimensions.d.ts +11 -0
  172. package/dist/cli/tui/hooks/useStdoutDimensions.d.ts.map +1 -0
  173. package/dist/cli/tui/hooks/useStdoutDimensions.js +29 -0
  174. package/dist/cli/tui/hooks/useStdoutDimensions.js.map +1 -0
  175. package/dist/cli/tui/utils/binary.d.ts +24 -0
  176. package/dist/cli/tui/utils/binary.d.ts.map +1 -0
  177. package/dist/cli/tui/utils/binary.js +152 -0
  178. package/dist/cli/tui/utils/binary.js.map +1 -0
  179. package/dist/cli/tui/utils/clipboard.d.ts +9 -0
  180. package/dist/cli/tui/utils/clipboard.d.ts.map +1 -0
  181. package/dist/cli/tui/utils/clipboard.js +58 -0
  182. package/dist/cli/tui/utils/clipboard.js.map +1 -0
  183. package/dist/cli/tui/utils/content-type.d.ts +8 -0
  184. package/dist/cli/tui/utils/content-type.d.ts.map +1 -0
  185. package/dist/cli/tui/utils/content-type.js +10 -0
  186. package/dist/cli/tui/utils/content-type.js.map +1 -0
  187. package/dist/cli/tui/utils/curl.d.ts +9 -0
  188. package/dist/cli/tui/utils/curl.d.ts.map +1 -0
  189. package/dist/cli/tui/utils/curl.js +54 -0
  190. package/dist/cli/tui/utils/curl.js.map +1 -0
  191. package/dist/cli/tui/utils/filters.d.ts +6 -0
  192. package/dist/cli/tui/utils/filters.d.ts.map +1 -0
  193. package/dist/cli/tui/utils/filters.js +13 -0
  194. package/dist/cli/tui/utils/filters.js.map +1 -0
  195. package/dist/cli/tui/utils/formatters.d.ts +49 -0
  196. package/dist/cli/tui/utils/formatters.d.ts.map +1 -0
  197. package/dist/cli/tui/utils/formatters.js +200 -0
  198. package/dist/cli/tui/utils/formatters.js.map +1 -0
  199. package/dist/cli/tui/utils/har.d.ts +75 -0
  200. package/dist/cli/tui/utils/har.d.ts.map +1 -0
  201. package/dist/cli/tui/utils/har.js +117 -0
  202. package/dist/cli/tui/utils/har.js.map +1 -0
  203. package/dist/cli/tui/utils/json-tree.d.ts +69 -0
  204. package/dist/cli/tui/utils/json-tree.d.ts.map +1 -0
  205. package/dist/cli/tui/utils/json-tree.js +339 -0
  206. package/dist/cli/tui/utils/json-tree.js.map +1 -0
  207. package/dist/cli/tui/utils/open-external.d.ts +17 -0
  208. package/dist/cli/tui/utils/open-external.d.ts.map +1 -0
  209. package/dist/cli/tui/utils/open-external.js +57 -0
  210. package/dist/cli/tui/utils/open-external.js.map +1 -0
  211. package/dist/cli/tui/utils/syntax-highlight.d.ts +16 -0
  212. package/dist/cli/tui/utils/syntax-highlight.d.ts.map +1 -0
  213. package/dist/cli/tui/utils/syntax-highlight.js +64 -0
  214. package/dist/cli/tui/utils/syntax-highlight.js.map +1 -0
  215. package/dist/daemon/control.d.ts +21 -0
  216. package/dist/daemon/control.d.ts.map +1 -0
  217. package/dist/daemon/control.js +311 -0
  218. package/dist/daemon/control.js.map +1 -0
  219. package/dist/daemon/htpx-client.d.ts +8 -0
  220. package/dist/daemon/htpx-client.d.ts.map +1 -0
  221. package/dist/daemon/htpx-client.js +25 -0
  222. package/dist/daemon/htpx-client.js.map +1 -0
  223. package/dist/daemon/index.d.ts +3 -0
  224. package/dist/daemon/index.d.ts.map +1 -0
  225. package/dist/daemon/index.js +178 -0
  226. package/dist/daemon/index.js.map +1 -0
  227. package/dist/daemon/interceptor-loader.d.ts +30 -0
  228. package/dist/daemon/interceptor-loader.d.ts.map +1 -0
  229. package/dist/daemon/interceptor-loader.js +249 -0
  230. package/dist/daemon/interceptor-loader.js.map +1 -0
  231. package/dist/daemon/interceptor-runner.d.ts +39 -0
  232. package/dist/daemon/interceptor-runner.d.ts.map +1 -0
  233. package/dist/daemon/interceptor-runner.js +312 -0
  234. package/dist/daemon/interceptor-runner.js.map +1 -0
  235. package/dist/daemon/procsi-client.d.ts +8 -0
  236. package/dist/daemon/procsi-client.d.ts.map +1 -0
  237. package/dist/daemon/procsi-client.js +25 -0
  238. package/dist/daemon/procsi-client.js.map +1 -0
  239. package/dist/daemon/proxy.d.ts +34 -0
  240. package/dist/daemon/proxy.d.ts.map +1 -0
  241. package/dist/daemon/proxy.js +213 -0
  242. package/dist/daemon/proxy.js.map +1 -0
  243. package/dist/daemon/storage.d.ts +130 -0
  244. package/dist/daemon/storage.d.ts.map +1 -0
  245. package/dist/daemon/storage.js +761 -0
  246. package/dist/daemon/storage.js.map +1 -0
  247. package/dist/interceptors.d.ts +2 -0
  248. package/dist/interceptors.d.ts.map +1 -0
  249. package/dist/interceptors.js +2 -0
  250. package/dist/interceptors.js.map +1 -0
  251. package/dist/mcp/server.d.ts +110 -0
  252. package/dist/mcp/server.d.ts.map +1 -0
  253. package/dist/mcp/server.js +806 -0
  254. package/dist/mcp/server.js.map +1 -0
  255. package/dist/overrides/node.d.ts +30 -0
  256. package/dist/overrides/node.d.ts.map +1 -0
  257. package/dist/overrides/node.js +66 -0
  258. package/dist/overrides/node.js.map +1 -0
  259. package/dist/shared/config.d.ts +21 -0
  260. package/dist/shared/config.d.ts.map +1 -0
  261. package/dist/shared/config.js +83 -0
  262. package/dist/shared/config.js.map +1 -0
  263. package/dist/shared/content-type.d.ts +64 -0
  264. package/dist/shared/content-type.d.ts.map +1 -0
  265. package/dist/shared/content-type.js +145 -0
  266. package/dist/shared/content-type.js.map +1 -0
  267. package/dist/shared/control-client.d.ts +144 -0
  268. package/dist/shared/control-client.d.ts.map +1 -0
  269. package/dist/shared/control-client.js +272 -0
  270. package/dist/shared/control-client.js.map +1 -0
  271. package/dist/shared/daemon.d.ts +33 -0
  272. package/dist/shared/daemon.d.ts.map +1 -0
  273. package/dist/shared/daemon.js +231 -0
  274. package/dist/shared/daemon.js.map +1 -0
  275. package/dist/shared/logger.d.ts +47 -0
  276. package/dist/shared/logger.d.ts.map +1 -0
  277. package/dist/shared/logger.js +200 -0
  278. package/dist/shared/logger.js.map +1 -0
  279. package/dist/shared/project.d.ts +76 -0
  280. package/dist/shared/project.d.ts.map +1 -0
  281. package/dist/shared/project.js +185 -0
  282. package/dist/shared/project.js.map +1 -0
  283. package/dist/shared/proxy-info.d.ts +10 -0
  284. package/dist/shared/proxy-info.d.ts.map +1 -0
  285. package/dist/shared/proxy-info.js +15 -0
  286. package/dist/shared/proxy-info.js.map +1 -0
  287. package/dist/shared/types.d.ts +128 -0
  288. package/dist/shared/types.d.ts.map +1 -0
  289. package/dist/shared/types.js +5 -0
  290. package/dist/shared/types.js.map +1 -0
  291. package/dist/shared/version.d.ts +5 -0
  292. package/dist/shared/version.d.ts.map +1 -0
  293. package/dist/shared/version.js +21 -0
  294. package/dist/shared/version.js.map +1 -0
  295. package/package.json +113 -0
  296. package/skills/procsi/SKILL.md +228 -0
@@ -0,0 +1,130 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Single request row in the request list.
4
+ */
5
+ import { useRef, memo } from "react";
6
+ import { Box, Text } from "ink";
7
+ import { useOnClick } from "@ink-tools/ink-mouse";
8
+ import { formatMethod, formatDuration, truncate } from "../utils/formatters.js";
9
+ /**
10
+ * Get the 2-character interception indicator and its colour.
11
+ * Returns "M " for mocked, "I " for modified, or " " for normal requests.
12
+ */
13
+ export function getInterceptionIndicator(type) {
14
+ switch (type) {
15
+ case "mocked":
16
+ return { text: "M ", colour: "magenta" };
17
+ case "modified":
18
+ return { text: "I ", colour: "cyan" };
19
+ default:
20
+ return { text: " " };
21
+ }
22
+ }
23
+ /**
24
+ * Get colour for HTTP status code.
25
+ */
26
+ export function getStatusColour(status) {
27
+ if (status === undefined) {
28
+ return "gray";
29
+ }
30
+ if (status >= 200 && status < 300) {
31
+ return "green";
32
+ }
33
+ if (status >= 300 && status < 400) {
34
+ return "yellow";
35
+ }
36
+ if (status >= 400) {
37
+ return "red";
38
+ }
39
+ return "white";
40
+ }
41
+ /**
42
+ * Get a visual indicator character for an HTTP status code.
43
+ */
44
+ export function getStatusIndicator(status) {
45
+ if (status === undefined) {
46
+ return " ";
47
+ }
48
+ if (status >= 200 && status < 300) {
49
+ return "✓";
50
+ }
51
+ if (status >= 300 && status < 400) {
52
+ return "→";
53
+ }
54
+ return "✗";
55
+ }
56
+ /**
57
+ * Get colour for HTTP method.
58
+ */
59
+ export function getMethodColour(method) {
60
+ switch (method.toUpperCase()) {
61
+ case "GET":
62
+ return "green";
63
+ case "POST":
64
+ return "blue";
65
+ case "PUT":
66
+ return "yellow";
67
+ case "PATCH":
68
+ return "yellow";
69
+ case "DELETE":
70
+ return "magenta";
71
+ default:
72
+ return "white";
73
+ }
74
+ }
75
+ /**
76
+ * Split text into segments around case-insensitive matches of a search term.
77
+ * Returns alternating [non-match, match, non-match, ...] segments.
78
+ */
79
+ function splitByMatch(text, term) {
80
+ if (!term)
81
+ return [{ text, isMatch: false }];
82
+ const segments = [];
83
+ const lowerText = text.toLowerCase();
84
+ const lowerTerm = term.toLowerCase();
85
+ let pos = 0;
86
+ while (pos < text.length) {
87
+ const matchIdx = lowerText.indexOf(lowerTerm, pos);
88
+ if (matchIdx === -1) {
89
+ segments.push({ text: text.slice(pos), isMatch: false });
90
+ break;
91
+ }
92
+ if (matchIdx > pos) {
93
+ segments.push({ text: text.slice(pos, matchIdx), isMatch: false });
94
+ }
95
+ segments.push({ text: text.slice(matchIdx, matchIdx + term.length), isMatch: true });
96
+ pos = matchIdx + term.length;
97
+ }
98
+ return segments.length > 0 ? segments : [{ text, isMatch: false }];
99
+ }
100
+ export const RequestListItem = memo(function RequestListItem({ request, isSelected, width, showFullUrl, onClick, searchTerm, }) {
101
+ const ref = useRef(null);
102
+ useOnClick(ref, () => {
103
+ if (onClick) {
104
+ onClick();
105
+ }
106
+ });
107
+ const interceptionWidth = 2; // "M " / "I " / " "
108
+ const methodWidth = 7;
109
+ const statusWidth = 6;
110
+ const durationWidth = 8;
111
+ const separatorsWidth = 3; // Spaces between columns
112
+ // Calculate remaining width for path
113
+ const pathWidth = Math.max(10, width - interceptionWidth - methodWidth - statusWidth - durationWidth - separatorsWidth);
114
+ const displayPath = truncate(showFullUrl ? request.url : request.path, pathWidth);
115
+ const paddedPath = displayPath.padEnd(pathWidth);
116
+ const statusText = request.responseStatus?.toString() ?? "...";
117
+ const statusIndicator = getStatusIndicator(request.responseStatus);
118
+ const duration = formatDuration(request.durationMs);
119
+ const indicator = isSelected ? "❯ " : " ";
120
+ const indicatorColour = isSelected ? "cyan" : undefined;
121
+ const interception = getInterceptionIndicator(request.interceptionType);
122
+ return (_jsx(Box, { ref: ref, width: width, children: _jsxs(Text, { wrap: "truncate", children: [_jsx(Text, { color: indicatorColour, children: indicator }), _jsx(Text, { color: interception.colour, children: interception.text }), _jsx(Text, { color: getMethodColour(request.method), children: formatMethod(request.method) }), _jsx(Text, { children: " " }), _jsxs(Text, { color: getStatusColour(request.responseStatus), children: [statusIndicator, statusText.padStart(3)] }), _jsx(Text, { children: " " }), searchTerm ? (_jsx(Text, { dimColor: !isSelected, children: splitByMatch(paddedPath, searchTerm).map((seg, i) => seg.isMatch ? (_jsx(Text, { color: "yellow", bold: true, children: seg.text }, i)) : (_jsx(Text, { children: seg.text }, i))) })) : (_jsx(Text, { dimColor: !isSelected, children: paddedPath })), _jsx(Text, { dimColor: true, children: duration.padStart(durationWidth) })] }) }));
123
+ }, (prevProps, nextProps) => {
124
+ return (prevProps.request === nextProps.request &&
125
+ prevProps.isSelected === nextProps.isSelected &&
126
+ prevProps.width === nextProps.width &&
127
+ prevProps.showFullUrl === nextProps.showFullUrl &&
128
+ prevProps.searchTerm === nextProps.searchTerm);
129
+ });
130
+ //# sourceMappingURL=RequestListItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestListItem.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/RequestListItem.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Full-screen save dialog for binary content.
3
+ *
4
+ * Replaces the main TUI when active (terminals don't support true overlays).
5
+ *
6
+ * Provides three options:
7
+ * [1] .htpx/exports/ - Project exports folder
8
+ * [2] ~/Downloads/ - Downloads folder
9
+ * [3] Custom path... - Text input
10
+ */
11
+ import React from "react";
12
+ export type SaveLocation = "exports" | "downloads" | "custom";
13
+ export interface SaveModalProps {
14
+ /** Filename being saved */
15
+ filename: string;
16
+ /** File size for display */
17
+ fileSize: string;
18
+ /** Screen width */
19
+ width: number;
20
+ /** Screen height */
21
+ height: number;
22
+ /** Called when user selects a location */
23
+ onSave: (location: SaveLocation, customPath?: string) => void;
24
+ /** Called when modal should close */
25
+ onClose: () => void;
26
+ /** Whether input is active (for testing) */
27
+ isActive?: boolean;
28
+ }
29
+ export declare function SaveModal({ filename, fileSize, width, height, onSave, onClose, isActive, }: SaveModalProps): React.ReactElement;
30
+ //# sourceMappingURL=SaveModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SaveModal.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/components/SaveModal.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,MAAM,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9D,qCAAqC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA8BD,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,MAAM,EACN,OAAO,EACP,QAAe,GAChB,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAoHrC"}
@@ -0,0 +1,95 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Full-screen save dialog for binary content.
4
+ *
5
+ * Replaces the main TUI when active (terminals don't support true overlays).
6
+ *
7
+ * Provides three options:
8
+ * [1] .htpx/exports/ - Project exports folder
9
+ * [2] ~/Downloads/ - Downloads folder
10
+ * [3] Custom path... - Text input
11
+ */
12
+ import { useState } from "react";
13
+ import { Box, Text, useInput } from "ink";
14
+ const OPTIONS = [
15
+ {
16
+ key: "1",
17
+ location: "exports",
18
+ label: ".htpx/exports/",
19
+ description: "Project exports folder",
20
+ },
21
+ {
22
+ key: "2",
23
+ location: "downloads",
24
+ label: "~/Downloads/",
25
+ description: "Downloads folder",
26
+ },
27
+ {
28
+ key: "3",
29
+ location: "custom",
30
+ label: "Custom path...",
31
+ description: "Enter a custom directory",
32
+ },
33
+ ];
34
+ export function SaveModal({ filename, fileSize, width, height, onSave, onClose, isActive = true, }) {
35
+ const [selectedIndex, setSelectedIndex] = useState(0);
36
+ const [showCustomInput, setShowCustomInput] = useState(false);
37
+ const [customPath, setCustomPath] = useState("");
38
+ useInput((input, key) => {
39
+ if (showCustomInput) {
40
+ // Handle custom path input
41
+ if (key.return) {
42
+ if (customPath.trim()) {
43
+ onSave("custom", customPath.trim());
44
+ }
45
+ }
46
+ else if (key.backspace || key.delete) {
47
+ setCustomPath((prev) => prev.slice(0, -1));
48
+ }
49
+ else if (key.escape) {
50
+ setShowCustomInput(false);
51
+ setCustomPath("");
52
+ }
53
+ else if (input && !key.ctrl && !key.meta) {
54
+ setCustomPath((prev) => prev + input);
55
+ }
56
+ return;
57
+ }
58
+ // Handle option selection
59
+ if (key.escape) {
60
+ onClose();
61
+ }
62
+ else if (input === "j" || key.downArrow) {
63
+ setSelectedIndex((prev) => Math.min(prev + 1, OPTIONS.length - 1));
64
+ }
65
+ else if (input === "k" || key.upArrow) {
66
+ setSelectedIndex((prev) => Math.max(prev - 1, 0));
67
+ }
68
+ else if (input === "1") {
69
+ onSave("exports");
70
+ }
71
+ else if (input === "2") {
72
+ onSave("downloads");
73
+ }
74
+ else if (input === "3") {
75
+ setShowCustomInput(true);
76
+ }
77
+ else if (key.return) {
78
+ const option = OPTIONS[selectedIndex];
79
+ if (option) {
80
+ if (option.location === "custom") {
81
+ setShowCustomInput(true);
82
+ }
83
+ else {
84
+ onSave(option.location);
85
+ }
86
+ }
87
+ }
88
+ }, { isActive });
89
+ return (_jsxs(Box, { flexDirection: "column", width: width, height: height, alignItems: "center", justifyContent: "center", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "cyan", bold: true, children: "Save Binary Content" }) }), _jsx(Box, { marginBottom: 2, children: _jsxs(Text, { dimColor: true, children: [filename, " (", fileSize, ")"] }) }), showCustomInput ? (
90
+ // Custom path input mode
91
+ _jsxs(Box, { flexDirection: "column", alignItems: "center", children: [_jsx(Text, { children: "Enter directory path:" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "> " }), _jsx(Text, { children: customPath }), _jsx(Text, { color: "cyan", children: "_" })] }), _jsx(Box, { marginTop: 2, children: _jsx(Text, { dimColor: true, children: "Enter to save, Escape to go back" }) })] })) : (
92
+ // Option selection mode
93
+ _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: "Select save location:" }) }), OPTIONS.map((option, index) => (_jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: index === selectedIndex ? "cyan" : undefined, children: index === selectedIndex ? "❯ " : " " }), _jsxs(Text, { color: "yellow", bold: true, children: ["[", option.key, "]"] }), _jsxs(Text, { color: index === selectedIndex ? "white" : "gray", children: [" ", option.label] }), _jsxs(Text, { dimColor: true, children: [" - ", option.description] })] }, option.key))), _jsx(Box, { marginTop: 2, children: _jsx(Text, { dimColor: true, children: "j/k navigate \u2502 Enter or number to select \u2502 Escape to cancel" }) })] }))] }));
94
+ }
95
+ //# sourceMappingURL=SaveModal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SaveModal.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/SaveModal.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Status bar showing keybinding hints at the bottom of the TUI.
3
+ * Hints are filtered based on the current focus/selection context.
4
+ */
5
+ import React from "react";
6
+ import { type HintItem } from "./HintContent.js";
7
+ interface StatusBarContext {
8
+ activePanel: "list" | "accordion";
9
+ hasSelection: boolean;
10
+ hasRequests: boolean;
11
+ onBodySection: boolean;
12
+ onViewableBodySection: boolean;
13
+ }
14
+ interface KeyHint extends HintItem {
15
+ visible?: (ctx: StatusBarContext) => boolean;
16
+ }
17
+ export interface StatusBarProps {
18
+ message?: string;
19
+ filterActive?: boolean;
20
+ /** When true the filter bar is open and capturing input, so main-view hints are suppressed. */
21
+ filterOpen?: boolean;
22
+ activePanel?: "list" | "accordion";
23
+ hasSelection?: boolean;
24
+ hasRequests?: boolean;
25
+ onBodySection?: boolean;
26
+ onViewableBodySection?: boolean;
27
+ /** Number of active interceptors; shown as a badge when > 0. */
28
+ interceptorCount?: number;
29
+ /** Terminal width in columns — used to constrain the hint bar. */
30
+ width?: number;
31
+ }
32
+ /**
33
+ * Returns hints visible for the given context. All new props default to true
34
+ * so the component remains backwards-compatible when no context is passed.
35
+ */
36
+ export declare function getVisibleHints({ activePanel, hasSelection, hasRequests, onBodySection, onViewableBodySection, }: Pick<StatusBarProps, "activePanel" | "hasSelection" | "hasRequests" | "onBodySection" | "onViewableBodySection">): KeyHint[];
37
+ export declare function StatusBar({ message, filterActive, filterOpen, activePanel, hasSelection, hasRequests, onBodySection, onViewableBodySection, interceptorCount, width, }: StatusBarProps): React.ReactElement;
38
+ export {};
39
+ //# 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;;;GAGG;AAEH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE9D,UAAU,gBAAgB;IACxB,WAAW,EAAE,MAAM,GAAG,WAAW,CAAC;IAClC,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED,UAAU,OAAQ,SAAQ,QAAQ;IAChC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC;CAC9C;AAmBD,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+FAA+F;IAC/F,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,WAAoB,EACpB,YAAmB,EACnB,WAAkB,EAClB,aAAoB,EACpB,qBAA6B,GAC9B,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,GAAG,cAAc,GAAG,aAAa,GAAG,eAAe,GAAG,uBAAuB,CAAC,GAAG,OAAO,EAAE,CAG9H;AAKD,wBAAgB,SAAS,CAAC,EACxB,OAAO,EACP,YAAY,EACZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,GACN,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CA0DrC"}
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Status bar showing keybinding hints at the bottom of the TUI.
4
+ * Hints are filtered based on the current focus/selection context.
5
+ */
6
+ import { useMemo } from "react";
7
+ import { Box, Text } from "ink";
8
+ import { HintContent } from "./HintContent.js";
9
+ const KEY_HINTS = [
10
+ { key: "j/k/g/G", action: "nav" },
11
+ { key: "^f/^b", action: "page", visible: (ctx) => ctx.activePanel === "list" },
12
+ { key: "Tab", action: "panel" },
13
+ { key: "1-5", action: "section" },
14
+ { key: "Enter", action: "view", visible: (ctx) => ctx.onViewableBodySection },
15
+ { key: "c", action: "curl", visible: (ctx) => ctx.hasSelection },
16
+ { key: "H", action: "HAR", visible: (ctx) => ctx.hasRequests },
17
+ { key: "y", action: "yank", visible: (ctx) => ctx.onBodySection },
18
+ { key: "s", action: "export", visible: (ctx) => ctx.onBodySection },
19
+ { key: "u", action: "URL" },
20
+ { key: "/", action: "filter" },
21
+ { key: "i", action: "info" },
22
+ { key: "?", action: "help" },
23
+ { key: "q", action: "quit" },
24
+ ];
25
+ /**
26
+ * Returns hints visible for the given context. All new props default to true
27
+ * so the component remains backwards-compatible when no context is passed.
28
+ */
29
+ export function getVisibleHints({ activePanel = "list", hasSelection = true, hasRequests = true, onBodySection = true, onViewableBodySection = false, }) {
30
+ const ctx = { activePanel, hasSelection, hasRequests, onBodySection, onViewableBodySection };
31
+ return KEY_HINTS.filter((hint) => !hint.visible || hint.visible(ctx));
32
+ }
33
+ const SEPARATOR_WIDTH = 3; // " │ "
34
+ const PADDING_WIDTH = 2; // paddingX={1} each side
35
+ export function StatusBar({ message, filterActive, filterOpen, activePanel, hasSelection, hasRequests, onBodySection, onViewableBodySection, interceptorCount, width, }) {
36
+ const visibleHints = useMemo(() => getVisibleHints({ activePanel, hasSelection, hasRequests, onBodySection, onViewableBodySection }), [activePanel, hasSelection, hasRequests, onBodySection, onViewableBodySection]);
37
+ // Calculate available width for hints, accounting for prefix badges
38
+ const hintsAvailableWidth = useMemo(() => {
39
+ if (!width)
40
+ return undefined;
41
+ let prefixWidth = 0;
42
+ if (interceptorCount !== undefined && interceptorCount > 0) {
43
+ const badge = `[${interceptorCount} interceptor${interceptorCount === 1 ? "" : "s"}]`;
44
+ prefixWidth += badge.length + SEPARATOR_WIDTH;
45
+ }
46
+ if (filterActive) {
47
+ prefixWidth += "[FILTERED]".length + SEPARATOR_WIDTH;
48
+ }
49
+ return width - PADDING_WIDTH - prefixWidth;
50
+ }, [width, interceptorCount, filterActive]);
51
+ return (_jsx(Box, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, paddingX: 1, height: 2, children: message ? (_jsx(Text, { color: "yellow", children: message })) : filterOpen ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: "cyan", bold: true, children: "Esc" }), _jsx(Text, { dimColor: true, children: " close filter" })] })) : (_jsxs(Text, { children: [interceptorCount !== undefined && interceptorCount > 0 && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "magenta", bold: true, children: ["[", interceptorCount, " interceptor", interceptorCount === 1 ? "" : "s", "]"] }), _jsx(Text, { dimColor: true, children: " \u2502 " })] })), filterActive && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "yellow", bold: true, children: "[FILTERED]" }), _jsx(Text, { dimColor: true, children: " \u2502 " })] })), _jsx(HintContent, { hints: visibleHints, availableWidth: hintsAvailableWidth })] })) }));
52
+ }
53
+ //# sourceMappingURL=StatusBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBar.js","sourceRoot":"","sources":["../../../../src/cli/tui/components/StatusBar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Full-screen modal for viewing text body content in a less-style pager.
3
+ * Supports syntax highlighting, line numbers, search, and keyboard navigation.
4
+ * Replaces the main TUI when active (terminals don't support true overlays).
5
+ */
6
+ import React from "react";
7
+ export interface TextViewerModalProps {
8
+ text: string;
9
+ title: string;
10
+ contentType: string;
11
+ bodySize: number;
12
+ width: number;
13
+ height: number;
14
+ onClose: () => void;
15
+ isActive?: boolean;
16
+ onStatus?: (message: string) => void;
17
+ }
18
+ export declare function TextViewerModal({ text, title, contentType, bodySize, width, height, onClose, isActive, onStatus, }: TextViewerModalProps): React.ReactElement;
19
+ //# sourceMappingURL=TextViewerModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextViewerModal.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/components/TextViewerModal.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAiBjF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAQD,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,KAAK,EACL,WAAW,EACX,QAAQ,EACR,KAAK,EACL,MAAM,EACN,OAAO,EACP,QAAe,EACf,QAAQ,GACT,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,CA0Q3C"}
@@ -0,0 +1,227 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Full-screen modal for viewing text body content in a less-style pager.
4
+ * Supports syntax highlighting, line numbers, search, and keyboard navigation.
5
+ * Replaces the main TUI when active (terminals don't support true overlays).
6
+ */
7
+ import React, { useState, useMemo, useCallback, useRef, useEffect } from "react";
8
+ import { Box, Text, useInput } from "ink";
9
+ import { highlightCode } from "../utils/syntax-highlight.js";
10
+ import { formatSize } from "../utils/formatters.js";
11
+ import { copyToClipboard } from "../utils/clipboard.js";
12
+ import { HintContent } from "./HintContent.js";
13
+ const TEXT_VIEWER_HINTS = [
14
+ { key: "j/k", action: "nav" },
15
+ { key: "^f/^b", action: "page" },
16
+ { key: "g/G", action: "top/bottom" },
17
+ { key: "/", action: "search" },
18
+ { key: "n/N", action: "match" },
19
+ { key: "y", action: "copy" },
20
+ { key: "q/Esc", action: "close" },
21
+ ];
22
+ const STATUS_MESSAGE_TIMEOUT_MS = 3000;
23
+ /** Rows reserved for header (title + info/search + divider), hint bar, and borders */
24
+ const HEADER_ROWS = 3;
25
+ const FOOTER_ROWS = 2;
26
+ export function TextViewerModal({ text, title, contentType, bodySize, width, height, onClose, isActive = true, onStatus, }) {
27
+ const [scrollOffset, setScrollOffset] = useState(0);
28
+ const [searchMode, setSearchMode] = useState(false);
29
+ const [searchText, setSearchText] = useState("");
30
+ const [currentMatchIndex, setCurrentMatchIndex] = useState(0);
31
+ const [statusMessage, setStatusMessage] = useState();
32
+ const statusTimeoutRef = useRef(null);
33
+ // Cleanup timers on unmount
34
+ useEffect(() => {
35
+ return () => {
36
+ if (statusTimeoutRef.current) {
37
+ clearTimeout(statusTimeoutRef.current);
38
+ }
39
+ };
40
+ }, []);
41
+ const showLocalStatus = useCallback((message) => {
42
+ if (statusTimeoutRef.current) {
43
+ clearTimeout(statusTimeoutRef.current);
44
+ }
45
+ setStatusMessage(message);
46
+ statusTimeoutRef.current = setTimeout(() => setStatusMessage(undefined), STATUS_MESSAGE_TIMEOUT_MS);
47
+ }, []);
48
+ // Prepare highlighted lines
49
+ const lines = useMemo(() => {
50
+ const highlighted = highlightCode(text, contentType);
51
+ return highlighted.split("\n");
52
+ }, [text, contentType]);
53
+ const totalLines = lines.length;
54
+ const lineNumberWidth = String(totalLines).length;
55
+ const availableHeight = height - HEADER_ROWS - FOOTER_ROWS;
56
+ // Compute search match line indices
57
+ const matchLineIndices = useMemo(() => {
58
+ if (!searchText)
59
+ return [];
60
+ const lowerSearch = searchText.toLowerCase();
61
+ const indices = [];
62
+ // Search against raw text lines (not highlighted) for accurate matching
63
+ const rawLines = text.split("\n");
64
+ for (let i = 0; i < rawLines.length; i++) {
65
+ const line = rawLines[i];
66
+ if (line !== undefined && line.toLowerCase().includes(lowerSearch)) {
67
+ indices.push(i);
68
+ }
69
+ }
70
+ return indices;
71
+ }, [text, searchText]);
72
+ // Keep currentMatchIndex in bounds when matches change
73
+ useEffect(() => {
74
+ if (matchLineIndices.length > 0 && currentMatchIndex >= matchLineIndices.length) {
75
+ setCurrentMatchIndex(0);
76
+ }
77
+ }, [matchLineIndices.length, currentMatchIndex]);
78
+ // Scroll helpers
79
+ const maxScrollOffset = Math.max(0, totalLines - availableHeight);
80
+ const scrollTo = useCallback((line) => {
81
+ const clamped = Math.max(0, Math.min(line, maxScrollOffset));
82
+ setScrollOffset(clamped);
83
+ }, [maxScrollOffset]);
84
+ // Auto-scroll to current match when using n/N
85
+ const scrollToMatch = useCallback((matchIdx) => {
86
+ if (matchLineIndices.length === 0)
87
+ return;
88
+ const lineIdx = matchLineIndices[matchIdx];
89
+ if (lineIdx === undefined)
90
+ return;
91
+ // Centre the match in the viewport if possible
92
+ const centreOffset = Math.max(0, lineIdx - Math.floor(availableHeight / 2));
93
+ scrollTo(centreOffset);
94
+ }, [matchLineIndices, availableHeight, scrollTo]);
95
+ useInput((input, key) => {
96
+ if (searchMode) {
97
+ if (key.escape) {
98
+ // Cancel search
99
+ setSearchMode(false);
100
+ setSearchText("");
101
+ setCurrentMatchIndex(0);
102
+ return;
103
+ }
104
+ if (key.return) {
105
+ // Close search mode, jump to first match
106
+ setSearchMode(false);
107
+ if (matchLineIndices.length > 0) {
108
+ setCurrentMatchIndex(0);
109
+ scrollToMatch(0);
110
+ }
111
+ return;
112
+ }
113
+ if (key.backspace || key.delete) {
114
+ setSearchText((prev) => prev.slice(0, -1));
115
+ return;
116
+ }
117
+ // Only accept single printable characters
118
+ if (input && input.length === 1 && !key.ctrl && !key.meta) {
119
+ setSearchText((prev) => prev + input);
120
+ }
121
+ return;
122
+ }
123
+ // Normal mode
124
+ if (key.escape || input === "q") {
125
+ onClose();
126
+ return;
127
+ }
128
+ if (input === "j" || key.downArrow) {
129
+ setScrollOffset((prev) => Math.min(prev + 1, maxScrollOffset));
130
+ }
131
+ else if (input === "k" || key.upArrow) {
132
+ setScrollOffset((prev) => Math.max(prev - 1, 0));
133
+ }
134
+ else if (input === "d" && key.ctrl) {
135
+ const halfPage = Math.floor(availableHeight / 2);
136
+ setScrollOffset((prev) => Math.min(prev + halfPage, maxScrollOffset));
137
+ }
138
+ else if (input === "u" && key.ctrl) {
139
+ const halfPage = Math.floor(availableHeight / 2);
140
+ setScrollOffset((prev) => Math.max(prev - halfPage, 0));
141
+ }
142
+ else if ((input === "f" && key.ctrl) || input === " ") {
143
+ // Full-page down (Ctrl+f or Space)
144
+ setScrollOffset((prev) => Math.min(prev + availableHeight, maxScrollOffset));
145
+ }
146
+ else if (input === "b" && key.ctrl) {
147
+ // Full-page up
148
+ setScrollOffset((prev) => Math.max(prev - availableHeight, 0));
149
+ }
150
+ else if (input === "g" && !key.shift) {
151
+ setScrollOffset(0);
152
+ }
153
+ else if (input === "G") {
154
+ setScrollOffset(maxScrollOffset);
155
+ }
156
+ else if (input === "/") {
157
+ setSearchMode(true);
158
+ setSearchText("");
159
+ setCurrentMatchIndex(0);
160
+ }
161
+ else if (input === "n") {
162
+ // Next match
163
+ if (matchLineIndices.length > 0) {
164
+ const nextIdx = (currentMatchIndex + 1) % matchLineIndices.length;
165
+ setCurrentMatchIndex(nextIdx);
166
+ scrollToMatch(nextIdx);
167
+ }
168
+ }
169
+ else if (input === "N") {
170
+ // Previous match
171
+ if (matchLineIndices.length > 0) {
172
+ const prevIdx = (currentMatchIndex - 1 + matchLineIndices.length) % matchLineIndices.length;
173
+ setCurrentMatchIndex(prevIdx);
174
+ scrollToMatch(prevIdx);
175
+ }
176
+ }
177
+ else if (input === "y") {
178
+ void copyToClipboard(text).then(() => {
179
+ const msg = "Copied to clipboard";
180
+ showLocalStatus(msg);
181
+ onStatus?.(msg);
182
+ }, () => {
183
+ const msg = "Failed to copy to clipboard";
184
+ showLocalStatus(msg);
185
+ onStatus?.(msg);
186
+ });
187
+ }
188
+ }, { isActive });
189
+ // Content type short display
190
+ const shortCt = contentType.split(";")[0]?.trim() ?? "";
191
+ // Build visible row slice
192
+ const visibleSlice = lines.slice(scrollOffset, scrollOffset + availableHeight);
193
+ // Determine the current match line for highlighting
194
+ const currentMatchLine = matchLineIndices.length > 0 ? matchLineIndices[currentMatchIndex] : undefined;
195
+ // Set of all match lines for quick lookup
196
+ const matchLineSet = useMemo(() => new Set(matchLineIndices), [matchLineIndices]);
197
+ // Header border
198
+ const headerRight = ` ${shortCt} ${formatSize(bodySize)} `;
199
+ const titlePart = ` ${title} `;
200
+ const headerBorderWidth = width - titlePart.length - headerRight.length - 4;
201
+ const headerBorder = `\u250C\u2500${titlePart}${"\u2500".repeat(Math.max(0, headerBorderWidth))}${headerRight}\u2500\u2510`;
202
+ // Divider
203
+ const divider = `\u251C${"\u2500".repeat(width - 2)}\u2524`;
204
+ // Footer border
205
+ const footerBorder = `\u2514${"\u2500".repeat(width - 2)}\u2518`;
206
+ // Content width available for text (minus line number column, separator, padding)
207
+ const textAreaWidth = width - 4 - lineNumberWidth - 1;
208
+ return (_jsxs(Box, { flexDirection: "column", width: width, height: height, children: [_jsx(Text, { color: "cyan", children: headerBorder }), _jsx(Box, { paddingX: 1, height: 1, children: searchMode ? (_jsxs(Text, { children: [_jsx(Text, { color: "yellow", children: "search: " }), _jsx(Text, { children: searchText }), _jsx(Text, { color: "gray", children: "\u2588" })] })) : (_jsx(Text, { dimColor: true, wrap: "truncate", children: matchLineIndices.length > 0
209
+ ? `Line ${scrollOffset + 1}/${totalLines} | ${matchLineIndices.length} match${matchLineIndices.length === 1 ? "" : "es"} (${currentMatchIndex + 1}/${matchLineIndices.length})`
210
+ : `Line ${scrollOffset + 1}/${totalLines}` })) }), _jsx(Text, { color: "cyan", children: divider }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [visibleSlice.map((line, idx) => {
211
+ const globalLineIdx = scrollOffset + idx;
212
+ const lineNumber = globalLineIdx + 1;
213
+ const isMatch = matchLineSet.has(globalLineIdx);
214
+ const isCurrentMatch = globalLineIdx === currentMatchLine;
215
+ return (_jsx(TextLine, { lineNumber: lineNumber, lineNumberWidth: lineNumberWidth, text: line, textAreaWidth: textAreaWidth, isMatch: isMatch, isCurrentMatch: isCurrentMatch }, globalLineIdx));
216
+ }), visibleSlice.length < availableHeight && _jsx(Box, { flexGrow: 1 })] }), _jsx(Text, { color: "cyan", children: divider }), _jsx(Box, { paddingX: 1, height: 1, children: statusMessage ? (_jsx(Text, { color: "green", children: statusMessage })) : (_jsx(HintContent, { hints: TEXT_VIEWER_HINTS, availableWidth: width - 4 })) }), _jsx(Text, { color: "cyan", children: footerBorder })] }));
217
+ }
218
+ /**
219
+ * Single line of text with line number gutter.
220
+ */
221
+ const TextLine = React.memo(function TextLine({ lineNumber, lineNumberWidth, text, textAreaWidth, isMatch, isCurrentMatch, }) {
222
+ const paddedLineNumber = String(lineNumber).padStart(lineNumberWidth, " ");
223
+ // Truncate line if wider than available space
224
+ const displayText = text.length > textAreaWidth ? text.slice(0, textAreaWidth) : text;
225
+ return (_jsxs(Text, { children: [_jsx(Text, { color: isCurrentMatch ? "yellow" : isMatch ? "yellow" : undefined, bold: isCurrentMatch, dimColor: !isMatch && !isCurrentMatch, children: paddedLineNumber }), _jsxs(Text, { dimColor: true, children: [" ", "\u2502", " "] }), _jsx(Text, { children: displayText })] }));
226
+ });
227
+ //# sourceMappingURL=TextViewerModal.js.map