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.
- package/LICENSE +665 -0
- package/README.md +587 -0
- package/dist/cli/commands/clear.d.ts +3 -0
- package/dist/cli/commands/clear.d.ts.map +1 -0
- package/dist/cli/commands/clear.js +30 -0
- package/dist/cli/commands/clear.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +3 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -0
- package/dist/cli/commands/daemon.js +59 -0
- package/dist/cli/commands/daemon.js.map +1 -0
- package/dist/cli/commands/debug-dump.d.ts +27 -0
- package/dist/cli/commands/debug-dump.d.ts.map +1 -0
- package/dist/cli/commands/debug-dump.js +102 -0
- package/dist/cli/commands/debug-dump.js.map +1 -0
- package/dist/cli/commands/helpers.d.ts +18 -0
- package/dist/cli/commands/helpers.d.ts.map +1 -0
- package/dist/cli/commands/helpers.js +34 -0
- package/dist/cli/commands/helpers.js.map +1 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +28 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/intercept.d.ts +9 -0
- package/dist/cli/commands/intercept.d.ts.map +1 -0
- package/dist/cli/commands/intercept.js +121 -0
- package/dist/cli/commands/intercept.js.map +1 -0
- package/dist/cli/commands/interceptors.d.ts +3 -0
- package/dist/cli/commands/interceptors.d.ts.map +1 -0
- package/dist/cli/commands/interceptors.js +163 -0
- package/dist/cli/commands/interceptors.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +3 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +24 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/off.d.ts +8 -0
- package/dist/cli/commands/off.d.ts.map +1 -0
- package/dist/cli/commands/off.js +34 -0
- package/dist/cli/commands/off.js.map +1 -0
- package/dist/cli/commands/on.d.ts +9 -0
- package/dist/cli/commands/on.d.ts.map +1 -0
- package/dist/cli/commands/on.js +121 -0
- package/dist/cli/commands/on.js.map +1 -0
- package/dist/cli/commands/project.d.ts +3 -0
- package/dist/cli/commands/project.d.ts.map +1 -0
- package/dist/cli/commands/project.js +15 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/commands/restart.d.ts +3 -0
- package/dist/cli/commands/restart.d.ts.map +1 -0
- package/dist/cli/commands/restart.js +35 -0
- package/dist/cli/commands/restart.js.map +1 -0
- package/dist/cli/commands/status.d.ts +3 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +66 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +3 -0
- package/dist/cli/commands/stop.d.ts.map +1 -0
- package/dist/cli/commands/stop.js +24 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/commands/tui.d.ts +3 -0
- package/dist/cli/commands/tui.d.ts.map +1 -0
- package/dist/cli/commands/tui.js +36 -0
- package/dist/cli/commands/tui.js.map +1 -0
- package/dist/cli/commands/vars.d.ts +36 -0
- package/dist/cli/commands/vars.d.ts.map +1 -0
- package/dist/cli/commands/vars.js +207 -0
- package/dist/cli/commands/vars.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +37 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/tui/App.d.ts +15 -0
- package/dist/cli/tui/App.d.ts.map +1 -0
- package/dist/cli/tui/App.js +544 -0
- package/dist/cli/tui/App.js.map +1 -0
- package/dist/cli/tui/components/AccordionContent.d.ts +28 -0
- package/dist/cli/tui/components/AccordionContent.d.ts.map +1 -0
- package/dist/cli/tui/components/AccordionContent.js +87 -0
- package/dist/cli/tui/components/AccordionContent.js.map +1 -0
- package/dist/cli/tui/components/AccordionPanel.d.ts +38 -0
- package/dist/cli/tui/components/AccordionPanel.d.ts.map +1 -0
- package/dist/cli/tui/components/AccordionPanel.js +110 -0
- package/dist/cli/tui/components/AccordionPanel.js.map +1 -0
- package/dist/cli/tui/components/AccordionSection.d.ts +32 -0
- package/dist/cli/tui/components/AccordionSection.d.ts.map +1 -0
- package/dist/cli/tui/components/AccordionSection.js +41 -0
- package/dist/cli/tui/components/AccordionSection.js.map +1 -0
- package/dist/cli/tui/components/BodyView.d.ts +14 -0
- package/dist/cli/tui/components/BodyView.d.ts.map +1 -0
- package/dist/cli/tui/components/BodyView.js +39 -0
- package/dist/cli/tui/components/BodyView.js.map +1 -0
- package/dist/cli/tui/components/ExportModal.d.ts +34 -0
- package/dist/cli/tui/components/ExportModal.d.ts.map +1 -0
- package/dist/cli/tui/components/ExportModal.js +109 -0
- package/dist/cli/tui/components/ExportModal.js.map +1 -0
- package/dist/cli/tui/components/FilterBar.d.ts +21 -0
- package/dist/cli/tui/components/FilterBar.d.ts.map +1 -0
- package/dist/cli/tui/components/FilterBar.js +155 -0
- package/dist/cli/tui/components/FilterBar.js.map +1 -0
- package/dist/cli/tui/components/HeadersView.d.ts +13 -0
- package/dist/cli/tui/components/HeadersView.d.ts.map +1 -0
- package/dist/cli/tui/components/HeadersView.js +8 -0
- package/dist/cli/tui/components/HeadersView.js.map +1 -0
- package/dist/cli/tui/components/HelpModal.d.ts +13 -0
- package/dist/cli/tui/components/HelpModal.d.ts.map +1 -0
- package/dist/cli/tui/components/HelpModal.js +78 -0
- package/dist/cli/tui/components/HelpModal.js.map +1 -0
- package/dist/cli/tui/components/HintContent.d.ts +25 -0
- package/dist/cli/tui/components/HintContent.d.ts.map +1 -0
- package/dist/cli/tui/components/HintContent.js +44 -0
- package/dist/cli/tui/components/HintContent.js.map +1 -0
- package/dist/cli/tui/components/InfoModal.d.ts +15 -0
- package/dist/cli/tui/components/InfoModal.d.ts.map +1 -0
- package/dist/cli/tui/components/InfoModal.js +17 -0
- package/dist/cli/tui/components/InfoModal.js.map +1 -0
- package/dist/cli/tui/components/JsonExplorerModal.d.ts +24 -0
- package/dist/cli/tui/components/JsonExplorerModal.d.ts.map +1 -0
- package/dist/cli/tui/components/JsonExplorerModal.js +311 -0
- package/dist/cli/tui/components/JsonExplorerModal.js.map +1 -0
- package/dist/cli/tui/components/Modal.d.ts +26 -0
- package/dist/cli/tui/components/Modal.d.ts.map +1 -0
- package/dist/cli/tui/components/Modal.js +15 -0
- package/dist/cli/tui/components/Modal.js.map +1 -0
- package/dist/cli/tui/components/Panel.d.ts +19 -0
- package/dist/cli/tui/components/Panel.d.ts.map +1 -0
- package/dist/cli/tui/components/Panel.js +37 -0
- package/dist/cli/tui/components/Panel.js.map +1 -0
- package/dist/cli/tui/components/RequestDetails.d.ts +16 -0
- package/dist/cli/tui/components/RequestDetails.d.ts.map +1 -0
- package/dist/cli/tui/components/RequestDetails.js +23 -0
- package/dist/cli/tui/components/RequestDetails.js.map +1 -0
- package/dist/cli/tui/components/RequestList.d.ts +21 -0
- package/dist/cli/tui/components/RequestList.d.ts.map +1 -0
- package/dist/cli/tui/components/RequestList.js +30 -0
- package/dist/cli/tui/components/RequestList.js.map +1 -0
- package/dist/cli/tui/components/RequestListItem.d.ts +36 -0
- package/dist/cli/tui/components/RequestListItem.d.ts.map +1 -0
- package/dist/cli/tui/components/RequestListItem.js +130 -0
- package/dist/cli/tui/components/RequestListItem.js.map +1 -0
- package/dist/cli/tui/components/SaveModal.d.ts +30 -0
- package/dist/cli/tui/components/SaveModal.d.ts.map +1 -0
- package/dist/cli/tui/components/SaveModal.js +95 -0
- package/dist/cli/tui/components/SaveModal.js.map +1 -0
- package/dist/cli/tui/components/StatusBar.d.ts +39 -0
- package/dist/cli/tui/components/StatusBar.d.ts.map +1 -0
- package/dist/cli/tui/components/StatusBar.js +53 -0
- package/dist/cli/tui/components/StatusBar.js.map +1 -0
- package/dist/cli/tui/components/TextViewerModal.d.ts +19 -0
- package/dist/cli/tui/components/TextViewerModal.d.ts.map +1 -0
- package/dist/cli/tui/components/TextViewerModal.js +227 -0
- package/dist/cli/tui/components/TextViewerModal.js.map +1 -0
- package/dist/cli/tui/hooks/useBodyExport.d.ts +26 -0
- package/dist/cli/tui/hooks/useBodyExport.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useBodyExport.js +173 -0
- package/dist/cli/tui/hooks/useBodyExport.js.map +1 -0
- package/dist/cli/tui/hooks/useExport.d.ts +29 -0
- package/dist/cli/tui/hooks/useExport.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useExport.js +64 -0
- package/dist/cli/tui/hooks/useExport.js.map +1 -0
- package/dist/cli/tui/hooks/useRequests.d.ts +26 -0
- package/dist/cli/tui/hooks/useRequests.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useRequests.js +131 -0
- package/dist/cli/tui/hooks/useRequests.js.map +1 -0
- package/dist/cli/tui/hooks/useSaveBinary.d.ts +26 -0
- package/dist/cli/tui/hooks/useSaveBinary.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useSaveBinary.js +165 -0
- package/dist/cli/tui/hooks/useSaveBinary.js.map +1 -0
- package/dist/cli/tui/hooks/useSpinner.d.ts +5 -0
- package/dist/cli/tui/hooks/useSpinner.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useSpinner.js +25 -0
- package/dist/cli/tui/hooks/useSpinner.js.map +1 -0
- package/dist/cli/tui/hooks/useStdoutDimensions.d.ts +11 -0
- package/dist/cli/tui/hooks/useStdoutDimensions.d.ts.map +1 -0
- package/dist/cli/tui/hooks/useStdoutDimensions.js +29 -0
- package/dist/cli/tui/hooks/useStdoutDimensions.js.map +1 -0
- package/dist/cli/tui/utils/binary.d.ts +24 -0
- package/dist/cli/tui/utils/binary.d.ts.map +1 -0
- package/dist/cli/tui/utils/binary.js +152 -0
- package/dist/cli/tui/utils/binary.js.map +1 -0
- package/dist/cli/tui/utils/clipboard.d.ts +9 -0
- package/dist/cli/tui/utils/clipboard.d.ts.map +1 -0
- package/dist/cli/tui/utils/clipboard.js +58 -0
- package/dist/cli/tui/utils/clipboard.js.map +1 -0
- package/dist/cli/tui/utils/content-type.d.ts +8 -0
- package/dist/cli/tui/utils/content-type.d.ts.map +1 -0
- package/dist/cli/tui/utils/content-type.js +10 -0
- package/dist/cli/tui/utils/content-type.js.map +1 -0
- package/dist/cli/tui/utils/curl.d.ts +9 -0
- package/dist/cli/tui/utils/curl.d.ts.map +1 -0
- package/dist/cli/tui/utils/curl.js +54 -0
- package/dist/cli/tui/utils/curl.js.map +1 -0
- package/dist/cli/tui/utils/filters.d.ts +6 -0
- package/dist/cli/tui/utils/filters.d.ts.map +1 -0
- package/dist/cli/tui/utils/filters.js +13 -0
- package/dist/cli/tui/utils/filters.js.map +1 -0
- package/dist/cli/tui/utils/formatters.d.ts +49 -0
- package/dist/cli/tui/utils/formatters.d.ts.map +1 -0
- package/dist/cli/tui/utils/formatters.js +200 -0
- package/dist/cli/tui/utils/formatters.js.map +1 -0
- package/dist/cli/tui/utils/har.d.ts +75 -0
- package/dist/cli/tui/utils/har.d.ts.map +1 -0
- package/dist/cli/tui/utils/har.js +117 -0
- package/dist/cli/tui/utils/har.js.map +1 -0
- package/dist/cli/tui/utils/json-tree.d.ts +69 -0
- package/dist/cli/tui/utils/json-tree.d.ts.map +1 -0
- package/dist/cli/tui/utils/json-tree.js +339 -0
- package/dist/cli/tui/utils/json-tree.js.map +1 -0
- package/dist/cli/tui/utils/open-external.d.ts +17 -0
- package/dist/cli/tui/utils/open-external.d.ts.map +1 -0
- package/dist/cli/tui/utils/open-external.js +57 -0
- package/dist/cli/tui/utils/open-external.js.map +1 -0
- package/dist/cli/tui/utils/syntax-highlight.d.ts +16 -0
- package/dist/cli/tui/utils/syntax-highlight.d.ts.map +1 -0
- package/dist/cli/tui/utils/syntax-highlight.js +64 -0
- package/dist/cli/tui/utils/syntax-highlight.js.map +1 -0
- package/dist/daemon/control.d.ts +21 -0
- package/dist/daemon/control.d.ts.map +1 -0
- package/dist/daemon/control.js +311 -0
- package/dist/daemon/control.js.map +1 -0
- package/dist/daemon/htpx-client.d.ts +8 -0
- package/dist/daemon/htpx-client.d.ts.map +1 -0
- package/dist/daemon/htpx-client.js +25 -0
- package/dist/daemon/htpx-client.js.map +1 -0
- package/dist/daemon/index.d.ts +3 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +178 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/interceptor-loader.d.ts +30 -0
- package/dist/daemon/interceptor-loader.d.ts.map +1 -0
- package/dist/daemon/interceptor-loader.js +249 -0
- package/dist/daemon/interceptor-loader.js.map +1 -0
- package/dist/daemon/interceptor-runner.d.ts +39 -0
- package/dist/daemon/interceptor-runner.d.ts.map +1 -0
- package/dist/daemon/interceptor-runner.js +312 -0
- package/dist/daemon/interceptor-runner.js.map +1 -0
- package/dist/daemon/procsi-client.d.ts +8 -0
- package/dist/daemon/procsi-client.d.ts.map +1 -0
- package/dist/daemon/procsi-client.js +25 -0
- package/dist/daemon/procsi-client.js.map +1 -0
- package/dist/daemon/proxy.d.ts +34 -0
- package/dist/daemon/proxy.d.ts.map +1 -0
- package/dist/daemon/proxy.js +213 -0
- package/dist/daemon/proxy.js.map +1 -0
- package/dist/daemon/storage.d.ts +130 -0
- package/dist/daemon/storage.d.ts.map +1 -0
- package/dist/daemon/storage.js +761 -0
- package/dist/daemon/storage.js.map +1 -0
- package/dist/interceptors.d.ts +2 -0
- package/dist/interceptors.d.ts.map +1 -0
- package/dist/interceptors.js +2 -0
- package/dist/interceptors.js.map +1 -0
- package/dist/mcp/server.d.ts +110 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +806 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/overrides/node.d.ts +30 -0
- package/dist/overrides/node.d.ts.map +1 -0
- package/dist/overrides/node.js +66 -0
- package/dist/overrides/node.js.map +1 -0
- package/dist/shared/config.d.ts +21 -0
- package/dist/shared/config.d.ts.map +1 -0
- package/dist/shared/config.js +83 -0
- package/dist/shared/config.js.map +1 -0
- package/dist/shared/content-type.d.ts +64 -0
- package/dist/shared/content-type.d.ts.map +1 -0
- package/dist/shared/content-type.js +145 -0
- package/dist/shared/content-type.js.map +1 -0
- package/dist/shared/control-client.d.ts +144 -0
- package/dist/shared/control-client.d.ts.map +1 -0
- package/dist/shared/control-client.js +272 -0
- package/dist/shared/control-client.js.map +1 -0
- package/dist/shared/daemon.d.ts +33 -0
- package/dist/shared/daemon.d.ts.map +1 -0
- package/dist/shared/daemon.js +231 -0
- package/dist/shared/daemon.js.map +1 -0
- package/dist/shared/logger.d.ts +47 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/logger.js +200 -0
- package/dist/shared/logger.js.map +1 -0
- package/dist/shared/project.d.ts +76 -0
- package/dist/shared/project.d.ts.map +1 -0
- package/dist/shared/project.js +185 -0
- package/dist/shared/project.js.map +1 -0
- package/dist/shared/proxy-info.d.ts +10 -0
- package/dist/shared/proxy-info.d.ts.map +1 -0
- package/dist/shared/proxy-info.js +15 -0
- package/dist/shared/proxy-info.js.map +1 -0
- package/dist/shared/types.d.ts +128 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +5 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/shared/version.d.ts +5 -0
- package/dist/shared/version.d.ts.map +1 -0
- package/dist/shared/version.js +21 -0
- package/dist/shared/version.js.map +1 -0
- package/package.json +113 -0
- package/skills/procsi/SKILL.md +228 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for saving binary content to disk.
|
|
3
|
+
*/
|
|
4
|
+
import { useCallback } from "react";
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import * as os from "node:os";
|
|
8
|
+
import { copyToClipboard } from "../utils/clipboard.js";
|
|
9
|
+
import { findOrCreateProjectRoot, ensureHtpxDir } from "../../../shared/project.js";
|
|
10
|
+
/**
|
|
11
|
+
* Generate a filename for binary content based on request metadata.
|
|
12
|
+
*/
|
|
13
|
+
export function generateFilename(requestId, contentType, url) {
|
|
14
|
+
// Try to extract extension from URL first
|
|
15
|
+
let extension = "";
|
|
16
|
+
try {
|
|
17
|
+
const urlPath = new URL(url).pathname;
|
|
18
|
+
const urlExtMatch = urlPath.match(/\.([a-zA-Z0-9]+)$/);
|
|
19
|
+
if (urlExtMatch?.[1]) {
|
|
20
|
+
extension = urlExtMatch[1].toLowerCase();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// Invalid URL, fall through to content-type detection
|
|
25
|
+
}
|
|
26
|
+
if (!extension && contentType) {
|
|
27
|
+
// Derive extension from content type
|
|
28
|
+
extension = getExtensionFromContentType(contentType);
|
|
29
|
+
}
|
|
30
|
+
// Generate timestamp for uniqueness
|
|
31
|
+
const timestamp = Date.now();
|
|
32
|
+
const shortId = requestId.slice(0, 8);
|
|
33
|
+
return extension ? `${shortId}-${timestamp}.${extension}` : `${shortId}-${timestamp}.bin`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Map common content types to file extensions.
|
|
37
|
+
*/
|
|
38
|
+
function getExtensionFromContentType(contentType) {
|
|
39
|
+
const type = contentType.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
40
|
+
const mappings = {
|
|
41
|
+
// Images
|
|
42
|
+
"image/jpeg": "jpg",
|
|
43
|
+
"image/png": "png",
|
|
44
|
+
"image/gif": "gif",
|
|
45
|
+
"image/webp": "webp",
|
|
46
|
+
"image/svg+xml": "svg",
|
|
47
|
+
"image/x-icon": "ico",
|
|
48
|
+
"image/bmp": "bmp",
|
|
49
|
+
"image/tiff": "tiff",
|
|
50
|
+
// Audio
|
|
51
|
+
"audio/mpeg": "mp3",
|
|
52
|
+
"audio/wav": "wav",
|
|
53
|
+
"audio/ogg": "ogg",
|
|
54
|
+
"audio/webm": "weba",
|
|
55
|
+
"audio/aac": "aac",
|
|
56
|
+
"audio/flac": "flac",
|
|
57
|
+
// Video
|
|
58
|
+
"video/mp4": "mp4",
|
|
59
|
+
"video/webm": "webm",
|
|
60
|
+
"video/ogg": "ogv",
|
|
61
|
+
"video/quicktime": "mov",
|
|
62
|
+
"video/x-msvideo": "avi",
|
|
63
|
+
"video/x-matroska": "mkv",
|
|
64
|
+
// Documents
|
|
65
|
+
"application/pdf": "pdf",
|
|
66
|
+
"application/msword": "doc",
|
|
67
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
|
|
68
|
+
"application/vnd.ms-excel": "xls",
|
|
69
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
|
|
70
|
+
"application/vnd.ms-powerpoint": "ppt",
|
|
71
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx",
|
|
72
|
+
// Archives
|
|
73
|
+
"application/zip": "zip",
|
|
74
|
+
"application/gzip": "gz",
|
|
75
|
+
"application/x-tar": "tar",
|
|
76
|
+
"application/x-rar-compressed": "rar",
|
|
77
|
+
"application/x-7z-compressed": "7z",
|
|
78
|
+
// Other
|
|
79
|
+
"application/octet-stream": "bin",
|
|
80
|
+
"application/wasm": "wasm",
|
|
81
|
+
};
|
|
82
|
+
return mappings[type] ?? "bin";
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolve the target directory based on save location.
|
|
86
|
+
*/
|
|
87
|
+
function resolveTargetDir(location, customPath) {
|
|
88
|
+
switch (location) {
|
|
89
|
+
case "exports": {
|
|
90
|
+
const projectRoot = findOrCreateProjectRoot();
|
|
91
|
+
const htpxDir = ensureHtpxDir(projectRoot);
|
|
92
|
+
const exportsDir = path.join(htpxDir, "exports");
|
|
93
|
+
if (!fs.existsSync(exportsDir)) {
|
|
94
|
+
fs.mkdirSync(exportsDir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
return exportsDir;
|
|
97
|
+
}
|
|
98
|
+
case "downloads": {
|
|
99
|
+
const downloadsDir = path.join(os.homedir(), "Downloads");
|
|
100
|
+
if (!fs.existsSync(downloadsDir)) {
|
|
101
|
+
fs.mkdirSync(downloadsDir, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
return downloadsDir;
|
|
104
|
+
}
|
|
105
|
+
case "custom": {
|
|
106
|
+
if (!customPath) {
|
|
107
|
+
throw new Error("Custom path required");
|
|
108
|
+
}
|
|
109
|
+
// Expand ~ to home directory
|
|
110
|
+
const expandedPath = customPath.startsWith("~")
|
|
111
|
+
? path.join(os.homedir(), customPath.slice(1))
|
|
112
|
+
: customPath;
|
|
113
|
+
const resolvedPath = path.resolve(expandedPath);
|
|
114
|
+
// Ensure directory exists
|
|
115
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
116
|
+
fs.mkdirSync(resolvedPath, { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
return resolvedPath;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Save binary content to disk.
|
|
124
|
+
*/
|
|
125
|
+
export async function saveBinaryContent(body, filename, location, customPath) {
|
|
126
|
+
try {
|
|
127
|
+
const targetDir = resolveTargetDir(location, customPath);
|
|
128
|
+
const filePath = path.join(targetDir, filename);
|
|
129
|
+
fs.writeFileSync(filePath, body);
|
|
130
|
+
// Copy path to clipboard
|
|
131
|
+
try {
|
|
132
|
+
await copyToClipboard(filePath);
|
|
133
|
+
return {
|
|
134
|
+
success: true,
|
|
135
|
+
message: `Saved to ${filePath} (path copied)`,
|
|
136
|
+
filePath,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Clipboard failed but file was saved
|
|
141
|
+
return {
|
|
142
|
+
success: true,
|
|
143
|
+
message: `Saved to ${filePath}`,
|
|
144
|
+
filePath,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
message: err instanceof Error ? err.message : "Failed to save file",
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Hook providing binary save functionality.
|
|
157
|
+
*/
|
|
158
|
+
export function useSaveBinary() {
|
|
159
|
+
const saveBinary = useCallback(async (body, requestId, contentType, url, location, customPath) => {
|
|
160
|
+
const filename = generateFilename(requestId, contentType, url);
|
|
161
|
+
return saveBinaryContent(body, filename, location, customPath);
|
|
162
|
+
}, []);
|
|
163
|
+
return { saveBinary };
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=useSaveBinary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSaveBinary.js","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useSaveBinary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSpinner.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useSpinner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,wBAAgB,UAAU,CAAC,MAAM,UAAO,GAAG,MAAM,CAqBhD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook that cycles through braille spinner frames for loading indicators.
|
|
3
|
+
*/
|
|
4
|
+
import { useState, useEffect, useRef } from "react";
|
|
5
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
6
|
+
const SPINNER_INTERVAL_MS = 80;
|
|
7
|
+
export function useSpinner(active = true) {
|
|
8
|
+
const [frameIndex, setFrameIndex] = useState(0);
|
|
9
|
+
const intervalRef = useRef(null);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!active) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
intervalRef.current = setInterval(() => {
|
|
15
|
+
setFrameIndex((prev) => (prev + 1) % SPINNER_FRAMES.length);
|
|
16
|
+
}, SPINNER_INTERVAL_MS);
|
|
17
|
+
return () => {
|
|
18
|
+
if (intervalRef.current) {
|
|
19
|
+
clearInterval(intervalRef.current);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}, [active]);
|
|
23
|
+
return SPINNER_FRAMES[frameIndex] ?? SPINNER_FRAMES[0];
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=useSpinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSpinner.js","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useSpinner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEpD,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AACnF,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B,MAAM,UAAU,UAAU,CAAC,MAAM,GAAG,IAAI;IACtC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,MAAM,CAAwB,IAAI,CAAC,CAAC;IAExD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QAED,WAAW,CAAC,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;YACrC,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QAC9D,CAAC,EAAE,mBAAmB,CAAC,CAAC;QAExB,OAAO,GAAG,EAAE;YACV,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;gBACxB,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACrC,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO,cAAc,CAAC,UAAU,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for subscribing to stdout dimensions.
|
|
3
|
+
*
|
|
4
|
+
* Replaces ink-use-stdout-dimensions which has compatibility issues with
|
|
5
|
+
* Node.js 24 due to CJS/ESM interop problems.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Returns [columns, rows] of the terminal, updating when the terminal is resized.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useStdoutDimensions(): [number, number];
|
|
11
|
+
//# sourceMappingURL=useStdoutDimensions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStdoutDimensions.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useStdoutDimensions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBtD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for subscribing to stdout dimensions.
|
|
3
|
+
*
|
|
4
|
+
* Replaces ink-use-stdout-dimensions which has compatibility issues with
|
|
5
|
+
* Node.js 24 due to CJS/ESM interop problems.
|
|
6
|
+
*/
|
|
7
|
+
import { useState, useEffect } from "react";
|
|
8
|
+
import { useStdout } from "ink";
|
|
9
|
+
/**
|
|
10
|
+
* Returns [columns, rows] of the terminal, updating when the terminal is resized.
|
|
11
|
+
*/
|
|
12
|
+
export function useStdoutDimensions() {
|
|
13
|
+
const { stdout } = useStdout();
|
|
14
|
+
const [dimensions, setDimensions] = useState([
|
|
15
|
+
stdout.columns || 80,
|
|
16
|
+
stdout.rows || 24,
|
|
17
|
+
]);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const handler = () => {
|
|
20
|
+
setDimensions([stdout.columns || 80, stdout.rows || 24]);
|
|
21
|
+
};
|
|
22
|
+
stdout.on("resize", handler);
|
|
23
|
+
return () => {
|
|
24
|
+
stdout.off("resize", handler);
|
|
25
|
+
};
|
|
26
|
+
}, [stdout]);
|
|
27
|
+
return dimensions;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=useStdoutDimensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStdoutDimensions.js","sourceRoot":"","sources":["../../../../src/cli/tui/hooks/useStdoutDimensions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAEhC;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAE/B,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAmB;QAC7D,MAAM,CAAC,OAAO,IAAI,EAAE;QACpB,MAAM,CAAC,IAAI,IAAI,EAAE;KAClB,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,aAAa,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC;QAEF,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAE7B,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary content detection utilities.
|
|
3
|
+
*
|
|
4
|
+
* Determines whether a buffer contains binary or text content based on
|
|
5
|
+
* Content-Type headers and byte scanning.
|
|
6
|
+
*/
|
|
7
|
+
export interface BinaryCheckResult {
|
|
8
|
+
isBinary: boolean;
|
|
9
|
+
reason: "content-type" | "content-scan" | "text-content-type";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Check if content is binary based on Content-Type and/or byte scanning.
|
|
13
|
+
*
|
|
14
|
+
* Detection logic:
|
|
15
|
+
* 1. Check Content-Type against text whitelist - if match, return not binary
|
|
16
|
+
* 2. Check Content-Type against binary patterns - if match, return binary
|
|
17
|
+
* 3. Fall back to scanning first 8KB for >10% non-printable characters
|
|
18
|
+
*/
|
|
19
|
+
export declare function isBinaryContent(body: Buffer | undefined, contentType: string | undefined): BinaryCheckResult;
|
|
20
|
+
/**
|
|
21
|
+
* Get a human-readable description for a binary content type.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getBinaryTypeDescription(contentType: string | undefined): string;
|
|
24
|
+
//# sourceMappingURL=binary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/utils/binary.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4CH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,cAAc,GAAG,cAAc,GAAG,mBAAmB,CAAC;CAC/D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,iBAAiB,CAiDnB;AAoCD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CA2BhF"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary content detection utilities.
|
|
3
|
+
*
|
|
4
|
+
* Determines whether a buffer contains binary or text content based on
|
|
5
|
+
* Content-Type headers and byte scanning.
|
|
6
|
+
*/
|
|
7
|
+
import { TEXT_CONTENT_TYPES, TEXT_SUFFIXES } from "../../../shared/content-type.js";
|
|
8
|
+
/**
|
|
9
|
+
* Content types that are definitively binary.
|
|
10
|
+
*/
|
|
11
|
+
const BINARY_CONTENT_TYPES = [
|
|
12
|
+
"image/",
|
|
13
|
+
"audio/",
|
|
14
|
+
"video/",
|
|
15
|
+
"application/octet-stream",
|
|
16
|
+
"application/pdf",
|
|
17
|
+
"application/zip",
|
|
18
|
+
"application/gzip",
|
|
19
|
+
"application/x-tar",
|
|
20
|
+
"application/x-rar-compressed",
|
|
21
|
+
"application/x-7z-compressed",
|
|
22
|
+
"application/vnd.ms-excel",
|
|
23
|
+
"application/vnd.ms-powerpoint",
|
|
24
|
+
"application/vnd.ms-word",
|
|
25
|
+
"application/vnd.openxmlformats-officedocument",
|
|
26
|
+
"application/x-shockwave-flash",
|
|
27
|
+
"application/wasm",
|
|
28
|
+
"font/",
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Human-readable descriptions for binary content types.
|
|
32
|
+
*/
|
|
33
|
+
const BINARY_DESCRIPTIONS = {
|
|
34
|
+
"image/": "Image",
|
|
35
|
+
"audio/": "Audio",
|
|
36
|
+
"video/": "Video",
|
|
37
|
+
"font/": "Font",
|
|
38
|
+
"application/pdf": "PDF",
|
|
39
|
+
"application/zip": "Archive",
|
|
40
|
+
"application/gzip": "Archive",
|
|
41
|
+
"application/x-tar": "Archive",
|
|
42
|
+
"application/x-rar-compressed": "Archive",
|
|
43
|
+
"application/x-7z-compressed": "Archive",
|
|
44
|
+
"application/wasm": "WebAssembly",
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Check if content is binary based on Content-Type and/or byte scanning.
|
|
48
|
+
*
|
|
49
|
+
* Detection logic:
|
|
50
|
+
* 1. Check Content-Type against text whitelist - if match, return not binary
|
|
51
|
+
* 2. Check Content-Type against binary patterns - if match, return binary
|
|
52
|
+
* 3. Fall back to scanning first 8KB for >10% non-printable characters
|
|
53
|
+
*/
|
|
54
|
+
export function isBinaryContent(body, contentType) {
|
|
55
|
+
// No body means not binary (nothing to display)
|
|
56
|
+
if (!body || body.length === 0) {
|
|
57
|
+
return { isBinary: false, reason: "text-content-type" };
|
|
58
|
+
}
|
|
59
|
+
// Normalise content type (remove charset and other parameters)
|
|
60
|
+
const normalisedType = contentType?.split(";")[0]?.trim().toLowerCase();
|
|
61
|
+
// Check text content types first
|
|
62
|
+
if (normalisedType) {
|
|
63
|
+
// Check prefixes
|
|
64
|
+
let isTextContentType = false;
|
|
65
|
+
for (const prefix of TEXT_CONTENT_TYPES) {
|
|
66
|
+
if (normalisedType.startsWith(prefix)) {
|
|
67
|
+
isTextContentType = true;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Check suffixes (e.g., application/hal+json)
|
|
72
|
+
if (!isTextContentType) {
|
|
73
|
+
for (const suffix of TEXT_SUFFIXES) {
|
|
74
|
+
if (normalisedType.endsWith(suffix)) {
|
|
75
|
+
isTextContentType = true;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (isTextContentType) {
|
|
81
|
+
// Content-type says text, but verify with byte scan as safety net.
|
|
82
|
+
// Handles compressed bodies still in the DB, mislabelled content types, etc.
|
|
83
|
+
const scanResult = scanForBinaryContent(body);
|
|
84
|
+
return scanResult.isBinary
|
|
85
|
+
? { isBinary: true, reason: "content-scan" }
|
|
86
|
+
: { isBinary: false, reason: "text-content-type" };
|
|
87
|
+
}
|
|
88
|
+
// Check binary content types
|
|
89
|
+
for (const prefix of BINARY_CONTENT_TYPES) {
|
|
90
|
+
if (normalisedType.startsWith(prefix)) {
|
|
91
|
+
return { isBinary: true, reason: "content-type" };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Fall back to byte scanning
|
|
96
|
+
return scanForBinaryContent(body);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Scan buffer for binary content by checking for non-printable characters.
|
|
100
|
+
* Scans first 8KB and considers binary if >10% are non-printable.
|
|
101
|
+
*/
|
|
102
|
+
function scanForBinaryContent(body) {
|
|
103
|
+
const SCAN_SIZE = 8 * 1024; // 8KB
|
|
104
|
+
const BINARY_THRESHOLD = 0.1; // 10%
|
|
105
|
+
const bytesToScan = Math.min(body.length, SCAN_SIZE);
|
|
106
|
+
let nonPrintableCount = 0;
|
|
107
|
+
for (let i = 0; i < bytesToScan; i++) {
|
|
108
|
+
const byte = body[i];
|
|
109
|
+
if (byte === undefined)
|
|
110
|
+
continue;
|
|
111
|
+
// Allow common text characters:
|
|
112
|
+
// - Tab (9), LF (10), CR (13)
|
|
113
|
+
// - Printable ASCII (32-126)
|
|
114
|
+
// - Extended ASCII (128-255) for UTF-8
|
|
115
|
+
const isPrintable = byte === 9 || byte === 10 || byte === 13 || (byte >= 32 && byte <= 126) || byte >= 128;
|
|
116
|
+
if (!isPrintable) {
|
|
117
|
+
nonPrintableCount++;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const ratio = nonPrintableCount / bytesToScan;
|
|
121
|
+
return {
|
|
122
|
+
isBinary: ratio > BINARY_THRESHOLD,
|
|
123
|
+
reason: "content-scan",
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get a human-readable description for a binary content type.
|
|
128
|
+
*/
|
|
129
|
+
export function getBinaryTypeDescription(contentType) {
|
|
130
|
+
if (!contentType) {
|
|
131
|
+
return "Binary";
|
|
132
|
+
}
|
|
133
|
+
const normalisedType = contentType.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
134
|
+
// Check exact matches first
|
|
135
|
+
if (BINARY_DESCRIPTIONS[normalisedType]) {
|
|
136
|
+
return BINARY_DESCRIPTIONS[normalisedType];
|
|
137
|
+
}
|
|
138
|
+
// Check prefix matches
|
|
139
|
+
for (const [prefix, description] of Object.entries(BINARY_DESCRIPTIONS)) {
|
|
140
|
+
if (prefix.endsWith("/") && normalisedType.startsWith(prefix)) {
|
|
141
|
+
return description;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Extract subtype for better description
|
|
145
|
+
if (normalisedType.startsWith("application/")) {
|
|
146
|
+
const subtype = normalisedType.replace("application/", "");
|
|
147
|
+
// Capitalise first letter
|
|
148
|
+
return subtype.charAt(0).toUpperCase() + subtype.slice(1);
|
|
149
|
+
}
|
|
150
|
+
return "Binary";
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=binary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary.js","sourceRoot":"","sources":["../../../../src/cli/tui/utils/binary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform clipboard utilities using native commands.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Copy text to the system clipboard.
|
|
6
|
+
* Uses pbcopy on macOS, xclip on Linux, clip on Windows.
|
|
7
|
+
*/
|
|
8
|
+
export declare function copyToClipboard(text: string): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=clipboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/utils/clipboard.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;GAGG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDjE"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform clipboard utilities using native commands.
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
/**
|
|
6
|
+
* Copy text to the system clipboard.
|
|
7
|
+
* Uses pbcopy on macOS, xclip on Linux, clip on Windows.
|
|
8
|
+
*/
|
|
9
|
+
export async function copyToClipboard(text) {
|
|
10
|
+
const platform = process.platform;
|
|
11
|
+
let command;
|
|
12
|
+
let args;
|
|
13
|
+
if (platform === "darwin") {
|
|
14
|
+
command = "pbcopy";
|
|
15
|
+
args = [];
|
|
16
|
+
}
|
|
17
|
+
else if (platform === "win32") {
|
|
18
|
+
command = "clip";
|
|
19
|
+
args = [];
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
// Linux - try xclip first, fall back to xsel
|
|
23
|
+
command = "xclip";
|
|
24
|
+
args = ["-selection", "clipboard"];
|
|
25
|
+
}
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
const proc = spawn(command, args, { stdio: ["pipe", "ignore", "ignore"] });
|
|
28
|
+
proc.on("error", (err) => {
|
|
29
|
+
if (platform === "linux" && command === "xclip") {
|
|
30
|
+
// Try xsel as fallback
|
|
31
|
+
const xsel = spawn("xsel", ["--clipboard", "--input"], {
|
|
32
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
33
|
+
});
|
|
34
|
+
xsel.on("error", () => reject(new Error("No clipboard tool available (tried xclip and xsel)")));
|
|
35
|
+
xsel.on("close", (code) => {
|
|
36
|
+
if (code === 0)
|
|
37
|
+
resolve();
|
|
38
|
+
else
|
|
39
|
+
reject(new Error(`xsel exited with code ${code}`));
|
|
40
|
+
});
|
|
41
|
+
xsel.stdin.write(text);
|
|
42
|
+
xsel.stdin.end();
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
reject(err);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
proc.on("close", (code) => {
|
|
49
|
+
if (code === 0)
|
|
50
|
+
resolve();
|
|
51
|
+
else
|
|
52
|
+
reject(new Error(`${command} exited with code ${code}`));
|
|
53
|
+
});
|
|
54
|
+
proc.stdin.write(text);
|
|
55
|
+
proc.stdin.end();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../../../src/cli/tui/utils/clipboard.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAElC,IAAI,OAAe,CAAC;IACpB,IAAI,IAAc,CAAC;IAEnB,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,GAAG,QAAQ,CAAC;QACnB,IAAI,GAAG,EAAE,CAAC;IACZ,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,GAAG,MAAM,CAAC;QACjB,IAAI,GAAG,EAAE,CAAC;IACZ,CAAC;SAAM,CAAC;QACN,6CAA6C;QAC7C,OAAO,GAAG,OAAO,CAAC;QAClB,IAAI,GAAG,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;QAE3E,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,IAAI,QAAQ,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;gBAChD,uBAAuB;gBACvB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,aAAa,EAAE,SAAS,CAAC,EAAE;oBACrD,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;iBACpC,CAAC,CAAC;gBACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CACpB,MAAM,CAAC,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC,CACxE,CAAC;gBACF,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;oBACxB,IAAI,IAAI,KAAK,CAAC;wBAAE,OAAO,EAAE,CAAC;;wBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC1D,CAAC,CAAC,CAAC;gBACH,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACvB,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;;gBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,OAAO,qBAAqB,IAAI,EAAE,CAAC,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-type.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/utils/content-type.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEtE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-type detection utilities.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check whether a content-type string indicates JSON content.
|
|
6
|
+
*/
|
|
7
|
+
export function isJsonContent(contentType) {
|
|
8
|
+
return !!(contentType?.includes("application/json") || contentType?.includes("+json"));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=content-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-type.js","sourceRoot":"","sources":["../../../../src/cli/tui/utils/content-type.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,WAA+B;IAC3D,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,kBAAkB,CAAC,IAAI,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AACzF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate curl commands from captured requests.
|
|
3
|
+
*/
|
|
4
|
+
import type { CapturedRequest } from "../../../shared/types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Generate a curl command from a captured request.
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateCurl(request: CapturedRequest): string;
|
|
9
|
+
//# sourceMappingURL=curl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/utils/curl.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AA6BhE;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CA0B7D"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate curl commands from captured requests.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Headers that should be excluded from curl output.
|
|
6
|
+
* These are typically set automatically by curl or are connection-specific.
|
|
7
|
+
*/
|
|
8
|
+
const EXCLUDED_HEADERS = new Set([
|
|
9
|
+
"host",
|
|
10
|
+
"content-length",
|
|
11
|
+
"connection",
|
|
12
|
+
"accept-encoding",
|
|
13
|
+
"transfer-encoding",
|
|
14
|
+
]);
|
|
15
|
+
/**
|
|
16
|
+
* Escape a string for use in a shell single-quoted context.
|
|
17
|
+
*
|
|
18
|
+
* Within single quotes, the shell does not interpret any special characters
|
|
19
|
+
* (`$`, `` ` ``, `\`, `!`, newlines, etc.) — the only character that cannot
|
|
20
|
+
* appear inside single quotes is the single quote itself. We handle that by
|
|
21
|
+
* ending the quote, inserting an escaped single quote, and reopening.
|
|
22
|
+
*
|
|
23
|
+
* Null bytes are stripped because some shells (e.g. bash) silently truncate
|
|
24
|
+
* strings at `\0`, which could cause the remainder of a value to be lost.
|
|
25
|
+
*/
|
|
26
|
+
function shellEscape(str) {
|
|
27
|
+
return str.replace(/\0/g, "").replace(/'/g, "'\"'\"'");
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate a curl command from a captured request.
|
|
31
|
+
*/
|
|
32
|
+
export function generateCurl(request) {
|
|
33
|
+
const parts = ["curl"];
|
|
34
|
+
// Add method if not GET
|
|
35
|
+
if (request.method !== "GET") {
|
|
36
|
+
parts.push(`-X ${request.method}`);
|
|
37
|
+
}
|
|
38
|
+
// Add URL
|
|
39
|
+
parts.push(`'${shellEscape(request.url)}'`);
|
|
40
|
+
// Add headers (excluding certain automatic ones)
|
|
41
|
+
for (const [name, value] of Object.entries(request.requestHeaders)) {
|
|
42
|
+
if (EXCLUDED_HEADERS.has(name.toLowerCase())) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
parts.push(`-H '${shellEscape(name)}: ${shellEscape(value)}'`);
|
|
46
|
+
}
|
|
47
|
+
// Add body if present
|
|
48
|
+
if (request.requestBody && request.requestBody.length > 0) {
|
|
49
|
+
const bodyStr = request.requestBody.toString("utf-8");
|
|
50
|
+
parts.push(`-d '${shellEscape(bodyStr)}'`);
|
|
51
|
+
}
|
|
52
|
+
return parts.join(" \\\n ");
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=curl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curl.js","sourceRoot":"","sources":["../../../../src/cli/tui/utils/curl.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;GAGG;AACH,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,MAAM;IACN,gBAAgB;IAChB,YAAY;IACZ,iBAAiB;IACjB,mBAAmB;CACpB,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,OAAwB;IACnD,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,CAAC;IAEjC,wBAAwB;IACxB,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,UAAU;IACV,KAAK,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAE5C,iDAAiD;IACjD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QACnE,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YAC7C,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjE,CAAC;IAED,sBAAsB;IACtB,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/utils/filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAU7D"}
|