Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 65 additions & 5 deletions sdk/typescript/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import {
constants,
existsSync,
lstatSync,
opendirSync,
realpathSync,
type BigIntStats,
writeSync,
} from "node:fs";
import {
lstat,
mkdir,
opendir,
open,
readFile,
realpath,
Expand Down Expand Up @@ -5051,6 +5053,46 @@ function isOutsidePath(path: string): boolean {
return path === ".." || path.startsWith(`..${sep}`) || isAbsolute(path);
}

async function hasPartialOutput(path: string): Promise<boolean> {
let directory: Awaited<ReturnType<typeof opendir>> | undefined;
try {
directory = await opendir(path);
return (await directory.read()) !== null;
} catch (error: unknown) {
return !(
typeof error === "object" &&
error !== null &&
"code" in error &&
error.code === "ENOENT"
);
} finally {
if (directory !== undefined) {
try {
await directory.close();
} catch {}
}
}
}

function hasPartialOutputSync(path: string): boolean {
let directory: ReturnType<typeof opendirSync> | undefined;
try {
directory = opendirSync(path);
return directory.readSync() !== null;
} catch (error: unknown) {
return !(
typeof error === "object" &&
error !== null &&
"code" in error &&
error.code === "ENOENT"
);
} finally {
try {
directory?.closeSync();
} catch {}
}
}

async function runExport(
arguments_: ExportArguments,
output: Writable,
Expand Down Expand Up @@ -5769,41 +5811,49 @@ async function executeScan(
}

if (requestedSignal !== null) {
const partialOutput = scanDir !== null && hasPartialOutputSync(scanDir);
diagnostic("scan.interrupted", {
signal: requestedSignal,
partial_output: scanDir !== null,
partial_output: partialOutput,
});
return {
exitCode: interruptedExit(requestedSignal, scanDir, errorOutput),
exitCode: interruptedExit(
requestedSignal,
partialOutput ? scanDir : null,
errorOutput,
),
error:
requestedSignal === "SIGINT"
? "Scan canceled by Ctrl-C."
: "Scan terminated by SIGTERM.",
};
}
if (failed) {
const partialOutput = scanDir !== null && (await hasPartialOutput(scanDir));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Suppress the embedded path for empty cost-limited scans

When --max-cost is exceeded before any artifact is written, this correctly computes partialOutput as false, but ScanCostLimitExceededError subclasses ScanInterruptedError and hardcodes “partial output remains at …” in its message. The early return for interrupted errors therefore still prints and returns that misleading path while the verbose diagnostic says partial_output=false; build the displayed message from the computed state or otherwise handle the cost-limit subtype before that return.

Useful? React with 👍 / 👎.

const costLimitFailure =
failure instanceof ScanCostLimitExceededError ? failure : undefined;
const message =
failure instanceof OutputInsideProtectedRootError
? errorMessage(protectedRootErrorMessage(failure))
: scanFailureMessage(failure, selectedAuthentication);
: costLimitFailure !== undefined
? scanCostLimitFailureMessage(costLimitFailure, partialOutput)
: scanFailureMessage(failure, selectedAuthentication);
diagnostic("scan.failed", {
classification:
costLimitFailure !== undefined
? "cost_limit_exceeded"
: isLocalScanFailure(failure)
? "local"
: classifyConnectionFailure(failure),
partial_output: scanDir !== null,
partial_output: partialOutput,
max_cost_usd: costLimitFailure?.maxCostUsd,
estimated_usd: costLimitFailure?.cost.estimatedUsd,
});
errorOutput.write(`${message}\n`);
if (failure instanceof ScanInterruptedError) {
return { exitCode: 2, error: message };
}
if (scanDir !== null) {
if (partialOutput && scanDir !== null) {
errorOutput.write(
`Partial output was kept at ${errorMessage(scanDir)}.\n`,
);
Expand Down Expand Up @@ -6097,6 +6147,16 @@ function scanFailureMessage(
}
}

function scanCostLimitFailureMessage(
failure: ScanCostLimitExceededError,
partialOutput: boolean,
): string {
const output = partialOutput
? `partial output remains at ${errorMessage(failure.scanDir)}`
: "no partial output was kept";
return `Scan stopped: estimated cost ${formatUsd(failure.cost.estimatedUsd)} exceeded the ${formatUsd(failure.maxCostUsd)} limit; ${output}.`;
}

function scanScope(arguments_: ScanArguments): string | null {
if (arguments_.paths.length > 0) {
const displayed = arguments_.paths.slice(0, 3).map((path) => {
Expand Down
Loading