@botpress/adk-cli
Version:
Command-line interface for the Botpress Agent Development Kit (ADK)
143 lines (140 loc) • 5.71 kB
JavaScript
// @bun
import {
box,
fg,
getActiveTheme,
renderToString,
t,
text
} from "./chunk-m2h26j5f.js";
import {
ValidationErrorCode
} from "./chunk-p0hjqn4r.js";
// src/utils/assert-valid-project.ts
class ProjectValidationError extends Error {
validation;
constructor(message, validation) {
super(message);
this.validation = validation;
this.name = "ProjectValidationError";
}
}
function normalizeOptions(exitOnErrorOrOptions = true, skipRender = false) {
if (typeof exitOnErrorOrOptions === "object") {
return {
exitOnError: exitOnErrorOrOptions.exitOnError ?? true,
skipRender: exitOnErrorOrOptions.skipRender ?? false,
throwOnError: exitOnErrorOrOptions.throwOnError ?? false,
filterCodes: exitOnErrorOrOptions.filterCodes ?? []
};
}
return {
exitOnError: exitOnErrorOrOptions,
skipRender,
throwOnError: false,
filterCodes: []
};
}
function buildAgentNotLinked(ctx, theme) {
return box(ctx, { flexDirection: "column", paddingY: 1 }, [
text(ctx, t`${fg(theme.status.error)(`${theme.symbols.cross} Agent not linked to a bot`)}`),
text(ctx, t`${fg(theme.text.dim)("Your local agent needs to be linked to a remote bot.")}`, { marginTop: 1 }),
text(ctx, t`${fg(theme.text.dim)("Run the following command to link it:")}`, { marginTop: 1 }),
text(ctx, t`${fg(theme.syntax.keyword)("adk link")}`, { marginTop: 1, marginLeft: 2 })
]);
}
function buildValidationReport(ctx, theme, errors, warnings, info) {
const sections = [];
if (errors.length > 0) {
const children = [
text(ctx, t`${fg(theme.status.error)(`${theme.symbols.cross} Project validation failed:`)}`)
];
for (const error of errors) {
const item = [
text(ctx, t`${fg(theme.status.error)(`${error.file || "Project"}:`)}`, { marginLeft: 2 }),
text(ctx, t`${fg(theme.status.error)(error.message)}`, { marginLeft: 4 })
];
if (error.hint) {
item.push(text(ctx, t`${fg(theme.text.dim)(`${theme.symbols.info} ${error.hint}`)}`, { marginLeft: 4 }));
}
children.push(box(ctx, { flexDirection: "column", marginTop: 1 }, item));
}
sections.push(box(ctx, { flexDirection: "column" }, children));
}
if (warnings.length > 0) {
const children = [text(ctx, t`${fg(theme.status.warning)(`${theme.symbols.warning} Warnings:`)}`)];
for (const warning of warnings) {
const item = [
text(ctx, t`${fg(theme.status.warning)(`${warning.file || "Project"}: ${warning.message}`)}`, {
marginLeft: 2
})
];
if (warning.hint) {
item.push(text(ctx, t`${fg(theme.text.dim)(`${theme.symbols.info} ${warning.hint}`)}`, { marginLeft: 4 }));
}
children.push(box(ctx, { flexDirection: "column", marginTop: 1 }, item));
}
sections.push(box(ctx, { flexDirection: "column", marginTop: errors.length > 0 ? 1 : 0 }, children));
}
if (info.length > 0) {
const children = [text(ctx, t`${fg(theme.status.info)(`${theme.symbols.info} Info:`)}`)];
for (const entry of info) {
const item = [
text(ctx, t`${fg(theme.status.info)(`${entry.file || "Project"}: ${entry.message}`)}`, { marginLeft: 2 })
];
if (entry.hint) {
item.push(text(ctx, t`${fg(theme.text.dim)(`${theme.symbols.info} ${entry.hint}`)}`, { marginLeft: 4 }));
}
children.push(box(ctx, { flexDirection: "column", marginTop: 1 }, item));
}
sections.push(box(ctx, { flexDirection: "column", marginTop: errors.length > 0 || warnings.length > 0 ? 1 : 0 }, children));
}
return box(ctx, { flexDirection: "column", paddingY: 1 }, sections);
}
async function assertValidProject(project, exitOnErrorOrOptions = true, skipRender = false) {
const options = normalizeOptions(exitOnErrorOrOptions, skipRender);
const info = project.info;
const validationResult = await project.validate();
const codeFilter = (item) => options.filterCodes.length === 0 || !options.filterCodes.includes(item.code);
const allErrors = [...info.errors, ...validationResult.errors].filter(codeFilter);
const allWarnings = [...info.warnings, ...validationResult.warnings].filter(codeFilter);
const allInfo = validationResult.info.filter(codeFilter);
const hasErrors = allErrors.length > 0;
const hasLinkingError = allErrors.some((error) => error.code === ValidationErrorCode.AGENT_NOT_LINKED);
if (hasLinkingError) {
if (!options.skipRender) {
const theme = getActiveTheme();
console.log(await renderToString((ctx) => buildAgentNotLinked(ctx, theme)));
}
if (options.throwOnError) {
throw new ProjectValidationError("Agent not linked to a bot", {
errors: allErrors,
warnings: allWarnings,
info: allInfo
});
}
if (options.exitOnError) {
process.exit(1);
}
return { ...validationResult, errors: allErrors, warnings: allWarnings, info: allInfo };
}
if (hasErrors || allWarnings.length > 0 || allInfo.length > 0) {
if (!options.skipRender) {
const theme = getActiveTheme();
console.log(await renderToString((ctx) => buildValidationReport(ctx, theme, allErrors, allWarnings, allInfo)));
}
if (hasErrors && options.throwOnError) {
const detail = allErrors.map((e) => `${e.file ?? "Project"}: ${e.message}`).join("; ");
throw new ProjectValidationError(`Project validation failed \u2014 ${detail}`, {
errors: allErrors,
warnings: allWarnings,
info: allInfo
});
}
if (hasErrors && options.exitOnError) {
process.exit(1);
}
}
return { ...validationResult, errors: allErrors, warnings: allWarnings, info: allInfo };
}
export { assertValidProject };