// @bun
import {
  displayWorkspaceInfo
} from "./chunk-xspapn3f.js";
import {
  buildAndUploadComponents,
  publishProdMetadata
} from "./chunk-nkq9jxh8.js";
import {
  adkBuild
} from "./chunk-gat1vdwz.js";
import"./chunk-1kgmzwze.js";
import"./chunk-4wmnzrst.js";
import"./chunk-rkjpw96h.js";
import"./chunk-62hm2spv.js";
import {
  ensureJsonOnlyFormat
} from "./chunk-5zqmmchg.js";
import"./chunk-7zvmmxnc.js";
import {
  identifyUser
} from "./chunk-w4a48hxy.js";
import {
  telemetry_default
} from "./chunk-c18d2qwm.js";
import"./chunk-p4n31dgt.js";
import {
  resolveCommandContext
} from "./chunk-2jcqy5j6.js";
import {
  ADK_LOGO_LINE1,
  ADK_LOGO_LINE2
} from "./chunk-9e2nksab.js";
import"./chunk-m2h26j5f.js";
import"./chunk-8gqzjqmb.js";
import"./chunk-6fad0ts7.js";
import {
  createCliLogger,
  source_default
} from "./chunk-t993tmz7.js";
import {
  sanitizeErrorMessage
} from "./chunk-px7fts59.js";
import {
  AdkError,
  BpDeployCommand,
  PreflightChecker,
  SecretsManager,
  isAdkError,
  pluralize2
} from "./chunk-7krp2mgz.js";
import"./chunk-np5wcwfv.js";
import"./chunk-je8v6rhj.js";
import"./chunk-6w0knnta.js";
import"./chunk-w15xmtkn.js";
import"./chunk-3sd5p4qp.js";
import"./chunk-nh2akp42.js";
import"./chunk-kat1bv74.js";
import"./chunk-2a5b6azq.js";
import"./chunk-s8cp3qe6.js";
import"./chunk-fv5teh9w.js";
import"./chunk-8ab2w9a1.js";
import"./chunk-3xrpxgq4.js";
import"./chunk-w346ejn9.js";
import"./chunk-n8gath4k.js";
import"./chunk-v3ens42y.js";
import"./chunk-8839jtgk.js";
import"./chunk-s2akeqpw.js";
import"./chunk-6771vrjp.js";
import"./chunk-g8mm42v1.js";
import"./chunk-0q5d80bn.js";
import"./chunk-300xaact.js";
import"./chunk-b8c41yvb.js";
import"./chunk-jsqe5am4.js";
import"./chunk-m4c14gcg.js";
import"./chunk-gspjbr79.js";
import"./chunk-wesykvkp.js";
import"./chunk-gzj56z73.js";
import {
  __require
} from "./chunk-dhs2bg35.js";

// src/commands/adk-deploy.ts
import path from "path";

// src/utils/preflight-formatter.ts
var purple = source_default.hex("#D2A6FF");
function formatValue(value) {
  if (value === undefined || value === null) {
    return source_default.gray("(not set)");
  }
  if (typeof value === "string") {
    return `"${value}"`;
  }
  if (typeof value === "boolean") {
    return value ? source_default.green("true") : source_default.red("false");
  }
  if (Array.isArray(value)) {
    return `[${value.map((v) => formatValue(v)).join(", ")}]`;
  }
  if (typeof value === "object") {
    return JSON.stringify(value);
  }
  return String(value);
}
function pushSecretWarnings(lines, warnings, env) {
  const required = warnings.filter((w) => !w.optional);
  const optional = warnings.filter((w) => w.optional);
  const flag = env === "prod" ? " --prod" : "";
  const label = env === "prod" ? " (prod)" : "";
  lines.push(source_default.bold.yellow(`Missing Secrets${label}`) + `
`);
  if (required.length > 0) {
    lines.push(source_default.red("  Required (must be set before use):") + `
`);
    for (const warning of required) {
      const desc = warning.description ? `: ${warning.description}` : "";
      lines.push(`    \u2014 ${warning.name}${desc}`);
      lines.push(`      ${source_default.gray("Set with:")} ${source_default.cyan(`adk secret:set ${warning.name}${flag}`)}
`);
    }
  }
  if (optional.length > 0) {
    lines.push(source_default.yellow("  Optional (can be set later):") + `
`);
    for (const warning of optional) {
      const desc = warning.description ? `: ${warning.description}` : "";
      lines.push(`    \u2014 ${warning.name}${desc}`);
      lines.push(`      ${source_default.gray("Set with:")} ${source_default.cyan(`adk secret:set ${warning.name}${flag}`)}
`);
    }
  }
  if (env === "dev") {
    lines.push(source_default.gray("  For local development, export SECRET_<NAME>=... in your environment."));
  }
  lines.push(source_default.gray("  Never commit .env files containing secrets to version control.") + `
`);
}

class PreflightFormatter {
  static format(result) {
    const lines = [];
    lines.push("");
    lines.push(purple(` ${ADK_LOGO_LINE1}  Botpress ADK`));
    lines.push(purple(` ${ADK_LOGO_LINE2}  Preflight Check`));
    lines.push("");
    lines.push(purple("Running preflight checks..."));
    lines.push("");
    if (result.agentConfig.length > 0) {
      lines.push(source_default.bold("Agent Configuration Differences"));
      lines.push(source_default.gray("(These are top-level agent settings)") + `
`);
      for (const diff of result.agentConfig) {
        lines.push(`  agent.${diff.field}:`);
        lines.push(`    ${source_default.red(`- Remote:  ${formatValue(diff.oldValue)}`)}`);
        lines.push(`    ${source_default.green(`+ Local:   ${formatValue(diff.newValue)}`)}
`);
      }
    }
    if (result.secretWarnings && result.secretWarnings.length > 0) {
      pushSecretWarnings(lines, result.secretWarnings, result.env);
    }
    lines.push(source_default.bold("Summary of Actions") + `
`);
    const agentConfig = result.agentConfig.length;
    if (agentConfig > 0) {
      lines.push(`  \u2022 ${source_default.cyan("Agent config:")} ${pluralize2(agentConfig, "change")}`);
    }
    lines.push("");
    return lines.join(`
`);
  }
  static formatPrompt() {
    return source_default.bold.red(`\u2753 Apply these changes before continuing?
`) + source_default.gray(`[y] apply  \xB7  [n] deploy without applying  \xB7  [Esc] cancel deployment
`) + source_default.gray("Proceed? [y/N] ");
  }
}

// src/commands/adk-deploy.ts
var ANSI_RE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
var PROGRESS_PREFIXES = ["\u25CB", "\u2714", "\u2713", "\u256D", "\u2502", "\u2570"];
function extractDeployErrorMessage(error) {
  if (!(error instanceof Error)) {
    return String(error);
  }
  const extra = error;
  if (typeof extra.stderr === "string" && extra.stderr.trim()) {
    const lines = extra.stderr.trim().split(`
`);
    for (let i = lines.length - 1;i >= 0; i--) {
      const line = lines[i].replace(ANSI_RE, "").trim();
      if (line && !PROGRESS_PREFIXES.some((p) => line.startsWith(p))) {
        return line;
      }
    }
  }
  return error.message;
}
function formatDeployPlan(plan, logger, options) {
  const hint = options?.showConfirmHints ? " (requires --confirm-storage-changes)" : "";
  if (plan.preflight.result.hasChanges) {
    logger.info(PreflightFormatter.format(plan.preflight.result));
  }
  if (plan.tablePlan?.hasChanges) {
    logger.info(`
\uD83D\uDCCA Tables:`, "cyan");
    if (plan.tablePlan.totalCreate > 0)
      logger.info(`  \u2022 ${plan.tablePlan.totalCreate} to create`, "green");
    if (plan.tablePlan.totalUpdate > 0)
      logger.info(`  \u2022 ${plan.tablePlan.totalUpdate} to update`, "cyan");
    if (plan.tablePlan.totalDelete > 0)
      logger.warn(`  \u2022 ${plan.tablePlan.totalDelete} to delete${hint}`);
  }
  if (plan.kbPlan?.hasChanges) {
    logger.info(`
\uD83D\uDCDA Knowledge bases:`, "cyan");
    logger.info(`  \u2022 ${plan.kbPlan.toSync} to sync, ${plan.kbPlan.toSkip} up to date`);
    if (plan.kbPlan.orphanedSourcesToDelete > 0) {
      logger.warn(`  \u2022 ${plan.kbPlan.orphanedSourcesToDelete} orphaned sources to remove${hint}`);
    }
  }
  if (plan.orphanedKBs.length > 0) {
    logger.warn(`
\u26A0\uFE0F  ${plan.orphanedKBs.length} remote KB(s) not defined locally:`);
    for (const kb of plan.orphanedKBs) {
      logger.warn(`   \u2022 ${kb.name}`);
    }
    if (options?.showConfirmHints) {
      logger.warn(`   Requires --confirm-storage-changes to delete`);
    }
  }
  if (plan.assetPlan?.hasChanges) {
    logger.info(`
\uD83D\uDCC1 Assets:`, "cyan");
    if (plan.assetPlan.totalCreate > 0)
      logger.info(`  \u2022 ${plan.assetPlan.totalCreate} to upload`, "green");
    if (plan.assetPlan.totalUpdate > 0)
      logger.info(`  \u2022 ${plan.assetPlan.totalUpdate} to update`, "cyan");
    if (plan.assetPlan.totalDelete > 0)
      logger.warn(`  \u2022 ${plan.assetPlan.totalDelete} to delete${hint}`);
  }
}
async function promptUserApproval() {
  const { promptApproval } = await import("./chunk-6afthdr4.js");
  return promptApproval(PreflightFormatter.formatPrompt(), process.stdout);
}
async function adkDeploy(environment = "production", options = {}) {
  ensureJsonOnlyFormat(options.format);
  const isJson = options.format === "json";
  const logger = createCliLogger({ format: options.format });
  if (isJson && !options.autoApprove && !options.dryRun) {
    throw new AdkError({
      code: "JSON_REQUIRES_YES",
      message: "--format json requires --yes or --dry-run flag",
      expected: true
    });
  }
  logger.info("\uD83D\uDE80 Deploying ADK agent to Botpress...", "blue");
  logger.info(`Environment: ${environment}`, "gray");
  let stage = "auth";
  try {
    stage = "load";
    const context = await resolveCommandContext({
      target: "prod",
      projectLoadOptions: { adkCommand: "adk-deploy" },
      require: ["project", "credentials", "workspace", "bot"]
    });
    const agentRoot = context.agentRoot;
    const project = context.project;
    const botId = context.botId;
    const workspaceId = context.workspaceId;
    const credentials = context.credentials;
    const client = context.client;
    await identifyUser(agentRoot).catch(() => {});
    if (!isJson) {
      await displayWorkspaceInfo({ context });
    }
    stage = "build";
    logger.info(`
\uD83C\uDFD7\uFE0F  Building agent project...`, "cyan");
    await adkBuild({
      silent: true,
      adkCommand: "adk-deploy",
      beforeGenerate: project.customComponents.length > 0 ? async () => {
        logger.info(`
\uD83E\uDDE9 Building and uploading custom components...`, "cyan");
        await buildAndUploadComponents({
          agentRoot,
          project,
          client,
          log: (msg) => logger.info(`  ${msg}`, "gray")
        });
      } : undefined
    });
    stage = "config";
    logger.info(`
\uD83D\uDD27 Validating configuration...`, "cyan");
    try {
      const { validateAndPromptConfig } = await import("./chunk-z9ppk3st.js");
      const configResult = await validateAndPromptConfig({
        projectPath: agentRoot,
        isProd: true,
        interactive: !isJson,
        botId,
        project,
        credentials,
        client
      });
      if (!configResult.valid) {
        logger.error(`
\u2717 Configuration validation failed:`);
        configResult.errors.forEach((err) => logger.error(`  \u2022 ${err}`));
        throw new AdkError({
          code: "CONFIG_VALIDATION_FAILED",
          message: "Configuration validation failed",
          expected: true,
          details: { errors: configResult.errors }
        });
      }
      logger.info(`\u2713 Configuration validated
`, "green");
    } catch (error) {
      if (!(isAdkError(error) && error.code === "INVALID_CONFIG_SCHEMA")) {
        throw error;
      }
    }
    stage = "preflight";
    logger.info("\uD83D\uDD0D Computing deploy plan...", "cyan");
    const checker = new PreflightChecker(agentRoot, { credentials });
    const plan = await checker.computeDeployPlan(botId);
    const hasAnyChanges = plan.preflight.result.hasChanges || plan.tablePlan?.hasChanges || plan.kbPlan?.hasChanges || plan.orphanedKBs.length > 0 || plan.assetPlan?.hasChanges;
    if (options.dryRun) {
      if (isJson) {
        const jsonPlan = {
          preflight: {
            hasChanges: plan.preflight.result.hasChanges,
            agentConfig: plan.preflight.result.agentConfig,
            secretWarnings: plan.preflight.result.secretWarnings
          },
          tables: plan.tablePlan ? {
            hasChanges: plan.tablePlan.hasChanges,
            totalCreate: plan.tablePlan.totalCreate,
            totalUpdate: plan.tablePlan.totalUpdate,
            totalDelete: plan.tablePlan.totalDelete
          } : null,
          knowledgeBases: plan.kbPlan ? {
            hasChanges: plan.kbPlan.hasChanges,
            toSync: plan.kbPlan.toSync,
            toSkip: plan.kbPlan.toSkip,
            orphanedKBs: plan.orphanedKBs.map((kb) => kb.name)
          } : null,
          assets: plan.assetPlan ? {
            hasChanges: plan.assetPlan.hasChanges,
            totalCreate: plan.assetPlan.totalCreate,
            totalUpdate: plan.assetPlan.totalUpdate,
            totalDelete: plan.assetPlan.totalDelete
          } : null,
          hasDestructiveStorageChanges: plan.hasDestructiveStorageChanges
        };
        logger.info("").result(jsonPlan);
      } else {
        formatDeployPlan(plan, logger, { showConfirmHints: true });
        if (plan.hasDestructiveStorageChanges) {
          logger.warn(`
Destructive storage changes require: --confirm-storage-changes`);
        }
        logger.info(`
\uD83D\uDD0D Dry run \u2014 no changes applied.`);
      }
      return;
    }
    let interactivelyApproved = false;
    let planApproved = true;
    if (hasAnyChanges) {
      formatDeployPlan(plan, logger);
      if (options.autoApprove) {
        if (plan.hasDestructiveStorageChanges && !options.confirmStorageChanges) {
          logger.error(`
\u2717 Destructive storage changes require explicit confirmation:`);
          logger.error(`   --confirm-storage-changes`);
          throw new AdkError({
            code: "STORAGE_CONFIRM_REQUIRED",
            message: "Destructive storage changes require --confirm-storage-changes",
            expected: true
          });
        }
        logger.info(`
\u2713 Auto-approved. Applying changes...
`, "green");
      } else {
        const choice = await promptUserApproval();
        if (choice === "cancel") {
          logger.error(`
\u2717 Deployment cancelled by user.
`);
          return;
        }
        if (choice === "yes") {
          interactivelyApproved = true;
        } else {
          planApproved = false;
          logger.warn(`
\u26A0\uFE0F  Plan updates declined \u2014 deploying the bot code without applying these changes.`);
          logger.warn("   Your bot may not work as expected until the plan updates are applied.");
          logger.warn("   Re-run `adk deploy` and approve the plan to apply them.\n");
        }
      }
    } else {
      logger.info(`\u2713 No changes detected. Proceeding...
`, "gray");
    }
    if (planApproved && plan.preflight.result.hasChanges) {
      await plan.preflight.apply({
        onProgress: (msg) => logger.info(`\uD83D\uDD04 ${msg}`, "cyan"),
        onSuccess: (msg) => logger.info(`\u2705 ${msg}`, "green"),
        onError: (msg) => logger.error(`\u274C ${msg}`)
      });
    }
    stage = "secrets";
    const declaredSecrets = project.config?.secrets ?? {};
    const secretsManager = new SecretsManager(project.path);
    const prodSecrets = await secretsManager.getAll("prod", declaredSecrets);
    const missingRequired = Object.entries(declaredSecrets).filter(([name, def]) => !def.optional && !(name in prodSecrets)).map(([name]) => name);
    if (missingRequired.length > 0) {
      throw new AdkError({
        code: "MISSING_SECRETS",
        message: `Missing required prod secrets: ${missingRequired.join(", ")}
Set them with: ${missingRequired.map((n) => `adk secret:set ${n} <value> --prod`).join(", ")}`,
        expected: true
      });
    }
    stage = "deploy";
    const botPath = path.join(project.path, ".adk", "bot");
    logger.info(`
\uD83D\uDCE4 Deploying bot to Botpress...`, "cyan");
    const deployCommand = new BpDeployCommand({
      botPath,
      botId,
      workspaceId,
      credentials,
      secrets: Object.keys(prodSecrets).length > 0 ? prodSecrets : undefined
    });
    if (!isJson) {
      deployCommand.on("stdout", (data) => logger.stdout(data));
      deployCommand.on("stderr", (data) => logger.stderr(data));
    }
    await deployCommand.run();
    await deployCommand.output();
    logger.info(`
\u2705 Agent deployed successfully!`, "green");
    logger.info(`\uD83C\uDF10 Your agent is now live on Botpress`, "gray");
    logger.info(`\uD83E\uDD16 Bot ID: ${botId}`, "gray");
    logger.info(`\uD83C\uDFE2 Workspace ID: ${workspaceId}`, "gray");
    stage = "manifest";
    logger.info(`
\uD83E\uDDFE Publishing prod metadata...`, "cyan");
    try {
      const result = await publishProdMetadata({ project, client, botId });
      if (result.agentMapSnapshotWarning) {
        logger.warn(`\u26A0\uFE0F  Failed to publish Agent Map metadata: ${result.agentMapSnapshotWarning}`);
        logger.warn("   Redeploy again to retry publishing Agent Map metadata.");
      }
      logger.info("\u2705 Prod metadata published", "green");
    } catch (err) {
      logger.warn(`\u26A0\uFE0F  Failed to publish prod metadata: ${err instanceof Error ? err.message : String(err)}`);
      logger.warn("   The bot was deployed. Run deploy again to retry publishing prod metadata.");
    }
    telemetry_default.track("deploy", {
      success: true,
      botId,
      workspaceId,
      environment,
      autoApproved: options.autoApprove,
      planDeclined: hasAnyChanges ? !planApproved : undefined,
      primitive_count: project.actions.length + project.workflows.length + project.conversations.length + project.triggers.length + project.tables.length
    });
    const confirmStorage = interactivelyApproved || (options.confirmStorageChanges ?? false);
    stage = "kb-sync";
    let kbSyncFailed = false;
    if (planApproved && plan.orphanedKBs.length > 0 && confirmStorage && plan.managers.kb) {
      try {
        for (const kb of plan.orphanedKBs) {
          logger.warn(`  \uD83D\uDDD1\uFE0F  Deleting orphaned KB "${kb.name}"...`);
          const { deletedFiles } = await plan.managers.kb.deleteKnowledgeBase(kb.id, kb.name);
          logger.info(`     Deleted ${deletedFiles} files`, "gray");
        }
      } catch (err) {
        kbSyncFailed = true;
        logger.error(`\u274C Failed to delete orphaned KBs: ${err instanceof Error ? err.message : String(err)}`);
      }
    }
    if (planApproved && plan.kbPlan?.hasChanges && plan.managers.kb) {
      logger.info(`
\uD83D\uDCDA Syncing knowledge bases...`, "cyan");
      try {
        const kbResult = await plan.managers.kb.executeSync(plan.kbPlan, { confirmDestructive: confirmStorage });
        for (const item of kbResult.synced) {
          const stats = [];
          if (item.result.added.length > 0)
            stats.push(`${item.result.added.length} added`);
          if (item.result.updated.length > 0)
            stats.push(`${item.result.updated.length} updated`);
          if (item.result.deleted.length > 0)
            stats.push(`${item.result.deleted.length} deleted`);
          logger.info(`  \u2705 KB "${item.name}" synced: ${stats.join(", ") || "no file changes"}`, "green");
        }
        for (const item of kbResult.skipped) {
          logger.info(`  \u23ED\uFE0F  KB "${item.name}" skipped: ${item.reason}`, "gray");
        }
        for (const item of kbResult.failed) {
          kbSyncFailed = true;
          logger.error(`  \u274C KB "${item.name}" failed: ${item.error}`);
        }
      } catch (err) {
        kbSyncFailed = true;
        logger.error(`\u274C Failed to sync knowledge bases: ${err instanceof Error ? err.message : String(err)}`);
      }
    }
    stage = "tables";
    let tableSyncFailed = false;
    if (planApproved && plan.tablePlan?.hasChanges) {
      logger.info(`
\uD83D\uDCCA Syncing tables...`, "cyan");
      try {
        const syncResult = await plan.managers.table.executeSync(plan.tablePlan, {
          confirmDestructive: confirmStorage
        });
        if (syncResult.summary.created > 0)
          logger.info(`  \u2705 Created ${syncResult.summary.created} tables`, "green");
        if (syncResult.summary.updated > 0)
          logger.info(`  \u2705 Updated ${syncResult.summary.updated} tables`, "green");
        if (syncResult.summary.deleted > 0)
          logger.info(`  \u2705 Deleted ${syncResult.summary.deleted} tables`, "green");
        if (syncResult.summary.skipped > 0) {
          logger.warn(`  \u26A0\uFE0F  ${syncResult.summary.skipped} table(s) retained (not deleted)`);
        }
        if (syncResult.summary.failed > 0) {
          tableSyncFailed = true;
          logger.error(`  \u274C Failed to sync ${syncResult.summary.failed} tables`);
          syncResult.failed.forEach(({ item, error }) => {
            logger.error(`     \u2022 ${item.localTable?.name || item.remoteTable?.name}: ${error.message}`);
          });
        }
      } catch (err) {
        tableSyncFailed = true;
        logger.error(`\u274C Failed to sync tables: ${err instanceof Error ? err.message : String(err)}`);
      }
    }
    stage = "assets";
    let assetsSyncFailed = false;
    if (planApproved && plan.assetPlan?.hasChanges) {
      logger.info(`
\uD83D\uDCC1 Syncing assets...`, "cyan");
      try {
        const assetResult = await plan.managers.assets.executeSync(plan.assetPlan, {
          confirmDestructive: confirmStorage
        });
        if (assetResult.summary.created > 0)
          logger.info(`  \u2705 Uploaded ${assetResult.summary.created} assets`, "green");
        if (assetResult.summary.updated > 0)
          logger.info(`  \u2705 Updated ${assetResult.summary.updated} assets`, "green");
        if (assetResult.summary.deleted > 0)
          logger.info(`  \u2705 Deleted ${assetResult.summary.deleted} assets`, "green");
        if (assetResult.summary.skipped > 0) {
          logger.warn(`  \u26A0\uFE0F  ${assetResult.summary.skipped} asset(s) retained (not deleted)`);
        }
        if (assetResult.summary.failed > 0) {
          assetsSyncFailed = true;
          logger.error(`  \u274C Failed to sync ${assetResult.summary.failed} assets`);
        }
      } catch (err) {
        assetsSyncFailed = true;
        logger.error(`\u274C Failed to sync assets: ${err instanceof Error ? err.message : String(err)}`);
      }
    }
    if (!planApproved) {
      logger.warn("\n\u26A0\uFE0F  Plan updates were not applied \u2014 run `adk deploy` again and approve to sync your config, tables, KBs, and assets.");
    }
    const deploySuccess = !kbSyncFailed && !tableSyncFailed && !assetsSyncFailed;
    logger.info("\uD83C\uDF89 Deployment complete.").result({ success: deploySuccess, botId, workspaceId, environment });
  } catch (error) {
    if (error instanceof Error) {
      const annotated = error;
      annotated.stage = stage;
      if (stage === "deploy") {
        annotated.detail = sanitizeErrorMessage(extractDeployErrorMessage(error));
      }
    }
    throw error;
  }
}
export {
  adkDeploy
};
