fix(cli): render actionable analysis errors
This commit is contained in:
parent
eb38e4c402
commit
af8c4efb4a
|
|
@ -6,6 +6,7 @@ import { silentLogger, type Logger } from "../logger.js";
|
|||
import { createEvidence } from "../domain/evidence.js";
|
||||
import type { NativeToolName } from "../contracts/nativeToolContracts.js";
|
||||
import type { ArtifactToolName } from "../contracts/artifactToolContracts.js";
|
||||
import { projectAnalysisError, type AnalysisError } from "../domain/errors.js";
|
||||
|
||||
const WORKFLOW_PROVIDER = {
|
||||
id: "rea-workflow",
|
||||
|
|
@ -47,8 +48,7 @@ export const runSessionStatus = async (
|
|||
logger: Logger = silentLogger,
|
||||
): Promise<JsonValue> => {
|
||||
const config = parseConfig(process.env);
|
||||
if (!config.ok)
|
||||
return { error: config.error._tag, message: config.error.message };
|
||||
if (!config.ok) return cliError(config.error);
|
||||
const session = createBinarySession(config.value, logger);
|
||||
try {
|
||||
return session.status();
|
||||
|
|
@ -64,13 +64,11 @@ const runAnalysis = async (
|
|||
logger: Logger,
|
||||
): Promise<JsonValue> => {
|
||||
const config = parseConfig(process.env);
|
||||
if (!config.ok)
|
||||
return { error: config.error._tag, message: config.error.message };
|
||||
if (!config.ok) return cliError(config.error);
|
||||
const session = createBinarySession(config.value, logger);
|
||||
try {
|
||||
const opened = await session.open(path);
|
||||
if (!opened.ok)
|
||||
return { error: opened.error._tag, message: opened.error.message };
|
||||
if (!opened.ok) return cliError(opened.error);
|
||||
if (
|
||||
tool === "binary_overview" ||
|
||||
tool === "analyze_function" ||
|
||||
|
|
@ -91,7 +89,7 @@ const runAnalysis = async (
|
|||
limitations: ["Derived by an REA composed workflow."],
|
||||
},
|
||||
)
|
||||
: { error: result.error._tag, message: result.error.message };
|
||||
: cliError(result.error);
|
||||
}
|
||||
const result = await session.execute(tool, arguments_);
|
||||
return result.ok
|
||||
|
|
@ -107,8 +105,13 @@ const runAnalysis = async (
|
|||
locations: result.value.locations,
|
||||
},
|
||||
)
|
||||
: { error: result.error._tag, message: result.error.message };
|
||||
: cliError(result.error);
|
||||
} finally {
|
||||
await session.close();
|
||||
}
|
||||
};
|
||||
|
||||
const cliError = (error: AnalysisError): JsonValue => ({
|
||||
error: "Analysis failed",
|
||||
...projectAnalysisError(error),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { parseConfig } from "./config.js";
|
|||
import { importReferenceSource } from "./application/ReferenceSourceImport.js";
|
||||
import { registerEvidenceCommands } from "./cliEvidenceCommands.js";
|
||||
import { registerProcessCommands } from "./cliProcessCommands.js";
|
||||
import { projectAnalysisError } from "./domain/errors.js";
|
||||
|
||||
/**
|
||||
* Build the one-shot Incur CLI without starting Hopper at import time.
|
||||
|
|
@ -374,7 +375,10 @@ const registerReferenceSourceCommand = (
|
|||
logCliCommand(logger, "import-reference-source", async () => {
|
||||
const config = parseConfig(process.env);
|
||||
if (!config.ok)
|
||||
return { error: config.error._tag, message: config.error.message };
|
||||
return {
|
||||
error: "Import failed",
|
||||
...projectAnalysisError(config.error),
|
||||
};
|
||||
const imported = await importReferenceSource({
|
||||
root: args.root,
|
||||
caller: "rea-cli",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import {
|
|||
import { parseConfig } from "./config.js";
|
||||
import { logCliCommand } from "./cliLogging.js";
|
||||
import type { Logger } from "./logger.js";
|
||||
import type { JsonValue } from "./domain/jsonValue.js";
|
||||
import { projectAnalysisError, type AnalysisError } from "./domain/errors.js";
|
||||
|
||||
/** Register filesystem-gated Evidence v2 commands. */
|
||||
export const registerEvidenceCommands = (
|
||||
|
|
@ -22,15 +24,12 @@ export const registerEvidenceCommands = (
|
|||
run: ({ args }) =>
|
||||
logCliCommand(logger, "evidence-import", async () => {
|
||||
const config = parseConfig(process.env);
|
||||
if (!config.ok)
|
||||
return { error: config.error._tag, message: config.error.message };
|
||||
if (!config.ok) return cliError(config.error);
|
||||
const imported = await importEvidenceBundleCommand(
|
||||
args.path,
|
||||
config.value.evidenceFilePolicy,
|
||||
);
|
||||
return imported.ok
|
||||
? imported.value
|
||||
: { error: imported.error._tag, message: imported.error.message };
|
||||
return imported.ok ? imported.value : cliError(imported.error);
|
||||
}),
|
||||
});
|
||||
cli.command("evidence-export", {
|
||||
|
|
@ -45,17 +44,14 @@ export const registerEvidenceCommands = (
|
|||
run: ({ args, options }) =>
|
||||
logCliCommand(logger, "evidence-export", async () => {
|
||||
const config = parseConfig(process.env);
|
||||
if (!config.ok)
|
||||
return { error: config.error._tag, message: config.error.message };
|
||||
if (!config.ok) return cliError(config.error);
|
||||
const exported = await exportEvidenceBundleCommand(
|
||||
args.source,
|
||||
args.output,
|
||||
options.overwrite,
|
||||
config.value.evidenceFilePolicy,
|
||||
);
|
||||
return exported.ok
|
||||
? exported.value
|
||||
: { error: exported.error._tag, message: exported.error.message };
|
||||
return exported.ok ? exported.value : cliError(exported.error);
|
||||
}),
|
||||
});
|
||||
cli.command("compare", {
|
||||
|
|
@ -72,8 +68,7 @@ export const registerEvidenceCommands = (
|
|||
run: ({ args, options }) =>
|
||||
logCliCommand(logger, "compare", async () => {
|
||||
const config = parseConfig(process.env);
|
||||
if (!config.ok)
|
||||
return { error: config.error._tag, message: config.error.message };
|
||||
if (!config.ok) return cliError(config.error);
|
||||
const compared = await compareEvidenceBundlesCommand({
|
||||
leftPath: args.left,
|
||||
rightPath: args.right,
|
||||
|
|
@ -81,9 +76,12 @@ export const registerEvidenceCommands = (
|
|||
limit: options.limit,
|
||||
policy: config.value.evidenceFilePolicy,
|
||||
});
|
||||
return compared.ok
|
||||
? compared.value
|
||||
: { error: compared.error._tag, message: compared.error.message };
|
||||
return compared.ok ? compared.value : cliError(compared.error);
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
const cliError = (error: AnalysisError): JsonValue => ({
|
||||
error: "Analysis failed",
|
||||
...projectAnalysisError(error),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { parseConfig } from "./config.js";
|
|||
import { createBinarySession } from "./application/runtime.js";
|
||||
import { createServer } from "./server/createServer.js";
|
||||
import { createLogger } from "./logger.js";
|
||||
import { projectAnalysisError } from "./domain/errors.js";
|
||||
|
||||
/**
|
||||
* Start the long-lived MCP adapter and install idempotent shutdown handlers.
|
||||
|
|
@ -21,7 +22,7 @@ import { createLogger } from "./logger.js";
|
|||
export const run = async (): Promise<number> => {
|
||||
const config = parseConfig(process.env);
|
||||
if (!config.ok) {
|
||||
process.stderr.write(`${config.error._tag}: ${config.error.message}\n`);
|
||||
process.stderr.write(`${projectAnalysisError(config.error).message}\n`);
|
||||
return 1;
|
||||
}
|
||||
const logger = createLogger("mcp", config.value.logLevel);
|
||||
|
|
@ -38,7 +39,7 @@ export const run = async (): Promise<number> => {
|
|||
{ errorTag: opened.error._tag },
|
||||
"Initial target failed to open",
|
||||
);
|
||||
process.stderr.write(`${opened.error._tag}: ${opened.error.message}\n`);
|
||||
process.stderr.write(`${projectAnalysisError(opened.error).message}\n`);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue