@botpress/adk-cli
Version:
Command-line interface for the Botpress Agent Development Kit (ADK)
356 lines (354 loc) • 12.4 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 {
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
};