@botpress/adk-cli
Version:
Command-line interface for the Botpress Agent Development Kit (ADK)
325 lines (323 loc) • 11.9 kB
JavaScript
// @bun
import {
assertValidProject
} from "./chunk-wmec2w0t.js";
import {
ensureJsonOnlyFormat
} from "./chunk-7sfagm12.js";
import {
resolveCommandContext
} from "./chunk-3ahwp6fe.js";
import"./chunk-m2h26j5f.js";
import"./chunk-8gqzjqmb.js";
import"./chunk-kk3h6qaj.js";
import {
createCliLogger
} from "./chunk-gzwt1qdr.js";
import"./chunk-nxy2ya5r.js";
import"./chunk-wzj4dc7n.js";
import {
AdkError,
KBSyncOperation,
KnowledgeManager
} from "./chunk-p0hjqn4r.js";
import"./chunk-np5wcwfv.js";
import"./chunk-dq2xpa24.js";
import"./chunk-6w0knnta.js";
import"./chunk-40x04ckt.js";
import"./chunk-t76d8fxx.js";
import"./chunk-nh2akp42.js";
import"./chunk-0fdvzjbh.js";
import"./chunk-2a5b6azq.js";
import"./chunk-vay209b5.js";
import"./chunk-3xrpxgq4.js";
import"./chunk-rfm3jr1m.js";
import"./chunk-w346ejn9.js";
import"./chunk-knvm2anf.js";
import"./chunk-65h5trb5.js";
import"./chunk-s2akeqpw.js";
import"./chunk-6771vrjp.js";
import"./chunk-g8mm42v1.js";
import"./chunk-50hzjdck.js";
import"./chunk-nn2jb0x0.js";
import"./chunk-v8xvth6j.js";
import"./chunk-kkk13rcb.js";
import"./chunk-ytpp1kam.js";
import"./chunk-na956zz3.js";
import"./chunk-f4bw8q7c.js";
import"./chunk-0v8vgrns.js";
import"./chunk-54qt5g7m.js";
import {
__require
} from "./chunk-dhs2bg35.js";
// src/commands/adk-kb.ts
async function adkKbSync(options) {
ensureJsonOnlyFormat(options?.format);
const isJson = options?.format === "json";
const logger = createCliLogger({ format: options?.format });
if (isJson && !options?.yes) {
throw new AdkError({ code: "INVALID_FLAGS", message: "--format json requires --yes flag", expected: true });
}
if (!options?.dev && !options?.prod) {
throw new AdkError({ code: "INVALID_FLAGS", message: "You must specify either --dev or --prod", expected: true });
}
if (options?.dev && options?.prod) {
throw new AdkError({ code: "INVALID_FLAGS", message: "Cannot specify both --dev and --prod", expected: true });
}
const isDev = options?.dev || false;
const context = await resolveCommandContext({
target: isDev ? "dev" : "prod",
require: ["project", "credentials", "workspace", "bot"]
});
const project = context.project;
const botId = context.botId;
const targetLabel = isDev ? "development" : "production";
logger.info(`\uD83D\uDD04 Syncing knowledge bases to ${targetLabel} bot...
`, "cyan");
await assertValidProject(project);
logger.info(`Bot ID: ${botId}
`, "gray");
if (project.knowledge.length === 0) {
logger.info("\uD83D\uDCDA No knowledge bases defined in project.").result({ success: true, synced: 0, skipped: 0, failed: 0, totalErrors: 0 });
return;
}
const kbManager = new KnowledgeManager({
project,
botId,
credentials: context.credentials
});
const kbsWithWebsites = kbManager.getKBsWithWebsiteSources();
if (kbsWithWebsites.length > 0) {
logger.warn("\u26A0\uFE0F Note: Some KBs have website sources that require adk dev to be running.");
logger.info(` KBs with websites: ${kbsWithWebsites.join(", ")}`, "gray");
logger.newline();
}
const plan = await kbManager.createSyncPlan();
const orphanedKBs = await kbManager.getOrphanedKBs();
if (orphanedKBs.length > 0) {
logger.warn(`
\u26A0\uFE0F Found ${orphanedKBs.length} remote KB(s) not defined locally:`);
for (const kb of orphanedKBs) {
logger.warn(` \u2022 ${kb.name}`);
}
logger.newline();
if (options?.confirmDeleteKbs) {
for (const kb of orphanedKBs) {
logger.error(` Deleting KB "${kb.name}"...`);
const { deletedFiles } = await kbManager.deleteKnowledgeBase(kb.id, kb.name);
logger.info(` Deleted ${deletedFiles} files`, "gray");
}
logger.newline();
} else if (!options?.yes) {
const { promptYesNo } = await import("./chunk-6afthdr4.js");
if (await promptYesNo("Do you want to delete these KBs and their files? (y/N): ", process.stdout)) {
for (const kb of orphanedKBs) {
logger.error(` Deleting KB "${kb.name}"...`);
const { deletedFiles } = await kbManager.deleteKnowledgeBase(kb.id, kb.name);
logger.info(` Deleted ${deletedFiles} files`, "gray");
}
logger.newline();
}
} else {
logger.warn(" To delete: run without --yes for interactive prompt, or re-run with --confirm-storage-changes");
logger.newline();
}
}
const allOrphanedSources = [];
for (const item of plan.items) {
if (item.orphanedSources && item.orphanedSources.length > 0) {
allOrphanedSources.push({
kbName: item.kb.name,
sources: item.orphanedSources.map((s) => ({ dsId: s.dsId, fileCount: s.fileCount }))
});
}
}
if (allOrphanedSources.length > 0) {
logger.warn(`
\u26A0\uFE0F Found orphaned sources (no longer defined locally):`);
for (const { kbName, sources } of allOrphanedSources) {
logger.warn(` ${kbName}:`);
for (const s of sources) {
logger.warn(` \u2022 "${s.dsId}" - ${s.fileCount} files`);
}
}
logger.newline();
}
if (!plan.hasChanges && !options?.force) {
logger.info("\u2705 All knowledge bases are up to date.", "green");
logger.info(` ${plan.toSkip} KB(s) unchanged`, "gray");
for (const item of plan.items) {
if (item.sources && item.sources.length > 0) {
logger.info(`
${item.kb.name}:`, "gray");
for (const source of item.sources) {
logger.info(` \u2713 ${source.dsId} (${source.dsType}) - ${source.reason}`, "gray");
}
}
}
logger.info("No changes needed.").result({ success: true, synced: 0, skipped: plan.toSkip, failed: 0, totalErrors: 0 });
return;
}
logger.info(`\uD83D\uDCCB KB sync plan:
`);
for (const item of plan.items) {
if (item.operation === KBSyncOperation.Sync || options?.force) {
const icon = item.operation === KBSyncOperation.Sync ? "\uD83D\uDD04" : "\u23ED\uFE0F ";
const needsSync = item.operation === KBSyncOperation.Sync;
if (needsSync) {
logger.warn(` ${icon} ${item.kb.name}`);
logger.warn(` ${item.reason}`);
} else {
logger.info(` ${icon} ${item.kb.name}`, "gray");
logger.info(` ${item.reason}`, "gray");
}
if (item.sources && item.sources.length > 0) {
for (const source of item.sources) {
const sourceIcon = source.needsSync ? "\u2022" : "\u2713";
if (source.needsSync) {
logger.warn(` ${sourceIcon} ${source.dsId} (${source.dsType})`);
logger.warn(` ${source.reason}`);
} else {
logger.info(` ${sourceIcon} ${source.dsId} (${source.dsType})`, "gray");
logger.info(` ${source.reason}`, "gray");
}
if (source.fileChanges) {
if (source.fileChanges.added.length > 0) {
logger.info(` + Added: ${source.fileChanges.added.length} files`, "green");
for (const file of source.fileChanges.added) {
logger.info(` + ${file}`, "green");
}
}
if (source.fileChanges.deleted.length > 0) {
logger.error(` - Deleted: ${source.fileChanges.deleted.length} files`);
for (const file of source.fileChanges.deleted) {
logger.error(` - ${file}`);
}
}
if (source.fileChanges.modified.length > 0) {
logger.info(` ~ Modified: ${source.fileChanges.modified.length} files`, "blue");
for (const file of source.fileChanges.modified) {
logger.info(` ~ ${file}`, "blue");
}
}
}
}
if (item.orphanedSources && item.orphanedSources.length > 0) {
logger.error(` Orphaned sources to remove:`);
for (const orphaned of item.orphanedSources) {
logger.error(` \u2715 ${orphaned.dsId} (${orphaned.fileCount} files)`);
}
}
} else {
if (needsSync) {
logger.warn(` Sources: ${item.kb.sourceCount}`);
} else {
logger.info(` Sources: ${item.kb.sourceCount}`, "gray");
}
}
logger.newline();
} else {
logger.info(` \u23ED\uFE0F ${item.kb.name} - ${item.reason}`, "gray");
}
}
logger.newline();
logger.info(`KBs: ${plan.toSync} to sync, ${plan.toSkip} up to date`);
logger.info(`Sources: ${plan.sourcesToSync} to sync, ${plan.sourcesToSkip} up to date`);
if (plan.orphanedSourcesToDelete > 0) {
logger.error(`Orphaned sources: ${plan.orphanedSourcesToDelete} to remove`);
}
logger.newline();
if (options?.dryRun) {
logger.info("\uD83D\uDD0D Dry run mode - no changes will be applied.", "blue").result({
success: true,
dryRun: true,
toSync: plan.toSync,
toSkip: plan.toSkip,
orphanedSourcesToDelete: plan.orphanedSourcesToDelete
});
return;
}
if (!options?.yes && plan.toSync > 0) {
const { promptYesNo } = await import("./chunk-6afthdr4.js");
if (!await promptYesNo("Proceed with sync? (y/N): ", process.stdout)) {
logger.info("\u274C Sync cancelled.");
return;
}
}
logger.info(`\u23F3 Syncing knowledge bases...
`);
const result = await kbManager.executeSync(plan, {
force: options?.force,
confirmDestructive: true
});
logger.info(`
\uD83D\uDCCA Sync results:`);
if (result.synced.length > 0) {
logger.info(`
\u2705 Synced (${result.synced.length}):`, "green");
for (const item of result.synced) {
logger.info(` \u2022 ${item.name}`, "green");
logger.info(` Files: ${item.result.processed} processed`, "gray");
if (item.result.added.length > 0) {
logger.info(` Added: ${item.result.added.length}`, "gray");
}
if (item.result.updated.length > 0) {
logger.info(` Updated: ${item.result.updated.length}`, "gray");
}
if (item.result.deleted.length > 0) {
logger.info(` Deleted: ${item.result.deleted.length}`, "gray");
}
if (item.result.errors.length > 0) {
logger.warn(` Errors: ${item.result.errors.length}`);
for (const err of item.result.errors) {
logger.warn(` - ${err.file}: ${err.error}`);
}
}
}
}
if (result.skipped.length > 0) {
logger.info(`
\u23ED\uFE0F Skipped (${result.skipped.length}):`, "gray");
for (const item of result.skipped) {
logger.info(` \u2022 ${item.name} - ${item.reason}`, "gray");
}
}
if (result.failed.length > 0) {
logger.error(`
\u274C Failed (${result.failed.length}):`);
for (const item of result.failed) {
logger.error(` \u2022 ${item.name}: ${item.error}`);
}
}
if (result.websiteSyncs && result.websiteSyncs.length > 0) {
logger.info(`
\uD83C\uDF10 Website sync workflows triggered (${result.websiteSyncs.length}):`, "cyan");
for (const ws of result.websiteSyncs) {
logger.info(` \u2022 ${ws.kbName}: workflow ${ws.workflowId}`, "cyan");
}
logger.info(" Website syncs run asynchronously in the bot runtime.", "gray");
}
const totalErrors = result.failed.length + result.synced.reduce((sum, s) => sum + s.result.errors.length, 0);
if (totalErrors === 0) {
logger.info(`
\uD83C\uDF89 KB sync completed successfully!`, "green").result({
success: true,
synced: result.synced.length,
skipped: result.skipped.length,
failed: result.failed.length,
totalErrors: 0
});
} else {
logger.warn(`
\u26A0\uFE0F KB sync completed with some errors.`).result({
success: false,
synced: result.synced.length,
skipped: result.skipped.length,
failed: result.failed.length,
totalErrors
});
}
}
export {
adkKbSync
};