@pentoshi/clai 2.0.28 → 2.0.30
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/dist/agent/confirm-port.d.ts +30 -0
- package/dist/agent/confirm-port.js +89 -0
- package/dist/agent/confirm-port.js.map +1 -0
- package/dist/agent/plan-tool.d.ts +26 -0
- package/dist/agent/plan-tool.js +188 -0
- package/dist/agent/plan-tool.js.map +1 -0
- package/dist/agent/runner.d.ts +6 -174
- package/dist/agent/runner.js +25 -1606
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/session-policy.d.ts +19 -0
- package/dist/agent/session-policy.js +40 -0
- package/dist/agent/session-policy.js.map +1 -0
- package/dist/agent/stop-summary.d.ts +8 -0
- package/dist/agent/stop-summary.js +53 -0
- package/dist/agent/stop-summary.js.map +1 -0
- package/dist/agent/tool-call-parser.d.ts +155 -0
- package/dist/agent/tool-call-parser.js +1107 -0
- package/dist/agent/tool-call-parser.js.map +1 -0
- package/dist/agent/tool-output-formatting.d.ts +7 -0
- package/dist/agent/tool-output-formatting.js +127 -0
- package/dist/agent/tool-output-formatting.js.map +1 -0
- package/dist/commands/update.js +1 -1
- package/dist/prompts/index.d.ts +2 -2
- package/dist/prompts/index.js +103 -59
- package/dist/prompts/index.js.map +1 -1
- package/dist/repl/prompt-line.d.ts +19 -0
- package/dist/repl/prompt-line.js +555 -0
- package/dist/repl/prompt-line.js.map +1 -0
- package/dist/repl/slash-commands.d.ts +24 -0
- package/dist/repl/slash-commands.js +317 -0
- package/dist/repl/slash-commands.js.map +1 -0
- package/dist/repl.d.ts +2 -25
- package/dist/repl.js +41 -898
- package/dist/repl.js.map +1 -1
- package/dist/safety/classifier.js +1 -1
- package/dist/safety/classifier.js.map +1 -1
- package/dist/store/keys.js +0 -4
- package/dist/store/keys.js.map +1 -1
- package/dist/store/plan.js +1 -1
- package/dist/store/plan.js.map +1 -1
- package/dist/tools/nmap-runner.d.ts +19 -0
- package/dist/tools/nmap-runner.js +177 -0
- package/dist/tools/nmap-runner.js.map +1 -0
- package/dist/tools/package-binary.d.ts +1 -0
- package/dist/tools/package-binary.js +30 -0
- package/dist/tools/package-binary.js.map +1 -0
- package/dist/tools/pdf.js +2 -2
- package/dist/tools/pdf.js.map +1 -1
- package/dist/tools/registry.d.ts +2 -11
- package/dist/tools/registry.js +3 -203
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/tool-types.d.ts +12 -0
- package/dist/tools/tool-types.js +2 -0
- package/dist/tools/tool-types.js.map +1 -0
- package/dist/tools/web/audit.d.ts +7 -29
- package/dist/tools/web/audit.js +7 -29
- package/dist/tools/web/audit.js.map +1 -1
- package/dist/tools/web/budget.d.ts +5 -28
- package/dist/tools/web/budget.js +5 -28
- package/dist/tools/web/budget.js.map +1 -1
- package/dist/tools/web/capture.d.ts +8 -35
- package/dist/tools/web/capture.js +8 -35
- package/dist/tools/web/capture.js.map +1 -1
- package/dist/tools/web/fetch-core.d.ts +6 -26
- package/dist/tools/web/fetch-core.js +6 -26
- package/dist/tools/web/fetch-core.js.map +1 -1
- package/dist/tools/web/readable.d.ts +7 -13
- package/dist/tools/web/readable.js +7 -13
- package/dist/tools/web/readable.js.map +1 -1
- package/dist/tools/web/search.d.ts +15 -19
- package/dist/tools/web/search.js +103 -44
- package/dist/tools/web/search.js.map +1 -1
- package/dist/tools/web/ssrf-guard.d.ts +8 -27
- package/dist/tools/web/ssrf-guard.js +8 -27
- package/dist/tools/web/ssrf-guard.js.map +1 -1
- package/dist/tui/App.js +19 -88
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/key-intent.d.ts +36 -0
- package/dist/tui/key-intent.js +54 -0
- package/dist/tui/key-intent.js.map +1 -0
- package/dist/tui/render-lines.js +125 -37
- package/dist/tui/render-lines.js.map +1 -1
- package/dist/tui/state.js +2 -2
- package/dist/tui/state.js.map +1 -1
- package/dist/tui/text-format.d.ts +11 -0
- package/dist/tui/text-format.js +85 -0
- package/dist/tui/text-format.js.map +1 -0
- package/dist/ui/ansi-box.d.ts +7 -0
- package/dist/ui/ansi-box.js +18 -0
- package/dist/ui/ansi-box.js.map +1 -0
- package/dist/ui/banner.d.ts +0 -9
- package/dist/ui/banner.js +1 -43
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/intro-card.d.ts +10 -0
- package/dist/ui/intro-card.js +39 -0
- package/dist/ui/intro-card.js.map +1 -0
- package/dist/ui/markdown.js +1 -1
- package/dist/ui/markdown.js.map +1 -1
- package/dist/ui/output-pane.js.map +1 -1
- package/dist/ui/spinner.js +6 -17
- package/dist/ui/spinner.js.map +1 -1
- package/dist/ui/wordmark.d.ts +7 -0
- package/dist/ui/wordmark.js +42 -0
- package/dist/ui/wordmark.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { platform } from "node:os";
|
|
2
|
+
import { commandAvailable } from "../os/pkgmgr.js";
|
|
3
|
+
import { spawnArgv } from "./shell.js";
|
|
4
|
+
import { nmapScanNeedsPrivilege, toConnectScanArgv } from "./validate.js";
|
|
5
|
+
/**
|
|
6
|
+
* Pick the OS-appropriate privilege-escalation prefix for a raw-socket scan.
|
|
7
|
+
* - macOS / Linux → `sudo` (clai forwards stdin so the user types their
|
|
8
|
+
* password live; the runner's interactive-stdin path handles the prompt).
|
|
9
|
+
* - Windows → `sudo` on Win11 build 26052+ if present, else `gsudo`
|
|
10
|
+
* if installed; otherwise no prefix (the user must run from an elevated
|
|
11
|
+
* terminal — nmap SYN scans need Administrator + Npcap there).
|
|
12
|
+
* Returns the elevation command + leading argv, or undefined when no helper
|
|
13
|
+
* is available (caller then falls back to an unprivileged connect scan).
|
|
14
|
+
*/
|
|
15
|
+
async function elevationPrefix() {
|
|
16
|
+
if (process.getuid && process.getuid() === 0) {
|
|
17
|
+
// Already root — no wrapper needed.
|
|
18
|
+
return { command: "", argv: [] };
|
|
19
|
+
}
|
|
20
|
+
if (platform() === "win32") {
|
|
21
|
+
if (await commandAvailable("sudo"))
|
|
22
|
+
return { command: "sudo", argv: [] };
|
|
23
|
+
if (await commandAvailable("gsudo"))
|
|
24
|
+
return { command: "gsudo", argv: [] };
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
if (await commandAvailable("sudo")) {
|
|
28
|
+
// -p sets a clear prompt; clai's interactive-stdin lets the user type it.
|
|
29
|
+
return { command: "sudo", argv: ["-p", "[clai] sudo password for nmap: "] };
|
|
30
|
+
}
|
|
31
|
+
if (await commandAvailable("doas"))
|
|
32
|
+
return { command: "doas", argv: [] };
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
/** Heuristic: did an nmap/sudo invocation fail because of missing privileges? */
|
|
36
|
+
function looksLikePrivilegeError(output) {
|
|
37
|
+
return /(?:requires root privileges|you (?:requested|need) (?:a scan type|root)|operation not permitted|must (?:be|run as) root|raw sockets?|sudo: (?:a (?:password|terminal) is required|no askpass|3 incorrect)|incorrect password|authentication failure|permission denied|requires (?:administrator|elevation))/i.test(output);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Run an nmap scan, transparently obtaining the privileges a stealth/raw
|
|
41
|
+
* scan needs and falling back to an unprivileged TCP connect scan when those
|
|
42
|
+
* privileges can't be obtained (no sudo, password declined, etc.).
|
|
43
|
+
*
|
|
44
|
+
* Strategy:
|
|
45
|
+
* 1. If the scan needs raw sockets and we're not root, wrap it in the
|
|
46
|
+
* OS-appropriate elevation helper (sudo / doas / gsudo). stdin is
|
|
47
|
+
* inherited so the user can type their password live — exactly the
|
|
48
|
+
* pattern documented for shell.exec sudo.
|
|
49
|
+
* 2. If elevation is unavailable, or the privileged attempt fails in a way
|
|
50
|
+
* that looks like a permission/privilege error, retry as `-sT` (TCP
|
|
51
|
+
* connect) which works for any user on every OS.
|
|
52
|
+
* This is the "most general approach first, then fall back" behavior the
|
|
53
|
+
* scans need so they never dead-end on "you must be root".
|
|
54
|
+
*/
|
|
55
|
+
export async function runNmapScan(argv, options) {
|
|
56
|
+
const needsPrivilege = nmapScanNeedsPrivilege(argv);
|
|
57
|
+
const prefix = needsPrivilege ? await elevationPrefix() : undefined;
|
|
58
|
+
const attempts = [];
|
|
59
|
+
if (needsPrivilege && prefix) {
|
|
60
|
+
if (prefix.command === "sudo") {
|
|
61
|
+
// Authenticate in a short, dedicated process. In the TUI, never inherit
|
|
62
|
+
// stdin for the long nmap scan: pipe the already-entered password to
|
|
63
|
+
// sudo so Ink keeps receiving Escape/Ctrl+C while nmap is running.
|
|
64
|
+
options?.onOutput?.(options?.requestSecret
|
|
65
|
+
? "\nAdministrator access is required for a stealth scan. Complete the secure password prompt below.\n"
|
|
66
|
+
: "\nAdministrator access is required for a stealth scan. Enter your sudo password below; Ctrl+C cancels.\n", "stdout");
|
|
67
|
+
let auth;
|
|
68
|
+
let sudoPassword;
|
|
69
|
+
if (options?.requestSecret) {
|
|
70
|
+
const password = await options.requestSecret({
|
|
71
|
+
title: "Administrator access",
|
|
72
|
+
prompt: "Enter your macOS password for sudo. It is sent only to sudo and is never stored.",
|
|
73
|
+
});
|
|
74
|
+
if (password === undefined) {
|
|
75
|
+
return { ok: false, output: "Administrator authentication cancelled.", exitCode: 130 };
|
|
76
|
+
}
|
|
77
|
+
sudoPassword = password;
|
|
78
|
+
auth = await spawnArgv({
|
|
79
|
+
command: "sudo",
|
|
80
|
+
argv: ["-S", "-p", "", "-v"],
|
|
81
|
+
stdinText: `${password}\n`,
|
|
82
|
+
timeoutMs: 30_000,
|
|
83
|
+
signal: options.signal,
|
|
84
|
+
onOutput: options.onOutput,
|
|
85
|
+
noArtifact: true,
|
|
86
|
+
interactiveStdin: false,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Classic REPL: let sudo read directly from its controlling terminal.
|
|
91
|
+
auth = await spawnArgv({
|
|
92
|
+
command: "sudo",
|
|
93
|
+
argv: [...prefix.argv, "-v"],
|
|
94
|
+
timeoutMs: 120_000,
|
|
95
|
+
signal: options?.signal,
|
|
96
|
+
onOutput: options?.onOutput,
|
|
97
|
+
interactiveStdin: true,
|
|
98
|
+
noArtifact: true,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (options?.signal?.aborted || auth.exitCode === 130)
|
|
102
|
+
return auth;
|
|
103
|
+
if (auth.ok) {
|
|
104
|
+
attempts.push({
|
|
105
|
+
command: "sudo",
|
|
106
|
+
argv: options?.requestSecret ? ["-S", "-p", "", "nmap", ...argv] : ["-n", "nmap", ...argv],
|
|
107
|
+
stdinText: options?.requestSecret ? `${sudoPassword ?? ""}\n` : undefined,
|
|
108
|
+
note: "Administrator access confirmed. Starting stealth scan (ESC cancels).",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
options?.onOutput?.("\nSudo authentication was not completed; using an unprivileged TCP connect scan instead.\n", "stderr");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else if (prefix.command) {
|
|
116
|
+
attempts.push({
|
|
117
|
+
command: prefix.command,
|
|
118
|
+
argv: [...prefix.argv, "nmap", ...argv],
|
|
119
|
+
interactiveStdin: true,
|
|
120
|
+
note: `Running a stealth scan with ${prefix.command} (you may be prompted for your password).`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Already root.
|
|
125
|
+
attempts.push({ command: "nmap", argv });
|
|
126
|
+
}
|
|
127
|
+
// Fallback: unprivileged connect scan if elevation fails/declines.
|
|
128
|
+
attempts.push({
|
|
129
|
+
command: "nmap",
|
|
130
|
+
argv: toConnectScanArgv(argv),
|
|
131
|
+
note: "Privileged scan unavailable — falling back to an unprivileged TCP connect scan (-sT).",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
else if (needsPrivilege && !prefix) {
|
|
135
|
+
// No elevation helper at all — go straight to the connect-scan fallback,
|
|
136
|
+
// but tell the user why the stealth scan was downgraded.
|
|
137
|
+
attempts.push({
|
|
138
|
+
command: "nmap",
|
|
139
|
+
argv: toConnectScanArgv(argv),
|
|
140
|
+
note: platform() === "win32"
|
|
141
|
+
? "No elevation helper found (sudo/gsudo). Run from an Administrator terminal with Npcap for a SYN scan; using a TCP connect scan (-sT) for now."
|
|
142
|
+
: "No sudo/doas available for a raw-socket SYN scan — using an unprivileged TCP connect scan (-sT) instead.",
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
attempts.push({ command: "nmap", argv });
|
|
147
|
+
}
|
|
148
|
+
let last;
|
|
149
|
+
for (let i = 0; i < attempts.length; i += 1) {
|
|
150
|
+
const attempt = attempts[i];
|
|
151
|
+
if (options?.signal?.aborted) {
|
|
152
|
+
return { ok: false, output: "Command aborted.", exitCode: 130 };
|
|
153
|
+
}
|
|
154
|
+
if (attempt.note)
|
|
155
|
+
options?.onOutput?.(`\n${attempt.note}\n`, "stdout");
|
|
156
|
+
const result = await spawnArgv({
|
|
157
|
+
command: attempt.command,
|
|
158
|
+
argv: attempt.argv,
|
|
159
|
+
stdinText: attempt.stdinText,
|
|
160
|
+
timeoutMs: 300_000,
|
|
161
|
+
signal: options?.signal,
|
|
162
|
+
onOutput: options?.onOutput,
|
|
163
|
+
...(attempt.interactiveStdin !== undefined
|
|
164
|
+
? { interactiveStdin: attempt.interactiveStdin }
|
|
165
|
+
: {}),
|
|
166
|
+
});
|
|
167
|
+
last = result;
|
|
168
|
+
// Success, or a non-privilege failure we shouldn't paper over → return.
|
|
169
|
+
const isLastAttempt = i === attempts.length - 1;
|
|
170
|
+
if (result.ok || isLastAttempt || !looksLikePrivilegeError(result.output)) {
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
// Otherwise loop to the next (fallback) attempt.
|
|
174
|
+
}
|
|
175
|
+
return last ?? { ok: false, output: "nmap produced no result.", exitCode: 1 };
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=nmap-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nmap-runner.js","sourceRoot":"","sources":["../../src/tools/nmap-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function packageBinaryName(pkg: string): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map a package name to the executable it installs, when they differ. Used
|
|
3
|
+
* by pkg.install to check whether the tool already exists before installing.
|
|
4
|
+
* Most packages share their binary name, so this only lists the exceptions.
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_BINARY_ALIASES = {
|
|
7
|
+
ripgrep: "rg",
|
|
8
|
+
dnsutils: "dig",
|
|
9
|
+
"bind-utils": "dig",
|
|
10
|
+
"bind9-dnsutils": "dig",
|
|
11
|
+
"python3-pip": "pip3",
|
|
12
|
+
"build-essential": "gcc",
|
|
13
|
+
nodejs: "node",
|
|
14
|
+
golang: "go",
|
|
15
|
+
"g++": "g++",
|
|
16
|
+
imagemagick: "magick",
|
|
17
|
+
"netcat-openbsd": "nc",
|
|
18
|
+
"net-tools": "ifconfig",
|
|
19
|
+
coreutils: "ls",
|
|
20
|
+
};
|
|
21
|
+
export function packageBinaryName(pkg) {
|
|
22
|
+
const lower = pkg.toLowerCase();
|
|
23
|
+
if (PACKAGE_BINARY_ALIASES[lower])
|
|
24
|
+
return PACKAGE_BINARY_ALIASES[lower];
|
|
25
|
+
// Strip a tap/cask prefix (homebrew "owner/tap/name" → "name") and any
|
|
26
|
+
// version suffix (apt "pkg=1.2" → "pkg") so the binary guess is sane.
|
|
27
|
+
const noTap = pkg.includes("/") ? pkg.slice(pkg.lastIndexOf("/") + 1) : pkg;
|
|
28
|
+
return noTap.split(/[=@:]/)[0] ?? noTap;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=package-binary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-binary.js","sourceRoot":"","sources":["../../src/tools/package-binary.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,sBAAsB,GAA2B;IACrD,OAAO,EAAE,IAAI;IACb,QAAQ,EAAE,KAAK;IACf,YAAY,EAAE,KAAK;IACnB,gBAAgB,EAAE,KAAK;IACvB,aAAa,EAAE,MAAM;IACrB,iBAAiB,EAAE,KAAK;IACxB,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,KAAK;IACZ,WAAW,EAAE,QAAQ;IACrB,gBAAgB,EAAE,IAAI;IACtB,WAAW,EAAE,UAAU;IACvB,SAAS,EAAE,IAAI;CAChB,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAChC,IAAI,sBAAsB,CAAC,KAAK,CAAC;QAAE,OAAO,sBAAsB,CAAC,KAAK,CAAE,CAAC;IACzE,uEAAuE;IACvE,sEAAsE;IACtE,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5E,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;AAC1C,CAAC"}
|
package/dist/tools/pdf.js
CHANGED
|
@@ -90,7 +90,7 @@ export async function pdfRead(args, options = {}) {
|
|
|
90
90
|
exitCode: 1,
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
//
|
|
93
|
+
// Step 1: fast text extraction for born-digital PDFs
|
|
94
94
|
let textLayerOutput = "";
|
|
95
95
|
if (await commandAvailable("pdftotext")) {
|
|
96
96
|
const direct = await spawnArgv({
|
|
@@ -115,7 +115,7 @@ export async function pdfRead(args, options = {}) {
|
|
|
115
115
|
if (options.signal?.aborted) {
|
|
116
116
|
return { ok: false, output: "pdf.read aborted.", exitCode: 130 };
|
|
117
117
|
}
|
|
118
|
-
//
|
|
118
|
+
// Step 2: scanned PDF → render pages then OCR each one
|
|
119
119
|
const missing = [];
|
|
120
120
|
if (!(await commandAvailable("pdftoppm")))
|
|
121
121
|
missing.push("pdftoppm (poppler)");
|
package/dist/tools/pdf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../src/tools/pdf.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../src/tools/pdf.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import type { ToolCall, ToolResult } from "../types.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
onOutput?: ((chunk: string, stream: "stdout" | "stderr") => void) | undefined;
|
|
5
|
-
requestSecret?: ((request: {
|
|
6
|
-
title: string;
|
|
7
|
-
prompt: string;
|
|
8
|
-
}) => Promise<string | undefined>) | undefined;
|
|
9
|
-
confirmed?: boolean | undefined;
|
|
10
|
-
userPrompt?: string | undefined;
|
|
11
|
-
}
|
|
12
|
-
export type ToolHandler = (args: Record<string, unknown>, options?: ToolRunOptions) => Promise<ToolResult>;
|
|
2
|
+
import { type ToolRunOptions, type ToolHandler } from "./tool-types.js";
|
|
3
|
+
export type { ToolRunOptions, ToolHandler };
|
|
13
4
|
export declare const toolRegistry: Record<string, ToolHandler>;
|
|
14
5
|
export declare function availableToolNames(): string[];
|
|
15
6
|
/**
|
package/dist/tools/registry.js
CHANGED
|
@@ -11,13 +11,14 @@ import { webSearch } from "./web/search.js";
|
|
|
11
11
|
import { RESPONSE_MODES } from "./web/types.js";
|
|
12
12
|
import { classifyToolCall } from "../safety/classifier.js";
|
|
13
13
|
import { loadScope } from "../store/scope.js";
|
|
14
|
-
import { parseHost, parsePortSpec, parseLegacyFlags, profileToNmapArgs,
|
|
15
|
-
import { platform } from "node:os";
|
|
14
|
+
import { parseHost, parsePortSpec, parseLegacyFlags, profileToNmapArgs, } from "./validate.js";
|
|
16
15
|
import { getNetworkContext } from "./network-context.js";
|
|
17
16
|
import { pingSweep } from "./net-ping-sweep.js";
|
|
18
17
|
import { toolCheckHandler } from "./capabilities.js";
|
|
19
18
|
import { jobManager } from "./jobs.js";
|
|
20
19
|
import { looksLongRunning } from "./command-intent.js";
|
|
20
|
+
import { packageBinaryName } from "./package-binary.js";
|
|
21
|
+
import { runNmapScan } from "./nmap-runner.js";
|
|
21
22
|
function requireString(args, key) {
|
|
22
23
|
const value = args[key];
|
|
23
24
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -45,207 +46,6 @@ function optionalResponseMode(args, key) {
|
|
|
45
46
|
}
|
|
46
47
|
return undefined;
|
|
47
48
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Map a package name to the executable it installs, when they differ. Used
|
|
50
|
-
* by pkg.install to check whether the tool already exists before installing.
|
|
51
|
-
* Most packages share their binary name, so this only lists the exceptions.
|
|
52
|
-
*/
|
|
53
|
-
const PACKAGE_BINARY_ALIASES = {
|
|
54
|
-
ripgrep: "rg",
|
|
55
|
-
dnsutils: "dig",
|
|
56
|
-
"bind-utils": "dig",
|
|
57
|
-
"bind9-dnsutils": "dig",
|
|
58
|
-
"python3-pip": "pip3",
|
|
59
|
-
"build-essential": "gcc",
|
|
60
|
-
nodejs: "node",
|
|
61
|
-
golang: "go",
|
|
62
|
-
"g++": "g++",
|
|
63
|
-
imagemagick: "magick",
|
|
64
|
-
"netcat-openbsd": "nc",
|
|
65
|
-
"net-tools": "ifconfig",
|
|
66
|
-
coreutils: "ls",
|
|
67
|
-
};
|
|
68
|
-
function packageBinaryName(pkg) {
|
|
69
|
-
const lower = pkg.toLowerCase();
|
|
70
|
-
if (PACKAGE_BINARY_ALIASES[lower])
|
|
71
|
-
return PACKAGE_BINARY_ALIASES[lower];
|
|
72
|
-
// Strip a tap/cask prefix (homebrew "owner/tap/name" → "name") and any
|
|
73
|
-
// version suffix (apt "pkg=1.2" → "pkg") so the binary guess is sane.
|
|
74
|
-
const noTap = pkg.includes("/") ? pkg.slice(pkg.lastIndexOf("/") + 1) : pkg;
|
|
75
|
-
return noTap.split(/[=@:]/)[0] ?? noTap;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Pick the OS-appropriate privilege-escalation prefix for a raw-socket scan.
|
|
79
|
-
* - macOS / Linux → `sudo` (clai forwards stdin so the user types their
|
|
80
|
-
* password live; the runner's interactive-stdin path handles the prompt).
|
|
81
|
-
* - Windows → `sudo` on Win11 build 26052+ if present, else `gsudo`
|
|
82
|
-
* if installed; otherwise no prefix (the user must run from an elevated
|
|
83
|
-
* terminal — nmap SYN scans need Administrator + Npcap there).
|
|
84
|
-
* Returns the elevation command + leading argv, or undefined when no helper
|
|
85
|
-
* is available (caller then falls back to an unprivileged connect scan).
|
|
86
|
-
*/
|
|
87
|
-
async function elevationPrefix() {
|
|
88
|
-
if (process.getuid && process.getuid() === 0) {
|
|
89
|
-
// Already root — no wrapper needed.
|
|
90
|
-
return { command: "", argv: [] };
|
|
91
|
-
}
|
|
92
|
-
if (platform() === "win32") {
|
|
93
|
-
if (await commandAvailable("sudo"))
|
|
94
|
-
return { command: "sudo", argv: [] };
|
|
95
|
-
if (await commandAvailable("gsudo"))
|
|
96
|
-
return { command: "gsudo", argv: [] };
|
|
97
|
-
return undefined;
|
|
98
|
-
}
|
|
99
|
-
if (await commandAvailable("sudo")) {
|
|
100
|
-
// -p sets a clear prompt; clai's interactive-stdin lets the user type it.
|
|
101
|
-
return { command: "sudo", argv: ["-p", "[clai] sudo password for nmap: "] };
|
|
102
|
-
}
|
|
103
|
-
if (await commandAvailable("doas"))
|
|
104
|
-
return { command: "doas", argv: [] };
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Run an nmap scan, transparently obtaining the privileges a stealth/raw
|
|
109
|
-
* scan needs and falling back to an unprivileged TCP connect scan when those
|
|
110
|
-
* privileges can't be obtained (no sudo, password declined, etc.).
|
|
111
|
-
*
|
|
112
|
-
* Strategy:
|
|
113
|
-
* 1. If the scan needs raw sockets and we're not root, wrap it in the
|
|
114
|
-
* OS-appropriate elevation helper (sudo / doas / gsudo). stdin is
|
|
115
|
-
* inherited so the user can type their password live — exactly the
|
|
116
|
-
* pattern documented for shell.exec sudo.
|
|
117
|
-
* 2. If elevation is unavailable, or the privileged attempt fails in a way
|
|
118
|
-
* that looks like a permission/privilege error, retry as `-sT` (TCP
|
|
119
|
-
* connect) which works for any user on every OS.
|
|
120
|
-
* This is the "most general approach first, then fall back" behavior the
|
|
121
|
-
* scans need so they never dead-end on "you must be root".
|
|
122
|
-
*/
|
|
123
|
-
async function runNmapScan(argv, options) {
|
|
124
|
-
const needsPrivilege = nmapScanNeedsPrivilege(argv);
|
|
125
|
-
const prefix = needsPrivilege ? await elevationPrefix() : undefined;
|
|
126
|
-
const attempts = [];
|
|
127
|
-
if (needsPrivilege && prefix) {
|
|
128
|
-
if (prefix.command === "sudo") {
|
|
129
|
-
// Authenticate in a short, dedicated process. In the TUI, never inherit
|
|
130
|
-
// stdin for the long nmap scan: pipe the already-entered password to
|
|
131
|
-
// sudo so Ink keeps receiving Escape/Ctrl+C while nmap is running.
|
|
132
|
-
options?.onOutput?.(options?.requestSecret
|
|
133
|
-
? "\nAdministrator access is required for a stealth scan. Complete the secure password prompt below.\n"
|
|
134
|
-
: "\nAdministrator access is required for a stealth scan. Enter your sudo password below; Ctrl+C cancels.\n", "stdout");
|
|
135
|
-
let auth;
|
|
136
|
-
let sudoPassword;
|
|
137
|
-
if (options?.requestSecret) {
|
|
138
|
-
const password = await options.requestSecret({
|
|
139
|
-
title: "Administrator access",
|
|
140
|
-
prompt: "Enter your macOS password for sudo. It is sent only to sudo and is never stored.",
|
|
141
|
-
});
|
|
142
|
-
if (password === undefined) {
|
|
143
|
-
return { ok: false, output: "Administrator authentication cancelled.", exitCode: 130 };
|
|
144
|
-
}
|
|
145
|
-
sudoPassword = password;
|
|
146
|
-
auth = await spawnArgv({
|
|
147
|
-
command: "sudo",
|
|
148
|
-
argv: ["-S", "-p", "", "-v"],
|
|
149
|
-
stdinText: `${password}\n`,
|
|
150
|
-
timeoutMs: 30_000,
|
|
151
|
-
signal: options.signal,
|
|
152
|
-
onOutput: options.onOutput,
|
|
153
|
-
noArtifact: true,
|
|
154
|
-
interactiveStdin: false,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
// Classic REPL: let sudo read directly from its controlling terminal.
|
|
159
|
-
auth = await spawnArgv({
|
|
160
|
-
command: "sudo",
|
|
161
|
-
argv: [...prefix.argv, "-v"],
|
|
162
|
-
timeoutMs: 120_000,
|
|
163
|
-
signal: options?.signal,
|
|
164
|
-
onOutput: options?.onOutput,
|
|
165
|
-
interactiveStdin: true,
|
|
166
|
-
noArtifact: true,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
if (options?.signal?.aborted || auth.exitCode === 130)
|
|
170
|
-
return auth;
|
|
171
|
-
if (auth.ok) {
|
|
172
|
-
attempts.push({
|
|
173
|
-
command: "sudo",
|
|
174
|
-
argv: options?.requestSecret ? ["-S", "-p", "", "nmap", ...argv] : ["-n", "nmap", ...argv],
|
|
175
|
-
stdinText: options?.requestSecret ? `${sudoPassword ?? ""}\n` : undefined,
|
|
176
|
-
note: "Administrator access confirmed. Starting stealth scan (ESC cancels).",
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
options?.onOutput?.("\nSudo authentication was not completed; using an unprivileged TCP connect scan instead.\n", "stderr");
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
else if (prefix.command) {
|
|
184
|
-
attempts.push({
|
|
185
|
-
command: prefix.command,
|
|
186
|
-
argv: [...prefix.argv, "nmap", ...argv],
|
|
187
|
-
interactiveStdin: true,
|
|
188
|
-
note: `Running a stealth scan with ${prefix.command} (you may be prompted for your password).`,
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
// Already root.
|
|
193
|
-
attempts.push({ command: "nmap", argv });
|
|
194
|
-
}
|
|
195
|
-
// Fallback: unprivileged connect scan if elevation fails/declines.
|
|
196
|
-
attempts.push({
|
|
197
|
-
command: "nmap",
|
|
198
|
-
argv: toConnectScanArgv(argv),
|
|
199
|
-
note: "Privileged scan unavailable — falling back to an unprivileged TCP connect scan (-sT).",
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
else if (needsPrivilege && !prefix) {
|
|
203
|
-
// No elevation helper at all — go straight to the connect-scan fallback,
|
|
204
|
-
// but tell the user why the stealth scan was downgraded.
|
|
205
|
-
attempts.push({
|
|
206
|
-
command: "nmap",
|
|
207
|
-
argv: toConnectScanArgv(argv),
|
|
208
|
-
note: platform() === "win32"
|
|
209
|
-
? "No elevation helper found (sudo/gsudo). Run from an Administrator terminal with Npcap for a SYN scan; using a TCP connect scan (-sT) for now."
|
|
210
|
-
: "No sudo/doas available for a raw-socket SYN scan — using an unprivileged TCP connect scan (-sT) instead.",
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
attempts.push({ command: "nmap", argv });
|
|
215
|
-
}
|
|
216
|
-
let last;
|
|
217
|
-
for (let i = 0; i < attempts.length; i += 1) {
|
|
218
|
-
const attempt = attempts[i];
|
|
219
|
-
if (options?.signal?.aborted) {
|
|
220
|
-
return { ok: false, output: "Command aborted.", exitCode: 130 };
|
|
221
|
-
}
|
|
222
|
-
if (attempt.note)
|
|
223
|
-
options?.onOutput?.(`\n${attempt.note}\n`, "stdout");
|
|
224
|
-
const result = await spawnArgv({
|
|
225
|
-
command: attempt.command,
|
|
226
|
-
argv: attempt.argv,
|
|
227
|
-
stdinText: attempt.stdinText,
|
|
228
|
-
timeoutMs: 300_000,
|
|
229
|
-
signal: options?.signal,
|
|
230
|
-
onOutput: options?.onOutput,
|
|
231
|
-
...(attempt.interactiveStdin !== undefined
|
|
232
|
-
? { interactiveStdin: attempt.interactiveStdin }
|
|
233
|
-
: {}),
|
|
234
|
-
});
|
|
235
|
-
last = result;
|
|
236
|
-
// Success, or a non-privilege failure we shouldn't paper over → return.
|
|
237
|
-
const isLastAttempt = i === attempts.length - 1;
|
|
238
|
-
if (result.ok || isLastAttempt || !looksLikePrivilegeError(result.output)) {
|
|
239
|
-
return result;
|
|
240
|
-
}
|
|
241
|
-
// Otherwise loop to the next (fallback) attempt.
|
|
242
|
-
}
|
|
243
|
-
return last ?? { ok: false, output: "nmap produced no result.", exitCode: 1 };
|
|
244
|
-
}
|
|
245
|
-
/** Heuristic: did an nmap/sudo invocation fail because of missing privileges? */
|
|
246
|
-
function looksLikePrivilegeError(output) {
|
|
247
|
-
return /(?:requires root privileges|you (?:requested|need) (?:a scan type|root)|operation not permitted|must (?:be|run as) root|raw sockets?|sudo: (?:a (?:password|terminal) is required|no askpass|3 incorrect)|incorrect password|authentication failure|permission denied|requires (?:administrator|elevation))/i.test(output);
|
|
248
|
-
}
|
|
249
49
|
export const toolRegistry = {
|
|
250
50
|
async "shell.exec"(args, options) {
|
|
251
51
|
const command = requireString(args, "command");
|