fix(exec-approvals): lazy-load command explainer

This commit is contained in:
Ruben Cuevas
2026-05-09 19:17:35 -04:00
committed by Peter Steinberger
parent c8d82e4535
commit fd5c5467e0
3 changed files with 37 additions and 1 deletions

View File

@@ -0,0 +1,24 @@
import { describe, expect, it, vi } from "vitest";
vi.mock("../command-explainer/extract.js", () => {
throw new Error("command explainer should not load for lightweight summaries");
});
describe("command-analysis lazy command explainer", () => {
it("does not load tree-sitter parser dependencies for policy summaries", async () => {
const { resolveCommandAnalysisSummaryForDisplay } = await import("./explain.js");
expect(
resolveCommandAnalysisSummaryForDisplay({
host: "gateway",
commandText: "python3 -c 'print(1)'",
}),
).toEqual(
expect.objectContaining({
commandCount: 1,
riskKinds: ["inline-eval"],
warningLines: ["Contains inline-eval: python3 -c"],
}),
);
});
});

View File

@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import { explainShellCommand } from "../command-explainer/index.js";
import {
explainCommandForDisplay,
resolveCommandAnalysisSummaryForDisplay,
summarizeCommandExplanation,
summarizeCommandSegmentsForDisplay,
@@ -19,6 +20,17 @@ describe("command-analysis explanation summary", () => {
);
});
it("loads the rich command explainer for rich display summaries", async () => {
const result = await explainCommandForDisplay(`bash -lc 'python3 -c "print(1)"'`);
expect(result?.summary).toEqual(
expect.objectContaining({
commandCount: 1,
riskKinds: expect.arrayContaining(["shell-wrapper", "inline-eval"]),
}),
);
});
it("summarizes policy command segments without async parsing", () => {
const summary = summarizeCommandSegmentsForDisplay([
{

View File

@@ -1,4 +1,3 @@
import { explainShellCommand } from "../command-explainer/extract.js";
import type { CommandExplanation, CommandRisk } from "../command-explainer/types.js";
import type { ExecCommandSegment } from "../exec-approvals-analysis.js";
import { analyzeCommandForPolicy } from "./policy.js";
@@ -122,6 +121,7 @@ export async function explainCommandForDisplay(
command: string,
): Promise<{ explanation: CommandExplanation; summary: CommandExplanationSummary } | null> {
try {
const { explainShellCommand } = await import("../command-explainer/extract.js");
const explanation = await explainShellCommand(command);
return { explanation, summary: summarizeCommandExplanation(explanation) };
} catch {