UNPKG

@botpress/adk-cli

Version:

Command-line interface for the Botpress Agent Development Kit (ADK)

325 lines (323 loc) 11.9 kB
// @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 };