UNPKG

@botpress/adk-cli

Version:

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

356 lines (354 loc) 12.4 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 { findAgentRootOrFail } from "./chunk-kk3h6qaj.js"; import { createCliLogger } from "./chunk-gzwt1qdr.js"; import"./chunk-nxy2ya5r.js"; import"./chunk-wzj4dc7n.js"; import { AdkError, AgentProject, AssetsManager } 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-assets.ts async function adkAssetsSync(options) { ensureJsonOnlyFormat(options?.format); const isJson = options?.format === "json"; const logger = createCliLogger({ format: options?.format }); if (isJson && !options?.yes) { throw new AdkError({ code: "JSON_REQUIRES_YES", message: "--format json requires --yes flag", expected: true }); } const context = await resolveCommandContext({ target: "prod", require: ["project", "credentials", "workspace", "bot"] }); const project = context.project; const assetsManager = new AssetsManager({ projectPath: project.path, botId: context.botId, credentials: context.credentials }); logger.info(`\uD83D\uDD04 Syncing assets... `); await assertValidProject(project); if (!await assetsManager.hasAssetsDirectory()) { logger.info("\uD83D\uDCC1 No assets directory found. Nothing to sync.").result({ success: true, created: 0, updated: 0, deleted: 0, failed: 0 }); return; } const plan = await assetsManager.createSyncPlan(); if (!plan.hasChanges) { logger.info("\u2705 All assets are up to date.").result({ success: true, created: 0, updated: 0, deleted: 0, failed: 0 }); return; } logger.info(`\uD83D\uDCCB Asset sync plan: `); if (plan.totalCreate > 0) { logger.info(`Files to upload (${plan.totalCreate}):`, "green"); for (const item of plan.items) { if (item.operation === "create" && item.localFile) { const size = formatFileSize(item.localFile.size); logger.info(` + ${item.localFile.relativePath} (${size})`, "green"); } } logger.newline(); } if (plan.totalUpdate > 0) { logger.warn(`Files to update (${plan.totalUpdate}):`); for (const item of plan.items) { if (item.operation === "update" && item.localFile) { const size = formatFileSize(item.localFile.size); logger.warn(` ~ ${item.localFile.relativePath} (${size}) - ${item.reason}`); } } logger.newline(); } if (plan.totalDelete > 0) { logger.error(`Files to delete (${plan.totalDelete}):`); for (const item of plan.items) { if (item.operation === "delete" && item.remoteFile) { const size = formatFileSize(item.remoteFile.size); logger.error(` - ${item.remoteFile.path} (${size}) - ${item.reason}`); } } logger.newline(); } if (options?.dryRun) { logger.info("\uD83D\uDD0D Dry run mode - no changes will be applied.", "blue").result({ success: true, dryRun: true, toCreate: plan.totalCreate, toUpdate: plan.totalUpdate, toDelete: plan.totalDelete }); return; } if (!options?.yes) { const { promptYesNo } = await import("./chunk-6afthdr4.js"); if (!await promptYesNo("Apply these changes? (y/N): ", process.stdout)) { logger.info("\u274C Sync cancelled."); return; } } const syncOptions = { dryRun: false, confirmDestructive: true, bailOnFailure: options?.bailOnFailure, force: options?.force }; logger.info("\u23F3 Applying changes..."); const result = await assetsManager.executeSync(plan, syncOptions); logger.info(` \uD83D\uDCCA Sync results:`); logger.info(`\u2705 Created: ${result.summary.created}`); logger.info(`\uD83D\uDD04 Updated: ${result.summary.updated}`); logger.info(`\uD83D\uDDD1\uFE0F Deleted: ${result.summary.deleted}`); if (result.summary.failed > 0) { logger.error(`\u274C Failed: ${result.summary.failed}`); logger.error(` Errors:`); for (const failure of result.failed) { const file = failure.item.localFile?.relativePath || failure.item.remoteFile?.path || "unknown"; logger.error(` \u2022 ${file}: ${failure.error.message}`); } } if (result.summary.failed === 0) { logger.info(` \uD83C\uDF89 Assets synced successfully!`, "green").result({ success: true, created: result.summary.created, updated: result.summary.updated, deleted: result.summary.deleted, failed: 0 }); } else { logger.warn(` \u26A0\uFE0F Sync completed with some errors.`).result({ success: false, created: result.summary.created, updated: result.summary.updated, deleted: result.summary.deleted, failed: result.summary.failed }); throw new AdkError({ code: "ASSET_SYNC_FAILED", message: `${result.summary.failed} asset(s) failed to sync` }); } } async function adkAssetsList(options) { ensureJsonOnlyFormat(options?.format); const logger = createCliLogger({ format: options?.format }); logger.info(`\uD83D\uDCCB Listing assets... `); const agentRoot = await findAgentRootOrFail(process.cwd()); const project = await AgentProject.load(agentRoot); await assertValidProject(project); const showLocal = !options?.remote; const showRemote = !options?.local; const hasBotId = !!project.agentInfo?.botId; const remoteContext = showRemote && hasBotId ? await resolveCommandContext({ target: "prod", require: ["project", "credentials", "workspace", "bot"] }) : undefined; const assetsManager = new AssetsManager({ projectPath: project.path, botId: remoteContext?.botId ?? project.agentInfo?.botId, credentials: remoteContext?.credentials }); if (showRemote && !hasBotId) { logger.warn("\u26A0\uFE0F Cannot list remote assets without bot ID."); logger.info(` Deploy your agent first or create agent.json to view remote assets. `, "gray"); if (!showLocal) { logger.info("No remote assets available.").result({ remote: [] }); return; } } const result = {}; if (showLocal) { const localAssets = await assetsManager.getLocalAssets(); result.local = localAssets.map((a) => ({ path: a.relativePath, size: a.size })); logger.info("\uD83D\uDCC1 Local assets:"); if (localAssets.length === 0) { logger.info(` No local assets found. `); } else { for (const asset of localAssets) { const size = formatFileSize(asset.size); const mtime = asset.stats.mtime.toISOString().split("T")[0]; logger.info(` \uD83D\uDCC4 ${asset.relativePath} (${size}, ${mtime})`); } logger.info(` Total: ${localAssets.length} files `); } } if (showRemote && hasBotId) { const remoteAssets = await assetsManager.getRemoteAssets(); result.remote = remoteAssets.map((a) => ({ path: a.path, size: a.size, updatedAt: a.updatedAt })); logger.info("\u2601\uFE0F Remote assets:"); if (remoteAssets.length === 0) { logger.info(` No remote assets found. `); } else { for (const asset of remoteAssets) { const size = formatFileSize(asset.size); const updated = new Date(asset.updatedAt).toISOString().split("T")[0]; logger.info(` \uD83D\uDCC4 ${asset.path} (${size}, ${updated})`); } logger.info(` Total: ${remoteAssets.length} files `); } } else if (showRemote) { result.remote = []; } logger.info("\uD83D\uDCCB Asset listing complete.").result(result); } async function adkAssetsStatus(options) { ensureJsonOnlyFormat(options?.format); const logger = createCliLogger({ format: options?.format }); logger.info(`\uD83D\uDCCA Assets status... `); const agentRoot = await findAgentRootOrFail(process.cwd()); const project = await AgentProject.load(agentRoot); await assertValidProject(project); let assetsManager = new AssetsManager({ projectPath: project.path, botId: project.agentInfo?.botId }); if (!await assetsManager.hasAssetsDirectory()) { logger.info("\uD83D\uDCC1 No assets directory found.").result({ localCount: 0, remoteCount: 0, hasChanges: false, toCreate: 0, toUpdate: 0, toDelete: 0 }); return; } if (!project.agentInfo?.botId) { const localAssets = await assetsManager.getLocalAssets(); logger.warn("\u26A0\uFE0F Cannot check remote status without bot ID."); logger.info(` Deploy your agent first or create agent.json. `, "gray"); logger.info(`\uD83D\uDCC1 Local assets: ${localAssets.length} files`); logger.info('\uD83D\uDCA1 Run "adk assets sync" after deployment to synchronize with remote.', "blue").result({ localCount: localAssets.length, remoteCount: 0, hasChanges: false, toCreate: 0, toUpdate: 0, toDelete: 0 }); return; } const context = await resolveCommandContext({ target: "prod", require: ["project", "credentials", "workspace", "bot"] }); assetsManager = new AssetsManager({ projectPath: context.project.path, botId: context.botId, credentials: context.credentials }); const plan = await assetsManager.createSyncPlan(); logger.info(`\uD83D\uDCC1 Local assets: ${plan.items.filter((i) => i.localFile).length} files`); logger.info(`\u2601\uFE0F Remote assets: ${plan.items.filter((i) => i.remoteFile).length} files`); logger.newline(); const statusResult = { localCount: plan.items.filter((i) => i.localFile).length, remoteCount: plan.items.filter((i) => i.remoteFile).length, hasChanges: plan.hasChanges, toCreate: plan.totalCreate, toUpdate: plan.totalUpdate, toDelete: plan.totalDelete }; if (plan.hasChanges) { logger.info("\uD83D\uDCCB Changes needed:"); if (plan.totalCreate > 0) { logger.info(` + ${plan.totalCreate} files to upload`, "green"); } if (plan.totalUpdate > 0) { logger.warn(` ~ ${plan.totalUpdate} files to update`); } if (plan.totalDelete > 0) { logger.error(` - ${plan.totalDelete} files to delete`); } logger.info(` Run "adk assets sync" to apply changes.`, "blue").result(statusResult); } else { logger.info("\u2705 All assets are synchronized.", "green").result(statusResult); } } async function adkAssetsPull() { const logger = createCliLogger(); try { logger.info(`\u2B07\uFE0F Pulling remote assets... `); const context = await resolveCommandContext({ target: "prod", require: ["project", "credentials", "workspace", "bot"] }); const project = context.project; await assertValidProject(project); const assetsManager = new AssetsManager({ projectPath: project.path, botId: context.botId, credentials: context.credentials }); const remoteAssets = await assetsManager.getRemoteAssets(); if (remoteAssets.length === 0) { logger.info("No remote assets to pull."); return; } logger.info(`Found ${remoteAssets.length} remote assets.`); logger.info("\u26A0\uFE0F Note: This feature is not yet implemented."); logger.info(" Remote asset downloading will be added in a future version."); } catch (error) { logger.error("\u274C Failed to pull assets:"); throw error; } } function formatFileSize(bytes) { if (bytes === 0) return "0 B"; const k = 1024; const sizes = ["B", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i]; } export { adkAssetsSync, adkAssetsStatus, adkAssetsPull, adkAssetsList };