UNPKG

deco-cli

Version:

CLI for managing decocms.com apps & projects

6,463 lines 217 kB
import { deleteSession, getLocal, readSession, getConfig, readWranglerConfig, getAppDomain, setToken, DECO_CMS_API_LOCAL, setLocal, AUTH_PORT_CLI, createClient, saveSession, DECO_CMS_LOGIN_URL, writeWranglerConfig, createWorkspaceClient, createWorkspaceClientStub, writeConfigFile, getMCPConfig, workspaceClientParams, getAppUUID, getMCPConfigVersion, getRulesConfig, getConfigFilePath } from './chunk-KFMYHDGF.js';
import process28 from 'process';
import { Command } from 'commander';
import fs11, { writeFile, readFile } from 'fs/promises';
import { spawn } from 'child_process';
import { promises, watch, existsSync, mkdirSync, writeFileSync, readFileSync, statSync, unlinkSync, createReadStream, createWriteStream } from 'fs';
import path2, { dirname, join, relative, resolve, posix, isAbsolute } from 'path';
import { createServer } from 'http';
import { fileURLToPath, URL as URL$1 } from 'url';
import inquirer6 from 'inquirer';
import inquirerSearchList from 'inquirer-search-list';
import { z } from 'zod';
import inquirerSearchCheckbox from 'inquirer-search-checkbox';
import { pipeline } from 'stream/promises';
import { compile } from 'json-schema-to-typescript';
import { generateName } from 'json-schema-to-typescript/dist/src/utils.js';
import { MD5 } from 'object-hash';
import prettier from 'prettier';
import { Buffer } from 'buffer';
import chalk5 from 'chalk';
import { connect } from '@deco-cx/warp-node';
import { createServer as createServer$1 } from 'net';
import * as semver from 'semver';
import { glob } from 'glob';
import { homedir } from 'os';
import { createHash } from 'crypto';
import ignore from 'ignore';

var DECONFIG_DIR = ".deconfig";
var HEAD_FILE = "head";
function getDeconfigHeadPath(cwd) {
  const targetCwd = process28.cwd();
  return join(targetCwd, DECONFIG_DIR, HEAD_FILE);
}
function getDeconfigDir(cwd) {
  const targetCwd = process28.cwd();
  return join(targetCwd, DECONFIG_DIR);
}
function ensureDeconfigDir(cwd) {
  const deconfigDir = getDeconfigDir();
  if (!existsSync(deconfigDir)) {
    mkdirSync(deconfigDir, { recursive: true });
  }
}
async function readDeconfigHead(cwd) {
  const headPath = getDeconfigHeadPath();
  try {
    const content = await promises.readFile(headPath, "utf-8");
    const config = JSON.parse(content);
    return config;
  } catch (error) {
    if (error.code === "ENOENT") {
      return null;
    }
    console.warn(
      `Warning: Could not read .deconfig/head file: ${error instanceof Error ? error.message : String(error)}`
    );
    return null;
  }
}
async function writeDeconfigHead(config, cwd) {
  ensureDeconfigDir();
  const headPath = getDeconfigHeadPath();
  try {
    const content = JSON.stringify(config, null, 2);
    await promises.writeFile(headPath, content, "utf-8");
  } catch (error) {
    console.error(
      `\u274C Failed to write .deconfig/head file: ${error instanceof Error ? error.message : String(error)}`
    );
    throw error;
  }
}
var loginCommand = () => {
  return new Promise((resolve3, reject) => {
    let timeout;
    const server = createServer(
      async (req, res) => {
        const url = new URL$1(req.url, `http://localhost:${AUTH_PORT_CLI}`);
        const headers = new Headers();
        for (const [key, value] of Object.entries(req.headers)) {
          if (value) {
            headers.set(key, Array.isArray(value) ? value.join(", ") : value);
          }
        }
        const { client, responseHeaders } = createClient(headers);
        if (url.pathname === "/login/oauth") {
          const credentials = {
            provider: url.searchParams.get("provider") ?? "google",
            options: { redirectTo: new URL$1("/auth/callback/oauth", url).href }
          };
          const { data } = await client.auth.signInWithOAuth(credentials);
          if (data.url) {
            const responseHeadersObj = {};
            responseHeaders.forEach((value, key) => {
              responseHeadersObj[key] = value;
            });
            res.writeHead(302, {
              Location: data.url,
              ...responseHeadersObj
            });
            res.end();
            return;
          }
          res.writeHead(500);
          res.end("Error redirecting to OAuth provider");
          return;
        }
        if (url.pathname === "/auth/callback/oauth") {
          const code = url.searchParams.get("code");
          if (!code) {
            res.writeHead(400);
            res.end("No code found");
            return;
          }
          const { data, error } = await client.auth.exchangeCodeForSession(code);
          if (error || !data?.session) {
            res.writeHead(400);
            res.end(error?.message ?? "Unknown error");
            return;
          }
          try {
            await saveSession(data);
          } catch (e) {
            console.error("Failed to save session data:", e);
          }
          if (timeout) {
            clearTimeout(timeout);
          }
          const html = await fetch(
            "https://admin.decocms.com/local-login-success.html"
          ).then((res2) => res2.text());
          res.writeHead(200, {
            "Content-Type": "text/html"
          });
          res.end(html);
          server.close(() => resolve3());
          return;
        }
        res.writeHead(404);
        res.end("Not found");
      }
    );
    server.listen(AUTH_PORT_CLI, () => {
      const browserCommands = {
        linux: "xdg-open",
        darwin: "open",
        win32: "start",
        freebsd: "xdg-open",
        openbsd: "xdg-open",
        sunos: "xdg-open",
        aix: "open"
      };
      const browser = process28.env.BROWSER ?? browserCommands[process28.platform] ?? "open";
      console.log("\u{1F510} Starting authentication process...");
      console.log("Opening browser for login...\n");
      const command = process28.platform === "win32" && browser === "start" ? spawn("cmd", ["/c", "start", DECO_CMS_LOGIN_URL], {
        detached: true
      }) : spawn(browser, [DECO_CMS_LOGIN_URL], { detached: true });
      command.unref();
      command.on("error", () => {
        console.log("\u26A0\uFE0F  Could not automatically open browser");
      });
      timeout = setTimeout(() => {
        console.log(
          "\u{1F4CB} If your browser didn't open automatically, please click the following link:"
        );
        console.log(`
   ${DECO_CMS_LOGIN_URL}
`);
        console.log("Waiting for authentication to complete...\n");
      }, 1e3);
    });
    server.on("error", (err) => {
      reject(err);
    });
  });
};

// src/commands/auth/whoami.ts
var whoamiCommand = async () => {
  try {
    const session = await readSession();
    if (!session || !session.access_token || !session.refresh_token) {
      console.log("\u274C  Not logged in. Run `deco login` to authenticate.\n");
      return;
    }
    const { client: supabase } = createClient();
    const { error: setSessionError } = await supabase.auth.setSession({
      access_token: session.access_token,
      refresh_token: session.refresh_token
    });
    if (setSessionError) {
      console.log("\u274C  Session expired or invalid. Please log in again.\n");
      return;
    }
    const { data, error } = await supabase.auth.getUser();
    if (error || !data?.user) {
      console.log("\u274C  Could not retrieve user info. Please log in again.\n");
      return;
    }
    const user = data.user;
    console.log("\u{1F464}  User Info:");
    console.log(`   \u{1F4BB}  ID:        ${user.id}`);
    console.log(`   \u{1F4E7}  Email:     ${user.email ?? "-"}`);
    if (user.user_metadata?.full_name) {
      console.log(`   \u{1F4DA}  Name:      ${user.user_metadata.full_name}`);
    }
    if (user.user_metadata?.avatar_url) {
      console.log(`   \u{1F5BC}\uFE0F  Avatar:    ${user.user_metadata.avatar_url}`);
    }
    console.log("");
    if (session.workspace) {
      console.log(
        `\u{1F3E2}  Current Workspace: \x1B[1m${session.workspace}\x1B[0m
`
      );
    } else {
      console.log("\u26A0\uFE0F  No workspace selected.\n");
    }
  } catch (err) {
    const message = typeof err === "object" && err && "message" in err ? err.message : String(err);
    console.error("\u274C  Error reading session:", message);
  }
};
async function promptWorkspace(local = false, current = "") {
  try {
    inquirer6.registerPrompt("search-list", inquirerSearchList);
  } catch {
    console.warn(
      "Could not load search functionality, falling back to basic list"
    );
  }
  const session = await readSession();
  if (!session) {
    throw new Error("No session found. Please run 'deco login' first.");
  }
  const client = await createWorkspaceClient({ workspace: "", local });
  try {
    const response = await client.callTool(
      {
        name: "TEAMS_LIST",
        arguments: {}
      },
      // @ts-expect-error We need to refactor TEAMS_LIST to stop returning array and use a proper object
      z.any()
    );
    if (response.isError) {
      throw new Error("Failed to fetch teams");
    }
    const { items: teams } = response.structuredContent;
    if (!teams || teams.length === 0) {
      throw new Error("No teams found. Please create a team first.");
    }
    const choices = teams.map((team) => ({
      name: team.name,
      value: team.slug
    }));
    let selectedSlug;
    try {
      const result = await inquirer6.prompt([
        {
          type: "search-list",
          name: "selectedSlug",
          message: "Select a workspace:",
          choices,
          default: current
        }
      ]);
      selectedSlug = result.selectedSlug;
    } catch {
      const result = await inquirer6.prompt([
        {
          type: "list",
          name: "selectedSlug",
          message: "Select a workspace:",
          choices,
          default: current
        }
      ]);
      selectedSlug = result.selectedSlug;
    }
    return selectedSlug;
  } finally {
    await client.close();
  }
}

// src/lib/slugify.ts
function slugify(input) {
  return input.toLowerCase().replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
}
function sanitizeConstantName(input) {
  return input.toUpperCase().replace(/[\s_]+/g, "_").replace(/[^A-Z0-9_]/g, "").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
}
inquirer6.registerPrompt("search-checkbox", inquirerSearchCheckbox);
async function promptIntegrations(local = false, workspace = "") {
  const session = await readSession();
  if (!session) {
    throw new Error("No session found. Please run 'deco login' first.");
  }
  const client = await createWorkspaceClient({ workspace, local });
  try {
    const response = await client.callTool(
      {
        name: "INTEGRATIONS_LIST",
        arguments: {}
      },
      // @ts-expect-error We need to refactor INTEGRATIONS_LIST to stop returning array and use a proper object
      z.any()
    );
    if (response.isError) {
      throw new Error("Failed to fetch integrations");
    }
    const integrationsResponse = response.structuredContent?.items;
    const integrations = (integrationsResponse || []).filter((c) => c.connection.type !== "INNATE").sort((a, b) => a.name.localeCompare(b.name));
    if (!integrations || integrations.length === 0) {
      throw new Error("No integrations found.");
    }
    const options = integrations.map((integration) => ({
      name: `${integration.name} - ${integration.description}`,
      value: integration.id,
      short: integration.name
    }));
    const { selectedIntegrationIds } = await inquirer6.prompt([
      {
        type: "search-checkbox",
        name: "selectedIntegrationIds",
        message: "Select integrations (use space to select, enter to confirm):",
        choices: options,
        searchable: true,
        highlight: true,
        searchText: "Type to search integrations:",
        emptyText: "No integrations found matching your search."
      }
    ]);
    const selectedIntegrations = integrations.filter(
      (integration) => selectedIntegrationIds.includes(integration.id)
    );
    return selectedIntegrations.map(({ name, id }) => ({
      name: sanitizeConstantName(name),
      type: "mcp",
      integration_id: id
    }));
  } finally {
    await client.close();
  }
}
async function ensureDir(dirPath) {
  try {
    await promises.mkdir(dirPath, { recursive: true });
  } catch (error) {
    if (error.code !== "EEXIST") {
      throw error;
    }
  }
}
async function copyFile(src, dest) {
  await ensureDir(dirname(dest));
  await pipeline(createReadStream(src), createWriteStream(dest));
}
async function copyDir(src, dest, options = {}) {
  await ensureDir(dest);
  const entries = await promises.readdir(src, { withFileTypes: true });
  for (const entry of entries) {
    const srcPath = join(src, entry.name);
    const destPath = join(dest, entry.name);
    if (entry.isDirectory()) {
      await copyDir(srcPath, destPath, options);
    } else if (entry.isFile()) {
      if (!options.overwrite) {
        try {
          await promises.access(destPath);
          continue;
        } catch {
        }
      }
      await copyFile(srcPath, destPath);
    }
  }
}
async function copy(src, dest, options = {}) {
  const srcStat = await promises.stat(src);
  if (srcStat.isDirectory()) {
    await copyDir(src, dest, options);
  } else if (srcStat.isFile()) {
    if (!options.overwrite) {
      try {
        await promises.access(dest);
        return;
      } catch {
      }
    }
    await copyFile(src, dest);
  } else {
    throw new Error(`Source ${src} is neither a file nor a directory`);
  }
}
async function* walk(root, options = {}) {
  const {
    maxDepth = Infinity,
    includeFiles = true,
    includeDirs = false,
    followSymlinks = false,
    exts,
    match,
    skip
  } = options;
  async function* walkRecursive(dir, depth) {
    if (depth > maxDepth) return;
    let entries;
    try {
      entries = await promises.readdir(dir, { withFileTypes: true });
    } catch {
      return;
    }
    for (const entry of entries) {
      const entryPath = join(dir, entry.name);
      const relativePath = relative(root, entryPath);
      let isFile = entry.isFile();
      let isDirectory = entry.isDirectory();
      const isSymlink = entry.isSymbolicLink();
      if (isSymlink && followSymlinks) {
        try {
          const stat = await promises.stat(entryPath);
          isFile = stat.isFile();
          isDirectory = stat.isDirectory();
        } catch {
          continue;
        }
      } else if (isSymlink && !followSymlinks) {
        continue;
      }
      const walkEntry = {
        path: entryPath,
        name: entry.name,
        isFile,
        isDirectory,
        isSymlink
      };
      if (skip && skip.some((pattern) => pattern.test(relativePath))) {
        continue;
      }
      if (match && !match.some((pattern) => pattern.test(relativePath))) {
        continue;
      }
      if (exts && isFile) {
        const ext = entryPath.substring(entryPath.lastIndexOf(".") + 1);
        if (!exts.includes(ext)) {
          continue;
        }
      }
      if (isFile && includeFiles) {
        yield walkEntry;
      }
      if (isDirectory && includeDirs) {
        yield walkEntry;
      }
      if (isDirectory) {
        yield* walkRecursive(entryPath, depth + 1);
      }
    }
  }
  yield* walkRecursive(root, 0);
}
var IDE_SUPPORT = {
  cursor: {
    name: "Cursor",
    createConfig: async (mcpConfig, projectRoot) => {
      const outDir = join(projectRoot, ".cursor");
      const configs = [];
      const configPath = join(outDir, "mcp.json");
      const existingConfig = await promises.readFile(configPath, "utf-8").then(JSON.parse).catch(() => ({ mcpServers: {} }));
      const config = {
        mcpServers: {
          ...existingConfig.mcpServers || {},
          ...mcpConfig.mcpServers
        }
      };
      configs.push({
        content: JSON.stringify(config, null, 2),
        path: join(outDir, "mcp.json")
      });
      const rules = Object.entries(await getRulesConfig());
      for (const [path4, content] of rules) {
        configs.push({ content, path: join(outDir, "rules", path4) });
      }
      return configs;
    }
  },
  vscode: {
    name: "VS Code",
    createConfig: async (mcpConfig, projectRoot) => {
      const outDir = join(projectRoot, ".vscode");
      const configs = [];
      const configPath = join(outDir, "mcp.json");
      const existingConfig = await promises.readFile(configPath, "utf-8").then(JSON.parse).catch(() => ({ mcpServers: {} }));
      const config = {
        mcpServers: {
          ...existingConfig.mcpServers || {},
          ...mcpConfig.mcpServers
        }
      };
      configs.push({
        content: JSON.stringify(config, null, 2),
        path: join(outDir, "mcp.json")
      });
      const rules = Object.entries(await getRulesConfig());
      for (const [path4, content] of rules) {
        configs.push({ content, path: join(outDir, "rules", path4) });
      }
      return configs;
    }
  }
};
async function writeIDEConfig(configs) {
  const targetDir = dirname(configs[0]?.path ?? "");
  await Promise.all(
    configs.map(async ({ content, path: path4 }) => {
      await ensureDir(dirname(path4));
      await promises.writeFile(path4, content);
    })
  );
  console.log(`\u2705 IDE configuration written to: ${targetDir}`);
}
var setMCPPreferences = async (workspace, app) => {
  const [appUUID, currentVersion] = await Promise.all([
    getAppUUID(workspace, app),
    getMCPConfigVersion()
  ]);
  const prefsPath = join(process28.cwd(), ".deco", "preferences.json");
  try {
    await ensureDir(dirname(prefsPath));
    let prefs = {};
    try {
      prefs = JSON.parse(await promises.readFile(prefsPath, "utf-8"));
    } catch {
    }
    prefs[`mcp-install-version-${appUUID}`] = currentVersion;
    await promises.writeFile(prefsPath, JSON.stringify(prefs, null, 2));
  } catch (error) {
    console.warn("Failed to save MCP preferences:", error);
  }
};
async function promptIDESetup(cfg, projectRoot = process28.cwd()) {
  await setMCPPreferences(cfg.workspace, cfg.app);
  const mcpConfig = getMCPConfig(cfg.workspace, cfg.app);
  const { wantsSentientIDE } = await inquirer6.prompt([
    {
      type: "confirm",
      name: "wantsSentientIDE",
      message: "Would you like to configure your IDE to use this project?",
      default: true
    }
  ]);
  if (!wantsSentientIDE) {
    return null;
  }
  const { selectedIDE } = await inquirer6.prompt([
    {
      type: "list",
      name: "selectedIDE",
      message: "Select your preferred IDE:",
      choices: [
        { name: "Cursor", value: "cursor" },
        { name: "VS Code", value: "vscode" },
        { name: "None", value: "none" }
      ]
    }
  ]);
  const ideSupport = IDE_SUPPORT[selectedIDE];
  if (selectedIDE === "none") {
    return null;
  }
  const configs = await ideSupport.createConfig(mcpConfig, projectRoot);
  return configs;
}

// src/lib/parse-binding-tool.ts
var SEPARATOR = "::";
var parser = {
  fromBindingToolToScope: ({
    bindingName,
    toolName
  }) => {
    const parts = [bindingName, toolName];
    if (parts.some((part) => part.includes(SEPARATOR))) {
      throw new Error(
        `binding name or tool name includes ${SEPARATOR} is not allowed`
      );
    }
    return parts.join(SEPARATOR);
  },
  fromScopeToBindingTool: (scope) => {
    const [bindingName, toolName] = scope.split(SEPARATOR);
    return { bindingName, toolName };
  }
};

// src/commands/gen/gen.ts
var toValidProperty = (property) => {
  return isValidJavaScriptPropertyName(property) ? property : `["${property}"]`;
};
var formatDescription = (desc) => {
  if (!desc) return "";
  return desc.replace(/\*\//g, "*\\/").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => ` * ${line}`).join("\n");
};
function slugify2(name) {
  return name.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function format(content) {
  try {
    return prettier.format(content, {
      parser: "babel-ts",
      plugins: []
    });
  } catch {
    return Promise.resolve(content);
  }
}
var RESERVED_KEYWORDS = [
  "break",
  "case",
  "catch",
  "class",
  "const",
  "continue",
  "debugger",
  "default",
  "delete",
  "do",
  "else",
  "export",
  "extends",
  "finally",
  "for",
  "function",
  "if",
  "import",
  "in",
  "instanceof",
  "let",
  "new",
  "return",
  "super",
  "switch",
  "this",
  "throw",
  "try",
  "typeof",
  "var",
  "void",
  "while",
  "with",
  "yield",
  "enum",
  "await",
  "implements",
  "interface",
  "package",
  "private",
  "protected",
  "public",
  "static",
  "abstract",
  "boolean",
  "byte",
  "char",
  "double",
  "final",
  "float",
  "goto",
  "int",
  "long",
  "native",
  "short",
  "synchronized",
  "throws",
  "transient",
  "volatile",
  "null",
  "true",
  "false",
  "undefined",
  "NaN",
  "Infinity"
];
function isValidJavaScriptPropertyName(name) {
  const validIdentifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
  if (!validIdentifierRegex.test(name)) {
    return false;
  }
  return !RESERVED_KEYWORDS.includes(name);
}
var CONTRACTS_BINDING = "@deco/contracts";
var unwrapMcpResult = (result, opts) => {
  if ("isError" in result && result.isError) {
    const message = (Array.isArray(result.content) ? result.content[0]?.text : void 0) ?? JSON.stringify(result);
    throw new Error(opts?.errorMessage?.(message) ?? message);
  }
  return result;
};
var workspaceSlug = (workspace) => {
  if (workspace.startsWith("/")) {
    return workspace.slice(1).split("/")[1];
  }
  return workspace;
};
var genEnv = async ({
  workspace,
  local,
  bindings,
  selfUrl
}) => {
  const wrangler = await readWranglerConfig();
  const appName = `@${wrangler.scope ?? workspaceSlug(workspace)}/${wrangler.name}`;
  const client = await createWorkspaceClient({ workspace, local });
  const apiClient = await createWorkspaceClient({ local });
  try {
    const types = /* @__PURE__ */ new Map();
    types.set("Env", 1);
    let tsTypes = "";
    const mapBindingTools = {};
    const props = await Promise.all(
      [
        ...bindings,
        ...selfUrl ? [
          {
            name: "SELF",
            type: "mcp",
            integration_url: selfUrl,
            ignoreCache: true
          }
        ] : []
      ].map(async (binding) => {
        let connection;
        let stateKey;
        if ("integration_id" in binding) {
          const integrationResult = await client.callTool({
            name: "INTEGRATIONS_GET",
            arguments: {
              id: binding.integration_id
            }
          });
          const integration = unwrapMcpResult(integrationResult, {
            errorMessage: (error) => `Error getting integration ${binding.integration_id}: ${error}`
          });
          connection = integration.structuredContent.connection;
        } else if ("integration_name" in binding || binding.type === "contract") {
          const [integrationName, type] = "integration_name" in binding ? [binding.integration_name, binding.integration_name] : [CONTRACTS_BINDING, `${appName}-${MD5(binding.contract)}`];
          stateKey = { type, key: binding.name };
          const appResult = await apiClient.callTool({
            name: "REGISTRY_GET_APP",
            arguments: {
              name: integrationName
            }
          });
          const app = unwrapMcpResult(appResult, {
            errorMessage: (error) => `Error getting app ${integrationName}: ${error}`
          });
          connection = app.structuredContent.connection;
        } else if ("integration_url" in binding) {
          connection = {
            type: "HTTP",
            url: binding.integration_url
          };
        } else {
          throw new Error(`Unknown binding type: ${binding}`);
        }
        const tools = await apiClient.callTool({
          name: "INTEGRATIONS_LIST_TOOLS",
          arguments: {
            connection,
            ignoreCache: "ignoreCache" in binding ? binding.ignoreCache : void 0
          }
        });
        if (!Array.isArray(tools.structuredContent?.tools)) {
          console.warn(
            `\u26A0\uFE0F No tools found for integration ${binding.name}. Skipping...`
          );
          return null;
        }
        if ("integration_name" in binding || binding.type === "contract") {
          mapBindingTools[binding.name] = tools.structuredContent.tools.map(
            (t) => t.name
          );
        }
        const compiledTools = await Promise.all(
          tools.structuredContent.tools.map(async (t) => {
            const jsName = generateName(t.name, /* @__PURE__ */ new Set());
            const inputName = `${jsName}Input`;
            const outputName = `${jsName}Output`;
            const customName = (schema) => {
              let typeName = schema.title ?? schema.type;
              if (Array.isArray(typeName)) {
                typeName = typeName.join(",");
              }
              if (typeof typeName !== "string") {
                return void 0;
              }
              const key = slugify2(typeName);
              const count = types.get(key) ?? 0;
              types.set(key, count + 1);
              return count ? `${typeName}_${count}` : typeName;
            };
            const [inputTs, outputTs] = await Promise.all([
              compile({ ...t.inputSchema, title: inputName }, inputName, {
                additionalProperties: false,
                customName,
                format: false
              }),
              t.outputSchema ? await compile(
                { ...t.outputSchema, title: outputName },
                outputName,
                {
                  customName,
                  additionalProperties: false,
                  format: false
                }
              ) : void 0
            ]);
            tsTypes += `
        ${inputTs}
        ${outputTs ?? ""}
          `;
            return [
              t.name,
              inputName,
              outputTs ? outputName : void 0,
              t.description
            ];
          })
        );
        return [binding.name, compiledTools, stateKey];
      })
    );
    return await format(`
    // Generated types - do not edit manually
${tsTypes}
   
  import { z } from "zod";

  export type Mcp<T extends Record<string, (input: any) => Promise<any>>> = {
    [K in keyof T]: ((input: Parameters<T[K]>[0]) => Promise<Awaited<ReturnType<T[K]>>>) & {
      asTool: () => Promise<{
        inputSchema: z.ZodType<Parameters<T[K]>[0]>
        outputSchema?: z.ZodType<Awaited<ReturnType<T[K]>>>
        description: string
        id: string
        execute: (input: Parameters<T[K]>[0]) => Promise<Awaited<ReturnType<T[K]>>>
      }>
    }
  }

  export const StateSchema = z.object({
    ${props.filter((p) => p !== null && p[2] !== void 0).map((prop) => {
      const [_, __, stateKey] = prop;
      return `${stateKey.key}: z.object({
        value: z.string(),
        __type: z.literal("${stateKey.type}").default("${stateKey.type}"),
      })`;
    }).join(",\n")}
  })

  export interface Env {
    DECO_CHAT_WORKSPACE: string;
    DECO_CHAT_API_JWT_PUBLIC_KEY: string;
    ${props.filter((p) => p !== null).map(([propName, tools]) => {
      return `${propName}: Mcp<{
        ${tools.map(([toolName, inputName, outputName, description]) => {
        const docComment = description ? `/**
${formatDescription(description)}
 */` : "";
        return `${docComment}
          ${toValidProperty(
          toolName
        )}: (input: ${inputName}) => Promise<${outputName ?? "any"}>;
          `;
      }).join("")}
      }>;`;
    }).join("")}
  }

  export const Scopes = {
    ${Object.entries(mapBindingTools).map(
      ([bindingName, tools]) => `${toValidProperty(bindingName)}: {
      ${tools.map(
        (toolName) => `${toValidProperty(toolName)}: "${parser.fromBindingToolToScope(
          { bindingName, toolName }
        )}"`
      ).join(",\n")}
    }`
    ).join(",\n")}
  }
  `);
  } finally {
    await client.close();
    await apiClient.close();
  }
};
async function configureCommand(local) {
  const currentConfig = await getConfig({ inlineOptions: { local } }).catch(
    () => ({})
  );
  const wranglerConfig = await readWranglerConfig();
  const defaultApp = typeof wranglerConfig.name === "string" ? wranglerConfig.name : "my-app";
  const { app } = await inquirer6.prompt([
    {
      type: "input",
      name: "app",
      message: "Enter app name:",
      default: defaultApp
    }
  ]);
  const workspace = await promptWorkspace(local, currentConfig.workspace);
  const mcpConfig = await promptIDESetup({ workspace, app });
  const bindings = await promptIntegrations(local, workspace);
  const envContent = await genEnv({ workspace, local, bindings });
  if (mcpConfig) {
    await writeIDEConfig(mcpConfig);
  }
  await writeWranglerConfig({
    name: app,
    deco: {
      ...wranglerConfig.deco,
      workspace,
      bindings: [...bindings, ...wranglerConfig.deco?.bindings ?? []]
    }
  });
  const outputPath = join(process28.cwd(), "deco.gen.ts");
  await promises.writeFile(outputPath, envContent);
  console.log(`\u2705 Environment types written to: ${outputPath}`);
  console.log(`\u2705 Configuration saved:`);
  console.log(`   App: ${app}`);
  console.log(`   Workspace: ${workspace}`);
}
var envFile = ".dev.vars";
async function getCurrentEnvVars(projectRoot) {
  const envFilepath = join(projectRoot, envFile);
  const devVarsFile = await promises.readFile(envFilepath, "utf-8").catch(() => "");
  const envVars = devVarsFile.split("\n").reduce(
    (acc, line) => {
      if (!line || line.startsWith("#")) {
        return acc;
      }
      const firstEqualIndex = line.indexOf("=");
      if (firstEqualIndex === -1) {
        return acc;
      }
      const key = line.substring(0, firstEqualIndex);
      const value = line.substring(firstEqualIndex + 1);
      acc[key] = value;
      return acc;
    },
    {}
  );
  return {
    envVars,
    envFilepath
  };
}
async function writeEnvVars(projectRoot, envVars) {
  await promises.writeFile(
    join(projectRoot, envFile),
    Object.entries(envVars).map(([key, value]) => `${key}=${value}`).join("\n")
  );
}
var getProjectRoot = () => {
  const configPath = getConfigFilePath(process28.cwd()) ?? process28.cwd();
  return dirname(configPath);
};
async function getEnvVars(projectRoot) {
  if (!projectRoot) {
    projectRoot = getProjectRoot();
  }
  const [currentEnvVars, session, config, wrangler] = await Promise.all([
    getCurrentEnvVars(projectRoot).then(({ envVars }) => envVars),
    readSession(),
    getConfig({}),
    readWranglerConfig(projectRoot)
  ]);
  const encodedBindings = Buffer.from(JSON.stringify(config.bindings)).toString(
    "base64"
  );
  const workspace = config.workspace ?? session?.workspace;
  const decoEnvVars = {
    DECO_WORKSPACE: workspace || "",
    DECO_API_TOKEN: session?.access_token ?? "",
    DECO_BINDINGS: encodedBindings,
    DECO_APP_ENTRYPOINT: "http://localhost:8787"
  };
  const deprecatedEnvVars = {
    DECO_CHAT_WORKSPACE: decoEnvVars.DECO_WORKSPACE,
    DECO_CHAT_API_TOKEN: decoEnvVars.DECO_API_TOKEN,
    DECO_CHAT_BINDINGS: decoEnvVars.DECO_BINDINGS,
    DECO_CHAT_APP_ENTRYPOINT: decoEnvVars.DECO_APP_ENTRYPOINT
  };
  const env = {
    ...currentEnvVars,
    ...deprecatedEnvVars,
    ...decoEnvVars
  };
  const { name, scope } = wrangler;
  if (name && workspace) {
    const [_, slug] = workspace.split("/");
    const appName = `@${scope ?? slug}/${name}`;
    env.DECO_APP_NAME = appName;
    env.DECO_CHAT_APP_NAME = appName;
  }
  if (config.local) {
    const apiUrl = "http://localhost:3001";
    env.DECO_API_URL = apiUrl;
    env.DECO_CHAT_API_URL = apiUrl;
  } else {
    delete env.DECO_API_URL;
    delete env.DECO_CHAT_API_URL;
  }
  return env;
}
async function ensureEnvVarsGitIgnore(projectRoot) {
  const gitignorePath = join(projectRoot, ".gitignore");
  try {
    const gitignoreContent = await promises.readFile(gitignorePath, "utf-8");
    const lines = gitignoreContent.split("\n");
    const entryExists = lines.some(
      (line) => line.trim() === envFile || line.trim() === `/${envFile}`
    );
    if (!entryExists) {
      const newContent = gitignoreContent.endsWith("\n") ? gitignoreContent + envFile + "\n" : gitignoreContent + "\n" + envFile + "\n";
      await promises.writeFile(gitignorePath, newContent);
    }
  } catch {
    await promises.writeFile(gitignorePath, envFile + "\n");
  }
}
async function addZodDependency(projectRoot) {
  const packageJsonPath = join(projectRoot, "package.json");
  const packageJsonContent = await promises.readFile(packageJsonPath, "utf-8");
  const packageJson = JSON.parse(packageJsonContent);
  if (!packageJson.dependencies) {
    packageJson.dependencies = {};
  }
  packageJson.dependencies.zod = "^3.24.3";
  await promises.writeFile(
    packageJsonPath,
    JSON.stringify(packageJson, null, 2) + "\n"
  );
}
async function cleanBuildDirectory(projectRoot, directory) {
  const buildDir = join(projectRoot, directory);
  await promises.rm(buildDir, { recursive: true, force: true });
  await promises.mkdir(buildDir);
}
async function ensureDevEnvironment(opts) {
  const projectRoot = getProjectRoot();
  if (opts.cleanBuildDirectory?.enabled) {
    await cleanBuildDirectory(projectRoot, opts.cleanBuildDirectory.directory);
  }
  await ensureEnvVarsGitIgnore(projectRoot);
  const env = await getEnvVars(projectRoot);
  await writeEnvVars(projectRoot, env);
  await addZodDependency(projectRoot);
}
function parseKeyValueEnvVar(input) {
  const eqIndex = input.indexOf("=");
  if (eqIndex === -1) {
    return null;
  }
  const key = input.slice(0, eqIndex);
  if (!key) {
    console.warn(
      `Warning: Skipping invalid environment variable line with empty key: "${input}"`
    );
    return null;
  }
  const value = input.slice(eqIndex + 1);
  return { key, value };
}
function parseEnvFileContent(content) {
  return content.split("\n").reduce(
    (acc, line) => {
      const trimmed = line.trim();
      if (!trimmed || trimmed.startsWith("#")) {
        return acc;
      }
      const parsed = parseKeyValueEnvVar(trimmed);
      if (parsed) {
        acc[parsed.key] = parsed.value;
      }
      return acc;
    },
    {}
  );
}
function parseJsonEnvVars(jsonObj) {
  if (typeof jsonObj !== "object" || jsonObj === null) {
    throw new Error("Invalid JSON: expected object");
  }
  const result = {};
  for (const [key, value] of Object.entries(jsonObj)) {
    result[key] = typeof value === "string" ? value : String(value);
  }
  return result;
}
async function parseEnvFile(filePath, workingDir) {
  const envFilePath = isAbsolute(filePath) ? filePath : join(workingDir, filePath);
  const fileContent = await promises.readFile(envFilePath, "utf-8");
  try {
    const jsonObj = JSON.parse(fileContent);
    return parseJsonEnvVars(jsonObj);
  } catch {
    return parseEnvFileContent(fileContent);
  }
}
function parseInlineJsonEnvVars(jsonString) {
  const jsonObj = JSON.parse(jsonString);
  return parseJsonEnvVars(jsonObj);
}
function isFilePath(input) {
  if (input.includes("/") || input.includes("\\")) return true;
  if (input.startsWith(".env")) return true;
  if (input.endsWith(".json")) return true;
  return false;
}

// src/commands/hosting/deploy.ts
function tryParseJson(text) {
  try {
    return JSON.parse(text);
  } catch {
    return null;
  }
}
function normalizePath(path4) {
  return posix.normalize(path4.replace(/\\/g, "/"));
}
function tryParseInlineJson(input) {
  try {
    const parsedVars = parseInlineJsonEnvVars(input);
    const count = Object.keys(parsedVars).length;
    return { vars: parsedVars, count };
  } catch (error) {
    console.warn(
      `\u26A0\uFE0F  Invalid JSON format: "${input}". Error: ${error instanceof Error ? error.message : String(error)}. Skipping.`
    );
    return null;
  }
}
async function tryParseEnvFile(filePath, workingDir) {
  try {
    const parsedVars = await parseEnvFile(filePath, workingDir);
    const count = Object.keys(parsedVars).length;
    return { vars: parsedVars, count };
  } catch (error) {
    console.warn(
      `\u26A0\uFE0F  Failed to read env file "${filePath}": ${error instanceof Error ? error.message : String(error)}. Skipping.`
    );
    return null;
  }
}
var WRANGLER_CONFIG_FILES = ["wrangler.toml", "wrangler.json"];
var deploy = async ({
  cwd,
  workspace,
  app: appSlug,
  local,
  assetsDirectory,
  skipConfirmation,
  force,
  promote = true,
  unlisted = true,
  dryRun = false,
  inlineEnvVars = []
}) => {
  console.log(
    `
\u{1F680} ${dryRun ? "Preparing" : "Deploying"} '${appSlug}' to '${workspace}'${dryRun ? " (dry run)" : ""}...
`
  );
  try {
    await promises.stat(cwd);
  } catch {
    throw new Error("Target directory not found");
  }
  const files = [];
  let hasTsFile = false;
  let foundWranglerConfigInWalk = false;
  let foundWranglerConfigName = "";
  for await (const entry of walk(cwd, {
    includeFiles: true,
    includeDirs: false,
    skip: [
      /node_modules/,
      /\.git/,
      /\.DS_Store/,
      /\.env/,
      /\.env\.local/,
      /\.dev\.vars/,
      /\.vite/
    ],
    exts: [
      "ts",
      "mjs",
      "js",
      "cjs",
      "toml",
      "json",
      "css",
      "html",
      "txt",
      "wasm",
      "sql"
    ]
  })) {
    const realPath = normalizePath(relative(cwd, entry.path));
    const content = await promises.readFile(entry.path, "utf-8");
    files.push({ path: realPath, content });
    if (realPath.endsWith(".ts")) {
      hasTsFile = true;
    }
    if (WRANGLER_CONFIG_FILES.some((name) => realPath.includes(name))) {
      foundWranglerConfigInWalk = true;
      foundWranglerConfigName = realPath;
    }
  }
  if (assetsDirectory) {
    for await (const entry of walk(assetsDirectory, {
      includeFiles: true,
      includeDirs: false,
      skip: [
        /node_modules/,
        /\.git/,
        /\.DS_Store/,
        /\.env/,
        /\.env\.local/,
        /\.dev\.vars/
      ]
    })) {
      const realPath = normalizePath(relative(assetsDirectory, entry.path));
      const content = await promises.readFile(entry.path);
      const base64Content = Buffer.from(content).toString("base64");
      files.push({ path: realPath, content: base64Content, asset: true });
    }
  }
  let wranglerConfigStatus = "";
  if (!foundWranglerConfigInWalk) {
    let found = false;
    for (const configFile of WRANGLER_CONFIG_FILES) {
      const configPath = `${process28.cwd()}/${configFile}`;
      try {
        const configContent = await promises.readFile(configPath, "utf-8");
        files.push({ path: configFile, content: configContent });
        wranglerConfigStatus = `${configFile} \u2705 (found in ${configPath})`;
        found = true;
        break;
      } catch {
      }
    }
    if (!found) {
      wranglerConfigStatus = "wrangler.toml/json \u274C";
    }
  } else {
    wranglerConfigStatus = `${foundWranglerConfigName} \u2705 (found in project files)`;
  }
  const { envVars: fileEnvVars, envFilepath } = await getCurrentEnvVars(cwd);
  const parsedInlineEnvVars = {};
  const envVarSources = [];
  for (const envVar of inlineEnvVars) {
    const trimmedEnvVar = envVar.trim();
    if (trimmedEnvVar.startsWith("{")) {
      const result = tryParseInlineJson(trimmedEnvVar);
      if (result && result.count > 0) {
        Object.assign(parsedInlineEnvVars, result.vars);
        envVarSources.push(`JSON (${result.count} vars)`);
      }
      continue;
    }
    if (isFilePath(trimmedEnvVar)) {
      const result = await tryParseEnvFile(trimmedEnvVar, cwd);
      if (result && result.count > 0) {
        Object.assign(parsedInlineEnvVars, result.vars);
        envVarSources.push(`${trimmedEnvVar} (${result.count} vars)`);
      }
      continue;
    }
    const parsed = parseKeyValueEnvVar(trimmedEnvVar);
    if (!parsed) {
      console.warn(
        `\u26A0\uFE0F  Invalid env var format: "${trimmedEnvVar}". Expected KEY=VALUE, JSON object, or file path. Skipping.`
      );
      continue;
    }
    parsedInlineEnvVars[parsed.key] = parsed.value;
  }
  const envVars = { ...fileEnvVars, ...parsedInlineEnvVars };
  const envVarsFromFile = Object.keys(fileEnvVars).length;
  const envVarsFromCLI = Object.keys(parsedInlineEnvVars).length;
  const envVarsTotal = Object.keys(envVars).length;
  let envVarsStatus = `Loaded ${envVarsFromFile} env vars from ${envFilepath}`;
  if (envVarsFromCLI > 0) {
    const sourcesInfo = envVarSources.length > 0 ? ` [${envVarSources.join(", ")}]` : "";
    envVarsStatus += ` + ${envVarsFromCLI} from CLI${sourcesInfo} (${envVarsTotal} total)`;
  }
  const manifest = {
    appSlug,
    files,
    envVars,
    envFilepath,
    bundle: hasTsFile,
    unlisted,
    force,
    promote
  };
  console.log("\u{1F69A} Deployment summary:");
  console.log(`  App: ${appSlug}`);
  console.log(`  Files: ${files.length}`);
  console.log(`  ${envVarsStatus}`);
  console.log(`  ${wranglerConfigStatus}`);
  if (promote) {
    console.log(`  Promote mode: true (deployment will replace production)`);
  }
  if (dryRun) {
    const manifestPath = join(cwd, "deploy-manifest.json");
    await promises.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
    console.log(`
\u{1F4C4} Dry run complete! Deploy manifest written to:`);
    console.log(`  ${manifestPath}`);
    console.log();
    return;
  }
  const confirmed = skipConfirmation || (await inquirer6.prompt([
    {
      type: "confirm",
      name: "proceed",
      message: "Proceed with deployment?",
      default: true
    }
  ])).proceed;
  if (!confirmed) {
    console.log("\u274C Deployment cancelled");
    process28.exit(0);
  }
  const client = await createWorkspaceClientStub({ workspace, local });
  const deploy2 = async (options) => {
    const response2 = await client.callTool({
      name: "HOSTING_APP_DEPLOY",
      arguments: manifest
    });
    if (response2.isError && Array.isArray(response2.content)) {
      console.error("Error deploying: ", response2);
      const errorText = response2.content[0]?.text;
      const errorTextJson = tryParseJson(errorText ?? "");
      if (errorTextJson?.name === "MCPBreakingChangeError" && !force) {
        console.log("Looks like you have breaking changes in your app.");
        console.log(errorTextJson.message);
        if (skipConfirmation) {
          console.error("Use --force (-f) to deploy with breaking changes");
          process28.exit(1);
        }
        const confirmed2 = await inquirer6.prompt([
          {
            type: "confirm",
            name: "proceed",
            message: "Would you like to retry with the --force flag?",
            default: true
          }
        ]);
        if (!confirmed2) {
          process28.exit(1);
        }
        return deploy2({ ...options, force: true });
      }
      throw new Error(errorText ?? "Unknown error");
    }
    return response2;
  };
  const response = await deploy2(manifest);
  if (!response.structuredContent || typeof response.structuredContent !== "object") {
    console.error("\u274C Deployment failed: Invalid response structure");
    console.error("Response:", JSON.stringify(response, null, 2));
    throw new Error("Deployment response missing structuredContent");
  }
  const structuredContent = response.structuredContent;
  const hosts = structuredContent.hosts;
  if (!hosts || !Array.isArray(hosts) || hosts.length === 0) {
    console.error("\u274C Deployment failed: No hosts returned in response");
    console.error("Response:", JSON.stringify(response, null, 2));
    throw new Error("Deployment response missing hosts array");
  }
  console.log(`
\u{1F389} Deployed! Available at:`);
  hosts.forEach((host) => console.log(`  ${host}`));
  console.log();
  const previewUrl = promote ? null : hosts[0];
  if (process28.env.GITHUB_OUTPUT && previewUrl) {
    await promises.appendFile(
      process28.env.GITHUB_OUTPUT,
      `preview_url=${previewUrl}
`
    );
  }
};
var listApps = async ({ workspace }) => {
  console.log(`\u{1F50D} Listing apps in workspace '${workspace}'...`);
  const client = await createWorkspaceClient({ workspace });
  const response = await client.callTool(
    {
      name: "HOSTING_APPS_LIST",
      arguments: {}
    },
    // @ts-expect-error We need to refactor HOSTING_APPS_LIST to stop returning array and use a proper object
    z.any()
  );
  if (response.isError && Array.isArray(response.content)) {
    throw new Error(response.content[0]?.text ?? "Unknown error");
  }
  const apps = response.structuredContent;
  if (apps.length === 0) {
    console.log("\u{1F4ED} No apps found in this workspace.");
  } else {
    console.log("\u{1F4F1} Apps in workspace:");
    apps.forEach((app) => {
      console.log(
        `  \u2022 ${app.slug} (${app.entrypoint}, Files: ${app.files.length})`
      );
    });
  }
};
var promoteApp = async ({
  workspace,
  local,
  appSlug,
  deploymentId,
  routePattern,
  skipConfirmation = false
}) => {
  const client = await createWorkspaceClient({ workspace, local });
  let selectedAppSlug = appSlug;
  if (!selectedAppSlug) {
    console.log(`\u{1F50D} Fetching published apps in workspace '${workspace}'...`);
    const publishedAppsResponse = await client.callTool({
      name: "REGISTRY_LIST_PUBLISHED_APPS",
      arguments: {}
    });
    if (publishedAppsResponse.isError && Array.isArray(publishedAppsResponse.content)) {
      throw new Error(
        publishedAppsResponse.content[0]?.text ?? "Failed to list published apps"
      );
    }
    const { apps } = publishedAppsResponse.structuredContent;
    if (apps.length === 0) {
      console.log("\u{1F4ED} No published apps found in this workspace.");
      return;
    }
    if (apps.length === 1) {
      selectedAppSlug = apps[0].name;
      console.log(
        `\u{1F4E6} Using app: ${selectedAppSlug} (${apps[0].friendlyName || apps[0].name})`
      );
    } else {
      const appOptions = apps.map((app2) => ({
        name: `${app2.name}${app2.friendlyName ? ` (${app2.friendlyName})` : ""}${app2.description ? ` - ${app2.description}` : ""}`,
        value: app2.name
      }));
      const { selectedApp } = await inquirer6.prompt([
        {
          type: "list",
          name: "selectedApp",
          message: "Select app to promote:",
          choices: appOptions
        }
      ]);
      selectedAppSlug = selectedApp;
    }
  }
  console.log(
    `\u{1F680} Promoting deployment for app '${selectedAppSlug}' in workspace '${workspace}'...`
  );
  const deploymentsResponse = await client.callTool({
    name: "HOSTING_APP_DEPLOYMENTS_LIST",
    arguments: { appSlug: selectedAppSlug }
  });
  if (deploymentsResponse.isError && Array.isArray(deploymentsResponse.content)) {
    throw new Error(
      deploymentsResponse.content[0]?.text ?? "Failed to list deployments"
    );
  }
  const { deployments, app } = deploymentsResponse.structuredContent;
  if (deployments.length === 0) {
    console.log("\u{1F4ED} No deployments found for this app.");
    return;
  }
  let selectedDeploymentId = deploymentId;
  if (!selectedDeploymentId) {
    if (deployments.length === 1) {
      selectedDeploymentId = deployments[0].id;
      console.log(
        `\u{1F4E6} Using deployment: ${selectedDeploymentId} (${deployments[0].entrypoint})`
      );
    } else {
      const deploymentOptions = deployments.map((dep) => ({
        name: `${dep.id} - ${new Date(
          dep.created_at
        ).toLocaleString()} (${dep.entrypoint})`,
        value: dep.id
      }));
      const { selectedDeployment: selectedDeployment2 } = await inquirer6.prompt([
        {
          type: "list",
          name: "selectedDeployment",
          message: "Select deployment to promote:",
          choices: deploymentOptions
        }
      ]);
      selectedDeploymentId = selectedDeployment2;
    }
  }
  const selectedDeployment = deployments.find(
    (d) => d.id === selectedDeploymentId
  );
  if (!selectedDeployment) {
    throw new Error(`Deployment ${selectedDeploymentId} not found`);
  }
  let selectedRoutePattern = routePattern;
  if (!selectedRoutePattern) {
    const { routeInput } = await inquirer6.prompt([
      {
        type: "input",
        name: "routeInput",
        message: "Enter route pattern to promote to:",
        default: `${selectedAppSlug}.deco.page`,
        validate: (input) => {
          const trimmed = input.trim();
          if (!trimmed) return "Route pattern is required";
          return true;
        }
      }
    ]);
    selectedRoutePattern = routeInput;
  }
  if (!skipConfirmation) {
    console.log("\n\u{1F4CB} Promotion Summary:");
    console.log(`  App: ${app.slug}`);
    console.log(`  Deployment: ${selectedDeploymentId}`);
    console.log(`  Entrypoint: ${selectedDeployment.entrypoint}`);
    console.log(`  Route Pattern: ${selectedRoutePattern}`);
    const { confirmed } = await inquirer6.prompt([
      {
        type: "confirm",
        name: "confirmed",
        message: "Do you want to proceed with the promotion?",
        default: true
      }
    ]);
    if (!confirmed) {
      console.log("\u274C Promotion cancelled.");
      return;
    }
  }
  try {
    const promoteResponse = await client.callTool({
      name: "HOSTING_APPS_PROMOTE",
      arguments: {
        deploymentId: selectedDeploymentId,
        routePattern: selectedRoutePattern
      }
    });
    if (promoteResponse.isError && Array.isArray(promoteResponse.content)) {
      throw new Error(
        promoteResponse.content[0]?.text ?? "Failed to promote deployment"
      );
    }
    const result = promoteResponse.structuredContent;
    if (result.success) {
      console.log("\u2705 Deployment promoted successfully!");
      console.log(`\u{1F310} Route updated: ${result.promotedRoute}`);
      console.log("\u{1F9F9} Route cache purged");
    } else {
      throw new Error("Promotion failed");
    }
  } catch (error) {
    console.error("\u274C Failed to promote deployment:", error);
    throw error;
  }
};

// package.json
var package_default = {
  name: "deco-cli",
  version: "0.28.6",
  description: "CLI for managing decocms.com apps & projects"};

// src/lib/package-info.ts
var packageInfo = {
  name: package_default.name,
  version: package_default.version,
  description: package_default.description
};

// src/lib/banner.ts
function displayBanner() {
  const deco = chalk5.green(`
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557
\u2588\u2588\u2551  \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557  \u2588\u2588\u2551     \u2588\u2588\u2551   \u2588\u2588\u2551
\u2588\u2588\u2551  \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D  \u2588\u2588\u2551     \u2588\u2588\u2551   \u2588\u2588\u2551
\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D 
`);
  const subtitle = chalk5.gray("Creating Deco project");
  const version = chalk5.dim(`CLI v${packageInfo.version}`);
  console.log(deco);
  console.log(`  ${subtitle}`);
  console.log(`  ${version}`);
  console.log("");
}
var __filename2 = fileURLToPath(import.meta.url);
var __dirname2 = dirname(__filename2);
var DEFAULT_TEMPLATE = {
  name: "Deco MCP app",
  description: "A Deco MCP app",
  repo: "deco-cx/deco-create",
  branch: "main",
  pathsToIgnore: []
};
function runCommand(command, args, cwd) {
  return new Promise((resolve3) => {
    const process29 = spawn(command, args, {
      cwd,
      stdio: "pipe"
    });
    process29.on("close", (code) => {
      resolve3(code === 0);
    });
    process29.on("error", () => {
      resolve3(false);
    });
  });
}
var PATHS_TO_IGNORE_ALWAYS = [".git"];
async function downloadTemplate(template, targetDir) {
  if (template.name === "base") {
    const templatePath = join(__dirname2, "../../../template/base");
    await ensureDir(targetDir);
    await copy(templatePath, targetDir, { overwrite: true });
    console.log(`\u2705 Template '${template.name}' copied successfully!`);
    return;
  }
  const tempDir = join(process28.cwd(), `.temp-${Date.now()}`);
  try {
    const success = await runCommand("git", [
      "clone",
      "--depth",
      "1",
      "--branch",
      template.branch || "main",
      `https://github.com/${template.repo}.git`,
      tempDir
    ]);
    if (!success) {
      throw new Error(`Failed to clone template repository: ${template.repo}`);
    }
    const pathsToIgnore = [
      ...template.pathsToIgnore || [],
      ...PATHS_TO_IGNORE_ALWAYS
    ];
    for (const path4 of pathsToIgnore) {
      try {
        const pathToRemove = join(tempDir, path4);
        const isDirectory = await promises.stat(pathToRemove).then((stat) => stat.isDirectory());
        await promises.rm(
          pathToRemove,
          isDirectory ? { recursive: true, force: true } : { force: true }
        );
      } catch {
        console.warn(`Failed to remove ${path4} from the original template`);
      }
    }
    const templatePath = join(tempDir, template.path || "");
    try {
      await promises.access(templatePath);
    } catch {
      throw new Error(`Template '${template.name}' not found in repository`);
    }
    await ensureDir(targetDir);
    await copy(templatePath, targetDir, { overwrite: true });
    console.log(`\u2705 Template '${template.name}' downloaded successfully!`);
  } finally {
    await promises.rm(tempDir, { recursive: true, force: true }).catch(() => {
    });
  }
}
async function customizeTemplate({
  targetDir,
  projectName,
  workspace,
  wranglerRoot
}) {
  const packageJsonPath = join(targetDir, "package.json");
  try {
    const packageJsonContent = await promises.readFile(packageJsonPath, "utf-8");
    const packageJson = JSON.parse(packageJsonContent);
    packageJson.name = projectName;
    await promises.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
  } catch (error) {
    console.warn(
      "\u26A0\uFE0F  Could not customize package.json:",
      error instanceof Error ? error.message : String(error)
    );
  }
  if (workspace) {
    try {
      const currentConfig = await readWranglerConfig(wranglerRoot || targetDir);
      const bindings = currentConfig.deco?.bindings || [];
      const newConfig = {
        ...currentConfig,
        name: projectName,
        scope: workspace,
        deco: {
          ...currentConfig.deco,
          workspace,
          bindings
        }
      };
      await writeWranglerConfig(newConfig, wranglerRoot || targetDir);
      const envContent = await genEnv({
        workspace,
        local: false,
        bindings: newConfig.deco.bindings || []
      });
      const outputPath = join(wranglerRoot || targetDir, "deco.gen.ts");
      await promises.writeFile(outputPath, envContent);
      console.log(`\u2705 Environment types written to: ${outputPath}`);
    } catch (error) {
      console.warn(
        "\u26A0\uFE0F  Could not update config file:",
        error instanceof Error ? error.message : String(error)
      );
    }
  }
}
async function createCommand(projectName, config = {}) {
  try {
    console.clear();
    displayBanner();
    let session = await readSession();
    if (!session) {
      console.log("\u{1F510} No session found. Starting authentication process...");
      try {
        await loginCommand();
        console.log("\u2705 Successfully logged in to admin.decocms.com");
        session = await readSession();
      } catch (error) {
        console.error(
          "\u274C Login failed:",
          error instanceof Error ? error.message : String(error)
        );
        console.warn(
          "\u26A0\uFE0F  Continuing without authentication. You can run 'deco login' later for a better experience."
        );
      }
    }
    const selectedTemplate = DEFAULT_TEMPLATE;
    const finalProjectName = slugify(
      projectName || (await inquirer6.prompt([
        {
          type: "input",
          name: "projectName",
          message: "Enter project name:",
          validate: (value) => {
            if (!value.trim()) {
              return "Project name cannot be empty";
            }
            if (!/^[a-z0-9-]+$/.test(value)) {
              return "Project name can only contain lowercase letters, numbers, and hyphens";
            }
            return true;
          }
        }
      ])).projectName
    );
    let workspace = config?.workspace;
    if (session) {
      try {
        workspace = await promptWorkspace(config?.local, workspace);
        console.log(`\u{1F4C1} Selected workspace: ${workspace}`);
      } catch (error) {
        console.error(
          "\u274C Failed to select workspace:",
          error instanceof Error ? error.message : String(error)
        );
        console.warn(
          "\u26A0\uFE0F  Could not select workspace. Continuing without workspace selection."
        );
      }
    } else {
      console.log(
        "\u26A0\uFE0F  No authentication session - skipping workspace selection"
      );
    }
    const targetDir = join(process28.cwd(), finalProjectName);
    try {
      await promises.access(targetDir);
      const { overwrite } = await inquirer6.prompt([
        {
          type: "list",
          name: "overwrite",
          message: `Directory '${finalProjectName}' already exists. Overwrite?`,
          choices: ["No", "Yes"]
        }
      ]);
      if (overwrite === "No") {
        console.log("\u274C Project creation cancelled.");
        return;
      }
      await promises.rm(targetDir, { recursive: true });
    } catch {
    }
    const wranglerRoot = join(targetDir, selectedTemplate.wranglerRoot || "");
    const { initGit } = await inquirer6.prompt([
      {
        type: "list",
        name: "initGit",
        message: "Initialize a git repository?",
        choices: ["No", "Yes"]
      }
    ]);
    const mcpResult = workspace ? await promptIDESetup({ workspace, app: finalProjectName }, targetDir) : null;
    console.log(`\u{1F4E6} Downloading template '${selectedTemplate.name}'...`);
    await downloadTemplate(selectedTemplate, targetDir);
    if (mcpResult) {
      await writeIDEConfig(mcpResult);
    }
    await customizeTemplate({
      targetDir,
      projectName: finalProjectName,
      workspace,
      wranglerRoot
    });
    if (initGit === "Yes") {
      try {
        const success = await runCommand("git", ["init"], targetDir);
        if (success) {
          console.log(`\u2705 Git repository initialized in '${finalProjectName}'`);
        } else {
          console.warn("\u26A0\uFE0F  Failed to initialize git repository");
        }
      } catch (error) {
        console.warn(
          "\u26A0\uFE0F  Could not initialize git repository:",
          error instanceof Error ? error.message : String(error)
        );
      }
    }
    console.log(`
\u{1F389} Project '${finalProjectName}' created successfully!`);
    console.log(`
Next steps:`);
    console.log(`  cd ${finalProjectName}`);
    console.log(`  npm install`);
    console.log(`  npm run dev`);
  } catch (error) {
    console.error(
      "\u274C Failed to create project:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}
function copyToClipboard(text) {
  try {
    let command;
    let args = [];
    switch (process28.platform) {
      case "darwin":
        command = "pbcopy";
        break;
      case "win32":
        command = "clip";
        break;
      case "linux":
        command = "xclip";
        args = ["-selection", "clipboard"];
        break;
      default:
        return Promise.resolve(false);
    }
    return new Promise((resolve3) => {
      const clipProcess = spawn(command, args, { stdio: "pipe" });
      clipProcess.stdin.write(text);
      clipProcess.stdin.end();
      clipProcess.on("close", (code) => {
        resolve3(code === 0);
      });
      clipProcess.on("error", () => {
        resolve3(false);
      });
    });
  } catch {
    return Promise.resolve(false);
  }
}
async function findRunningAddr(port) {
  const LOCALHOST_ENDPOINTS = ["localhost", "127.0.0.1", "0.0.0.0"];
  for (const endpoint of LOCALHOST_ENDPOINTS) {
    try {
      const server = createServer$1();
      await new Promise((resolve3, reject) => {
        server.listen(port, endpoint, () => {
          server.close();
          resolve3();
        });
        server.on("error", reject);
      });
    } catch {
      return endpoint;
    }
  }
  return null;
}
async function waitForPort(port) {
  let addr = await findRunningAddr(port);
  if (addr) {
    return addr;
  }
  console.log(chalk5.yellow(`Waiting for port ${port} to become available...`));
  while (!addr) {
    await new Promise((resolve3) => setTimeout(resolve3, 1e3));
    addr = await findRunningAddr(port);
  }
  console.log(chalk5.green(`Port ${port} is now available!`));
  return addr;
}
async function monitorPortAvailability(port) {
  while (true) {
    const isAvailable = await findRunningAddr(port);
    if (!isAvailable) {
      console.log(chalk5.red(`\u26A0\uFE0F Warning: Port ${port} is no longer available!`));
    }
    await new Promise((resolve3) => setTimeout(resolve3, 2e3));
  }
}
async function register(port, domain, onBeforeRegister) {
  const server = `wss://${domain}`;
  const serverUrl = `https://${domain}`;
  try {
    monitorPortAvailability(port).catch((err) => {
      console.error("Port monitoring error:", err);
    });
    onBeforeRegister?.(serverUrl);
    const host = await waitForPort(port);
    const localAddr = `http://${host}:${port}`;
    const tunnel = await connect({
      domain,
      localAddr,
      server,
      apiKey: process28.env.DECO_TUNNEL_SERVER_TOKEN ?? "c309424a-2dc4-46fe-bfc7-a7c10df59477"
    });
    await tunnel.registered;
    const copied = await copyToClipboard(serverUrl);
    console.log(
      `
Tunnel started 
   -> \u{1F310} ${chalk5.bold("Preview")}: ${chalk5.cyan(
        serverUrl
      )}${copied ? chalk5.dim(" (copied to clipboard)") : ""}`
    );
    await tunnel.closed;
  } catch (err) {
    console.log("Tunnel connection error, retrying in 500ms...", err);
    await new Promise((resolve3) => setTimeout(resolve3, 500));
    return register(port, domain);
  }
}
var link = async ({
  port = 8787,
  onBeforeRegister
} = {}) => {
  const config = await getConfig({});
  const wranglerConfig = await readWranglerConfig();
  const app = typeof wranglerConfig.name === "string" ? wranglerConfig.name : "my-app";
  const appDomain = getAppDomain(config.workspace, app);
  await register(port, appDomain, onBeforeRegister);
};
async function devCommand(opts) {
  try {
    await ensureDevEnvironment(opts);
    const commandOverride = opts.command ?? ["wrangler", "dev"];
    const _config = await getConfig().catch(() => ({
      workspace: "default",
      bindings: [],
      local: false,
      enable_workflows: true
    }));
    const wranglerConfig = await readWranglerConfig();
    const app = typeof wranglerConfig.name === "string" ? wranglerConfig.name : "my-app";
    console.log(chalk5.gray(`Starting development server for '${app}'...`));
    if (opts.genWatch) {
      const watchPath = resolve(opts.genWatch);
      console.log(
        chalk5.gray(
          `Setting up file watcher for TypeScript files in: ${watchPath}`
        )
      );
      let isGenerating = false;
      const debounceMs = 2500;
      let debounceTimer = null;
      const generateTypes = async () => {
        if (isGenerating) return;
        isGenerating = true;
        try {
          console.log(
            chalk5.gray("TypeScript file changed, regenerating deco.gen.ts...")
          );
          const config = await getConfig();
          const wranglerConfig2 = await readWranglerConfig();
          const env = await genEnv({
            workspace: config.workspace,
            local: config.local,
            bindings: config.bindings,
            selfUrl: `https://${getAppDomain(
              config.workspace,
              wranglerConfig2.name ?? "my-app"
            )}/mcp`
          });
          const outputPath = join(process28.cwd(), "deco.gen.ts");
          await writeFile(outputPath, env);
          console.log(chalk5.blue(`Generated types written to: ${outputPath}`));
        } catch (error) {
          console.error(
            chalk5.red("Failed to generate types:"),
            error instanceof Error ? error.message : String(error)
          );
        } finally {
          isGenerating = false;
        }
      };
      await generateTypes();
      const watcher = watch(
        watchPath,
        { recursive: true },
        (_eventType, filename) => {
          if (filename && filename.endsWith(".ts") && !filename.endsWith(".gen.ts")) {
            if (debounceTimer) {
              clearTimeout(debounceTimer);
            }
            debounceTimer = setTimeout(generateTypes, debounceMs);
          }
        }
      );
      const cleanupWatcher = () => {
        console.log(chalk5.yellow("\nStopping file watcher..."));
        watcher.close();
      };
      process28.on("SIGINT", cleanupWatcher);
      process28.on("SIGTERM", cleanupWatcher);
    }
    console.log(chalk5.gray("Starting development server with tunnel..."));
    await link({
      port: 8787,
      onBeforeRegister: () => {
        console.log(chalk5.gray("Starting Wrangler development server..."));
        const command = commandOverride ?? ["wrangler", "dev"];
        const wranglerProcess = spawn("npx", command, {
          stdio: "inherit",
          shell: true
        });
        const cleanup = () => {
          console.log(chalk5.yellow("\nStopping development server..."));
          wranglerProcess.kill("SIGINT");
          process28.exit(0);
        };
        process28.on("SIGINT", cleanup);
        process28.on("SIGTERM", cleanup);
        wranglerProcess.on("error", (error) => {
          console.error(chalk5.red("Failed to start Wrangler:"), error.message);
          process28.exit(1);
        });
        return wranglerProcess;
      }
    });
  } catch (error) {
    console.error(
      chalk5.red("Development server failed:"),
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}
function detectRuntime() {
  if (typeof globalThis.Deno !== "undefined") return "deno";
  if (process28.versions.bun) return "bun";
  if (process28.versions.node) return "node";
  return "unknown";
}

// src/commands/update/upgrade.ts
var getPackageJson = async () => {
  return packageInfo;
};
var getLatestVersion = async (packageName) => {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
  try {
    const response = await fetch(
      `https://registry.npmjs.org/${packageName}/latest`,
      {
        signal: controller.signal
      }
    );
    clearTimeout(timeoutId);
    if (!response.ok) {
      throw new Error(`Failed to fetch latest version: ${response.statusText}`);
    }
    const data = await response.json();
    return data.version;
  } catch (error) {
    clearTimeout(timeoutId);
    if (error instanceof Error && error.name === "AbortError") {
      throw new Error("Request timed out while checking for updates");
    }
    throw error;
  }
};
var getInstallCommand = (runtime, packageName) => {
  switch (runtime) {
    case "bun":
      return ["bun", ["install", "-g", packageName]];
    case "deno":
      return ["deno", ["install", "-Ar", "-g", "-f", `npm:${packageName}`]];
    case "node":
      return ["npm", ["install", "-g", packageName]];
    case "unknown":
    default:
      console.log(chalk5.yellow("\u26A0\uFE0F  Unknown runtime, falling back to npm"));
      return ["npm", ["install", "-g", packageName]];
  }
};
var upgrade = (packageName) => {
  console.log(chalk5.yellow("\u{1F504} Upgrading to the latest version..."));
  const runtime = detectRuntime();
  console.log(chalk5.gray(`Detected runtime: ${runtime}`));
  const [command, args] = getInstallCommand(runtime, packageName);
  return new Promise((resolve3, reject) => {
    const child = spawn(command, args, {
      stdio: "inherit",
      shell: true
    });
    child.on("close", (code) => {
      if (code === 0) {
        console.log(chalk5.green("\u{1F389} CLI updated successfully!"));
        console.log(
          chalk5.blue(
            "Please restart your terminal or run 'deco --version' to verify."
          )
        );
        resolve3();
      } else {
        console.error(chalk5.red("\u274C Failed to update the CLI."));
        reject(
          new Error(
            `${command} ${args.join(" ")} failed with exit code ${code}`
          )
        );
      }
    });
    child.on("error", (error) => {
      console.error(chalk5.red("\u274C Failed to update the CLI."));
      reject(error);
    });
  });
};
async function upgradeCommand() {
  try {
    const packageJson = await getPackageJson();
    const currentVersion = packageJson.version;
    console.log(chalk5.blue(`Current version: v${currentVersion}`));
    console.log(chalk5.blue("Checking for updates..."));
    const latestVersion = await getLatestVersion(packageJson.name);
    if (semver.gt(latestVersion, currentVersion)) {
      console.log(
        chalk5.green(
          `\u{1F4E6} New version available: ${chalk5.bold(`v${latestVersion}`)}`
        )
      );
      const { confirmed } = await inquirer6.prompt([
        {
          type: "confirm",
          name: "confirmed",
          message: `Update from v${currentVersion} to v${latestVersion}?`,
          default: true
        }
      ]);
      if (confirmed) {
        await upgrade(packageJson.name);
      } else {
        console.log(chalk5.gray("Update cancelled."));
      }
    } else if (semver.eq(latestVersion, currentVersion)) {
      console.log(
        chalk5.green("\u2705 You are already running the latest version!")
      );
    } else {
      console.log(chalk5.blue("\u2139\uFE0F  You are running a development version."));
    }
  } catch (error) {
    console.error(
      chalk5.red("\u274C Failed to check for updates:"),
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}
var DECO_DEPENDENCIES = [
  "@deco/workers-runtime",
  "@decocms/runtime"
];
var DECO_DEV_DEPENDENCIES = ["deco-cli"];
var getLatestVersion2 = async (packageName) => {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), 1e4);
  try {
    if (packageName === "@deco/workers-runtime") {
      const response2 = await fetch(
        "https://jsr.io/@deco/workers-runtime/meta.json",
        {
          signal: controller.signal
        }
      );
      clearTimeout(timeoutId);
      if (response2.ok) {
        const data2 = await response2.json();
        return data2.latest;
      }
    }
    const response = await fetch(
      `https://registry.npmjs.org/${packageName}/latest`,
      {
        signal: controller.signal
      }
    );
    clearTimeout(timeoutId);
    if (!response.ok) {
      throw new Error(`Failed to fetch latest version: ${response.statusText}`);
    }
    const data = await response.json();
    return data.version;
  } catch (error) {
    clearTimeout(timeoutId);
    if (error instanceof Error && error.name === "AbortError") {
      throw new Error("Request timed out while checking for updates");
    }
    throw error;
  }
};
var parseCurrentVersion = (versionString) => {
  if (versionString.startsWith("npm:@jsr/")) {
    const match = versionString.match(/@([^@]+)$/);
    return match ? match[1] : versionString;
  }
  return versionString.replace(/^[\^~]/, "");
};
var formatVersionForPackageJson = (packageName, version) => {
  if (packageName === "@deco/workers-runtime") {
    return `npm:@jsr/deco__workers-runtime@${version}`;
  }
  return `^${version}`;
};
var discoverWorkspaces = async (rootPath) => {
  const rootPackageJsonPath = resolve(rootPath, "package.json");
  if (!existsSync(rootPackageJsonPath)) {
    throw new Error("No package.json found in the current directory");
  }
  const rootPackageJson = JSON.parse(
    await readFile(rootPackageJsonPath, "utf-8")
  );
  if (!rootPackageJson.workspaces) {
    return [rootPackageJsonPath];
  }
  const packageJsonPaths = [rootPackageJsonPath];
  for (const workspacePattern of rootPackageJson.workspaces) {
    const workspaceDirs = await glob(workspacePattern, {
      cwd: rootPath
    });
    for (const dir of workspaceDirs) {
      const packageJsonPath = resolve(rootPath, dir, "package.json");
      if (existsSync(packageJsonPath)) {
        packageJsonPaths.push(packageJsonPath);
      }
    }
  }
  return packageJsonPaths;
};
var findPackageJsons = async (cwd) => {
  return await discoverWorkspaces(cwd);
};
var checkForUpdates = async (packageJsonPath) => {
  const packageJsonContent = await readFile(packageJsonPath, "utf-8");
  const packageJson = JSON.parse(packageJsonContent);
  const updates = [];
  if (packageJson.dependencies) {
    for (const depName of DECO_DEPENDENCIES) {
      const currentVersionString = packageJson.dependencies[depName];
      if (currentVersionString) {
        try {
          const currentVersion = parseCurrentVersion(currentVersionString);
          const latestVersion = await getLatestVersion2(depName);
          if (currentVersion !== latestVersion) {
            updates.push({
              name: depName,
              currentVersion,
              latestVersion,
              isDev: false,
              packagePath: packageJsonPath
            });
          }
        } catch (error) {
          console.warn(
            chalk5.yellow(
              `\u26A0\uFE0F  Failed to check updates for ${depName}: ${error instanceof Error ? error.message : String(error)}`
            )
          );
        }
      }
    }
  }
  if (packageJson.devDependencies) {
    for (const depName of DECO_DEV_DEPENDENCIES) {
      const currentVersionString = packageJson.devDependencies[depName];
      if (currentVersionString) {
        try {
          const currentVersion = parseCurrentVersion(currentVersionString);
          const latestVersion = await getLatestVersion2(depName);
          if (currentVersion !== latestVersion) {
            updates.push({
              name: depName,
              currentVersion,
              latestVersion,
              isDev: true,
              packagePath: packageJsonPath
            });
          }
        } catch (error) {
          console.warn(
            chalk5.yellow(
              `\u26A0\uFE0F  Failed to check updates for ${depName}: ${error instanceof Error ? error.message : String(error)}`
            )
          );
        }
      }
    }
  }
  return updates;
};
var checkAllPackagesForUpdates = async (packageJsonPaths) => {
  const allUpdates = [];
  for (const packageJsonPath of packageJsonPaths) {
    try {
      const updates = await checkForUpdates(packageJsonPath);
      allUpdates.push(...updates);
    } catch (error) {
      console.warn(
        chalk5.yellow(
          `\u26A0\uFE0F  Failed to check updates for ${packageJsonPath}: ${error instanceof Error ? error.message : String(error)}`
        )
      );
    }
  }
  return allUpdates;
};
var applyUpdates = async (updates) => {
  const updatesByPackage = /* @__PURE__ */ new Map();
  for (const update2 of updates) {
    if (!updatesByPackage.has(update2.packagePath)) {
      updatesByPackage.set(update2.packagePath, []);
    }
    updatesByPackage.get(update2.packagePath).push(update2);
  }
  for (const [packageJsonPath, packageUpdates] of updatesByPackage) {
    const packageJsonContent = await readFile(packageJsonPath, "utf-8");
    const packageJson = JSON.parse(packageJsonContent);
    for (const update2 of packageUpdates) {
      const newVersionString = formatVersionForPackageJson(
        update2.name,
        update2.latestVersion
      );
      if (update2.isDev && packageJson.devDependencies) {
        packageJson.devDependencies[update2.name] = newVersionString;
      } else if (!update2.isDev && packageJson.dependencies) {
        packageJson.dependencies[update2.name] = newVersionString;
      }
      const relativePath = packageJsonPath.replace(process28.cwd(), ".");
      console.log(
        chalk5.green(
          `\u2705 Updated ${update2.name} in ${relativePath}: ${update2.currentVersion} \u2192 ${update2.latestVersion}`
        )
      );
    }
    await writeFile(
      packageJsonPath,
      JSON.stringify(packageJson, null, 2) + "\n"
    );
  }
};
async function updateCommand(options) {
  try {
    const cwd = process28.cwd();
    console.log(chalk5.blue("\u{1F50D} Searching for Deco dependencies to update..."));
    const packageJsonPaths = await findPackageJsons(cwd);
    if (packageJsonPaths.length === 1) {
      console.log(chalk5.gray(`Found package.json at: ${packageJsonPaths[0]}`));
    } else {
      console.log(
        chalk5.gray(
          `Found ${packageJsonPaths.length} package.json files in workspace:`
        )
      );
      for (const path4 of packageJsonPaths) {
        const relativePath = path4.replace(cwd, ".");
        console.log(chalk5.gray(`  - ${relativePath}`));
      }
    }
    const updates = await checkAllPackagesForUpdates(packageJsonPaths);
    if (updates.length === 0) {
      console.log(chalk5.green("\u2705 All Deco dependencies are up to date!"));
      return;
    }
    console.log();
    console.log(chalk5.yellow("\u{1F4E6} Available updates:"));
    for (const update2 of updates) {
      const depType = update2.isDev ? "(dev)" : "";
      const relativePath = update2.packagePath.replace(cwd, ".");
      console.log(
        chalk5.blue(
          `  ${update2.name} ${depType} in ${relativePath}: ${update2.currentVersion} \u2192 ${update2.latestVersion}`
        )
      );
    }
    console.log();
    let confirmed = options.yes || false;
    if (!confirmed) {
      const response = await inquirer6.prompt([
        {
          type: "confirm",
          name: "confirmed",
          message: `Update ${updates.length} Deco ${updates.length === 1 ? "dependency" : "dependencies"}?`,
          default: true
        }
      ]);
      confirmed = response.confirmed;
    }
    if (!confirmed) {
      console.log(chalk5.gray("Update cancelled."));
      return;
    }
    console.log(chalk5.yellow("\u{1F504} Updating dependencies..."));
    await applyUpdates(updates);
    console.log();
    console.log(chalk5.green("\u{1F389} Dependencies updated successfully!"));
    console.log(
      chalk5.blue(
        "\u{1F4A1} Don't forget to run your package manager to install the new versions."
      )
    );
  } catch (error) {
    console.error(
      chalk5.red("\u274C Failed to update dependencies:"),
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}
async function addCommand({ workspace, local }) {
  try {
    const session = await readSession();
    if (!session) {
      console.error("\u274C No session found. Please run 'deco login' first.");
      return;
    }
    const config = await getConfig({
      inlineOptions: { workspace, local }
    }).catch(() => ({
      workspace: workspace || session.workspace || "default",
      bindings: [],
      local: local || false,
      enable_workflows: true
    }));
    console.log(`\u{1F4C1} Using workspace: ${config.workspace}`);
    console.log("\u{1F50D} Fetching available integrations...");
    const selectedBindings = await promptIntegrations(
      config.local,
      config.workspace
    );
    if (selectedBindings.length === 0) {
      console.log("\u2139\uFE0F  No integrations selected. Nothing to add.");
      return;
    }
    console.log(`\u2705 Selected ${selectedBindings.length} integration(s)`);
    const newBindings = [];
    for (const binding of selectedBindings) {
      const integrationBinding = binding;
      const { bindingName } = await inquirer6.prompt([
        {
          type: "input",
          name: "bindingName",
          message: `Enter binding name for integration "${integrationBinding.integration_id}":`,
          default: integrationBinding.name,
          validate: (value) => {
            if (!value.trim()) {
              return "Binding name cannot be empty";
            }
            if (!/^[A-Z_][A-Z0-9_]*$/.test(value)) {
              return "Binding name must be uppercase with underscores (e.g., MY_INTEGRATION)";
            }
            return true;
          }
        }
      ]);
      newBindings.push({
        name: bindingName,
        type: "mcp",
        integration_id: integrationBinding.integration_id
      });
    }
    const currentWranglerConfig = await readWranglerConfig();
    const currentBindings = currentWranglerConfig.deco?.bindings || [];
    const allBindings = [...currentBindings, ...newBindings];
    const updatedConfig = {
      ...config,
      bindings: allBindings
    };
    await writeConfigFile(updatedConfig);
    console.log(`\u2705 Added ${newBindings.length} integration(s) successfully!`);
    newBindings.forEach((binding) => {
      const id = "integration_id" in binding ? binding.integration_id : "integration_name" in binding ? binding.integration_name : "unknown";
      console.log(`  - ${binding.name} (${id})`);
    });
    console.log("\n\u{1F4A1} Run 'deco gen' to update your environment types.");
    console.log("\u{1F389} Your integrations are ready to use!");
  } catch (error) {
    console.error(
      "\u274C Failed to add integrations:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}
inquirer6.registerPrompt("search-checkbox", inquirerSearchCheckbox);
async function promptRegistry(local = false, workspace = "") {
  const session = await readSession();
  if (!session) {
    throw new Error("No session found. Please run 'deco login' first.");
  }
  const client = await createWorkspaceClient({ workspace, local });
  try {
    const response = await client.callTool(
      {
        name: "DECO_INTEGRATIONS_SEARCH",
        arguments: { query: "" }
        // Empty query returns all apps
      },
      // @ts-expect-error We need to refactor DECO_INTEGRATIONS_SEARCH to use a proper schema
      z.any()
    );
    if (response.isError) {
      throw new Error("Failed to fetch registry apps");
    }
    const registryResponse = response.structuredContent?.integrations;
    const apps = (registryResponse || []).sort((a, b) => {
      if (a.verified && !b.verified) return -1;
      if (!a.verified && b.verified) return 1;
      return a.name.localeCompare(b.name);
    });
    if (!apps || apps.length === 0) {
      throw new Error("No registry apps found.");
    }
    const options = apps.map((app) => ({
      name: `${app.friendlyName || app.name}${app.verified ? " \u2713" : ""} - ${app.description || "No description"}`,
      value: app.appName,
      short: app.friendlyName || app.name
    }));
    const { selectedAppNames } = await inquirer6.prompt([
      {
        type: "search-checkbox",
        name: "selectedAppNames",
        message: "Select apps from registry (use space to select, enter to confirm):",
        choices: options,
        searchable: true,
        highlight: true,
        searchText: "Type to search registry apps:",
        emptyText: "No apps found matching your search."
      }
    ]);
    const selectedApps = apps.filter(
      (app) => selectedAppNames.includes(app.appName)
    );
    return selectedApps.map(({ friendlyName, name, appName }) => ({
      name: sanitizeConstantName(friendlyName || name),
      type: "mcp",
      integration_name: appName
    }));
  } finally {
    await client.close();
  }
}
async function addRegistryCommand({
  workspace,
  local,
  appName,
  skipGen = false
}) {
  try {
    const session = await readSession();
    if (!session) {
      console.error("\u274C No session found. Please run 'deco login' first.");
      return;
    }
    const config = await getConfig({
      inlineOptions: { workspace, local }
    }).catch(() => ({
      workspace: workspace || session.workspace || "default",
      bindings: [],
      local: local || false,
      enable_workflows: true
    }));
    console.log(`\u{1F4C1} Using workspace: ${config.workspace}`);
    let selectedBindings;
    if (appName) {
      console.log(`\u{1F50D} Searching registry for "${appName}"...`);
      const apiClient = await createWorkspaceClientStub({
        local: config.local
      });
      const response = await apiClient.callTool({
        name: "REGISTRY_GET_APP",
        arguments: { name: appName }
      });
      if (response.isError) {
        const errorText = response.content?.[0]?.text ?? `App "${appName}" not found in registry`;
        throw new Error(errorText);
      }
      const app = response.structuredContent;
      selectedBindings = [
        {
          name: sanitizeConstantName(app.friendlyName || app.name),
          type: "mcp",
          integration_name: app.appName
        }
      ];
      console.log(`\u2705 Found app: ${app.friendlyName || app.name}`);
    } else {
      console.log("\u{1F50D} Searching registry for available apps...");
      selectedBindings = await promptRegistry(config.local, config.workspace);
      if (selectedBindings.length === 0) {
        console.log("\u2139\uFE0F  No apps selected. Nothing to add.");
        return;
      }
      console.log(
        `\u2705 Selected ${selectedBindings.length} app(s) from registry`
      );
    }
    const newBindings = [];
    for (const binding of selectedBindings) {
      const registryBinding = binding;
      const { bindingName } = await inquirer6.prompt([
        {
          type: "input",
          name: "bindingName",
          message: `Enter binding name for app "${registryBinding.integration_name}":`,
          default: registryBinding.name,
          validate: (value) => {
            if (!value.trim()) {
              return "Binding name cannot be empty";
            }
            if (!/^[A-Z_][A-Z0-9_]*$/.test(value)) {
              return "Binding name must be uppercase with underscores (e.g., MY_APP)";
            }
            return true;
          }
        }
      ]);
      newBindings.push({
        name: bindingName,
        type: "mcp",
        integration_name: registryBinding.integration_name
      });
    }
    const currentWranglerConfig = await readWranglerConfig();
    const currentBindings = currentWranglerConfig.deco?.bindings || [];
    const allBindings = [...currentBindings, ...newBindings];
    const updatedConfig = {
      ...config,
      bindings: allBindings
    };
    await writeConfigFile(updatedConfig);
    console.log(`\u2705 Added ${newBindings.length} app(s) successfully!`);
    newBindings.forEach((binding) => {
      const id = "integration_id" in binding ? binding.integration_id : "integration_name" in binding ? binding.integration_name : "unknown";
      console.log(`  - ${binding.name} (${id})`);
    });
    if (!skipGen) {
      console.log("\n\u{1F504} Generating environment types...");
      try {
        const wranglerConfig = await readWranglerConfig();
        const env = await genEnv({
          workspace: config.workspace,
          local: config.local,
          bindings: updatedConfig.bindings,
          selfUrl: `https://${getAppDomain(
            config.workspace,
            wranglerConfig.name ?? "my-app"
          )}/mcp`
        });
        const DEFAULT_OUTPUT_PATH = "shared/deco.gen.ts";
        await writeFile(DEFAULT_OUTPUT_PATH, env);
        console.log(`\u2705 Types generated at ${DEFAULT_OUTPUT_PATH}`);
      } catch (genError) {
        console.warn(
          "\u26A0\uFE0F  Failed to generate types:",
          genError instanceof Error ? genError.message : String(genError)
        );
        console.log("\u{1F4A1} Run 'deco gen' manually to generate types.");
      }
    } else {
      console.log("\n\u{1F4A1} Run 'deco gen' to update your environment types.");
    }
    console.log("\u{1F389} Your apps are ready to use!");
  } catch (error) {
    console.error(
      "\u274C Failed to add registry apps:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}
async function autocompleteIntegrations(partial) {
  try {
    const config = await getConfig({}).catch(() => ({
      workspace: void 0,
      local: false
    }));
    if (!config.workspace) return [];
    const client = await createWorkspaceClient({
      workspace: config.workspace,
      local: config.local
    });
    const response = await client.callTool({
      name: "INTEGRATIONS_LIST",
      arguments: {}
    });
    if (response.isError || !response.structuredContent) return [];
    const integrations = response.structuredContent?.items || [];
    return integrations.map((integration) => integration.id).filter((id) => id.toLowerCase().includes(partial.toLowerCase())).sort();
  } catch {
    return [];
  }
}
async function autocompleteTools(partial, options) {
  try {
    if (!options.integration) return [];
    const config = await getConfig({}).catch(() => ({
      workspace: void 0,
      local: false
    }));
    if (!config.workspace) return [];
    const client = await createWorkspaceClient({
      workspace: config.workspace,
      local: config.local,
      integrationId: options.integration
    });
    const toolsResponse = await client.listTools();
    return toolsResponse.tools.map((tool) => tool.name).filter((name) => name.toLowerCase().includes(partial.toLowerCase())).sort();
  } catch {
    return [];
  }
}
function parseSetArguments(setArgs) {
  const result = {};
  for (const arg of setArgs) {
    const equalIndex = arg.indexOf("=");
    if (equalIndex === -1) {
      throw new Error(
        `Invalid --set argument: ${arg}. Expected format: key=value`
      );
    }
    const key = arg.slice(0, equalIndex);
    const value = arg.slice(equalIndex + 1);
    const keyParts = key.split(".");
    let current = result;
    for (let i = 0; i < keyParts.length - 1; i++) {
      const part = keyParts[i];
      if (!(part in current)) {
        current[part] = {};
      }
      current = current[part];
    }
    const finalKey = keyParts[keyParts.length - 1];
    try {
      current[finalKey] = JSON.parse(value);
    } catch {
      current[finalKey] = value;
    }
  }
  return result;
}
async function callToolCommand(toolName, options) {
  try {
    const config = await getConfig({
      inlineOptions: { workspace: options.workspace }
    });
    if (!config.workspace) {
      throw new Error("No workspace configured. Run 'deco configure' first.");
    }
    let payload = {};
    if (options.payload) {
      try {
        payload = JSON.parse(options.payload);
      } catch (error) {
        throw new Error(
          `Invalid JSON payload: ${error instanceof Error ? error.message : String(error)}`
        );
      }
    }
    if (options.set && options.set.length > 0) {
      const setPayload = parseSetArguments(options.set);
      payload = { ...payload, ...setPayload };
    }
    const client = await createWorkspaceClient({
      workspace: config.workspace,
      local: config.local,
      integrationId: options.integration
    });
    const response = await client.callTool({
      name: toolName,
      arguments: payload
    });
    if (response.isError) {
      const errorMessage = Array.isArray(response.content) ? response.content.map((c) => c.text).join("\n") : "Unknown error occurred";
      throw new Error(errorMessage);
    }
    console.log(JSON.stringify(response.structuredContent, null, 2));
  } catch (error) {
    console.error(
      "\u274C Tool call failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}

// src/commands/completion/completion.ts
async function generateCompletions(options) {
  const { current, previous, line } = options;
  try {
    const words = line.split(/\s+/);
    const commandIndex = words.findIndex((word) => word === "call-tool");
    if (commandIndex === -1) {
      return;
    }
    const args = words.slice(commandIndex + 1);
    const integrationIndex = args.findIndex(
      (arg) => arg === "-i" || arg === "--integration"
    );
    const integration = integrationIndex !== -1 && integrationIndex + 1 < args.length ? args[integrationIndex + 1] : void 0;
    let completions = [];
    if (previous === "-i" || previous === "--integration") {
      completions = await autocompleteIntegrations(current);
    } else if (integration && !current.startsWith("-")) {
      const toolIndex = args.findIndex(
        (arg) => !arg.startsWith("-") && arg !== integration
      );
      if (toolIndex === -1 || args[toolIndex] === current) {
        completions = await autocompleteTools(current, { integration });
      }
    } else if (!current.startsWith("-") && !integration) {
      completions = [
        "-i",
        "--integration",
        "-p",
        "--payload",
        "--set",
        "-w",
        "--workspace"
      ];
    }
    completions.forEach((completion2) => console.log(completion2));
  } catch (error) {
    console.error("Completion error:", error);
  }
}
async function completionCommand(type, options) {
  if (type === "call-tool") {
    await generateCompletions({
      current: options.current || "",
      previous: options.previous || "",
      line: options.line || ""
    });
  }
}
function generateBashCompletionScript() {
  return `#!/bin/bash

# Deco CLI completion script for bash
_deco_completion() {
  local cur prev words cword
  _init_completion || return

  # Check if we're completing for call-tool command
  if [[ "\${words[*]}" == *"call-tool"* ]]; then
    local line="\${COMP_LINE}"
    local completions
    
    # Call the deco CLI completion command
    completions=$(deco completion call-tool --current="$cur" --previous="$prev" --line="$line" 2>/dev/null)
    
    if [[ $? -eq 0 && -n "$completions" ]]; then
      COMPREPLY=($(compgen -W "$completions" -- "$cur"))
      return 0
    fi
  fi

  # Default completion for other commands
  case $prev in
    -w|--workspace)
      # Complete workspace names (could be enhanced to fetch from config)
      return 0
      ;;
    *)
      # Complete with available subcommands and options
      COMPREPLY=($(compgen -W "login logout whoami configure hosting dev add call-tool upgrade update link gen create" -- "$cur"))
      ;;
  esac
}

# Register the completion function
complete -F _deco_completion deco
`;
}
function generateZshCompletionScript() {
  return `#compdef deco

# Deco CLI completion script for zsh
_deco() {
  local context state state_descr line
  typeset -A opt_args

  _arguments -C \\
    '1: :_deco_commands' \\
    '*:: :->args'

  case \${words[1]} in
    call-tool)
      _deco_call_tool
      ;;
  esac
}

_deco_commands() {
  local commands
  commands=(
    'login:Log in to admin.decocms.com'
    'logout:Log out and remove session data'
    'whoami:Print current session info'
    'configure:Save configuration options'
    'hosting:Manage hosting apps'
    'dev:Start development server'
    'add:Add integrations'
    'call-tool:Call a tool on an integration'
    'upgrade:Upgrade the CLI'
    'update:Update dependencies'
    'link:Link project to remote domain'
    'gen:Generate environment'
    'create:Create new project'
  )
  _describe 'commands' commands
}

_deco_call_tool() {
  local context state state_descr line
  typeset -A opt_args

  _arguments -C \\
    '-i[Integration ID]:integration:_deco_integrations' \\
    '--integration[Integration ID]:integration:_deco_integrations' \\
    '-p[JSON payload]:payload:' \\
    '--payload[JSON payload]:payload:' \\
    '--set[Set key=value]:keyvalue:' \\
    '-w[Workspace name]:workspace:' \\
    '--workspace[Workspace name]:workspace:' \\
    '1: :_deco_tools'
}

_deco_integrations() {
  local integrations
  integrations=($(deco completion call-tool --current="$PREFIX" --previous="-i" --line="$BUFFER" 2>/dev/null))
  _describe 'integrations' integrations
}

_deco_tools() {
  local tools integration
  # Extract integration from command line
  if [[ "$words" == *"-i"* ]]; then
    local i_index=\${words[(i)-i]}
    if (( i_index < \${#words} )); then
      integration=\${words[i_index+1]}
    fi
  elif [[ "$words" == *"--integration"* ]]; then
    local int_index=\${words[(i)--integration]}
    if (( int_index < \${#words} )); then
      integration=\${words[int_index+1]}
    fi
  fi
  
  if [[ -n "$integration" ]]; then
    tools=($(deco completion call-tool --current="$PREFIX" --previous="" --line="$BUFFER" 2>/dev/null))
    _describe 'tools' tools
  fi
}

_deco "$@"
`;
}
async function installCompletionCommand(shell, options = {}) {
  try {
    const targetShell = shell || process28.env.SHELL?.split("/").pop() || "bash";
    let script;
    let filename;
    let installPath;
    switch (targetShell) {
      case "bash": {
        script = generateBashCompletionScript();
        filename = "deco-completion.bash";
        installPath = options.output || join(homedir(), ".local/share/bash-completion/completions/deco");
        break;
      }
      case "zsh": {
        script = generateZshCompletionScript();
        filename = "_deco";
        const zshDirs = [
          join(homedir(), ".zsh/completions"),
          "/usr/local/share/zsh/site-functions",
          "/opt/homebrew/share/zsh/site-functions"
        ];
        installPath = options.output || zshDirs[0];
        break;
      }
      default: {
        console.error(`\u274C Unsupported shell: ${targetShell}`);
        console.log("Supported shells: bash, zsh");
        process28.exit(1);
      }
    }
    const finalPath = options.output || (targetShell === "zsh" ? join(installPath, filename) : installPath);
    await ensureDir(dirname(finalPath));
    await writeFile(finalPath, script, "utf8");
    console.log(`\u2705 Completion script installed to: ${finalPath}`);
    if (!options.output) {
      switch (targetShell) {
        case "bash":
          console.log("");
          console.log("To enable completions, add this to your ~/.bashrc:");
          console.log(`source "${finalPath}"`);
          break;
        case "zsh":
          console.log("");
          console.log("To enable completions, add this to your ~/.zshrc:");
          console.log(`fpath=("${dirname(finalPath)}" $fpath)`);
          console.log("autoload -U compinit && compinit");
          break;
      }
      console.log("");
      console.log("Then restart your shell or run:");
      console.log("source ~/.bashrc  # for bash");
      console.log("source ~/.zshrc   # for zsh");
    }
  } catch (error) {
    console.error(
      "\u274C Failed to install completion:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}
async function fetchFileContent(filePath, branchName, workspace, local) {
  const client = await createWorkspaceClient({
    workspace,
    local
  });
  try {
    const response = await client.callTool({
      name: "READ_FILE",
      arguments: {
        branch: branchName,
        path: filePath
      }
    });
    if (response.isError) {
      const errorMessage = Array.isArray(response.content) ? response.content[0]?.text || "Failed to read file" : "Failed to read file";
      throw new Error(errorMessage);
    }
    const result = response.structuredContent;
    if (!result || !result.content) {
      throw new Error("No content returned from READ_FILE tool");
    }
    return Buffer.from(result.content, "base64");
  } catch (error) {
    console.error(
      `\u274C Failed to fetch content for ${filePath}:`,
      error instanceof Error ? error.message : String(error)
    );
    throw error;
  } finally {
    await client.close();
  }
}
async function putFileContent(filePath, content, branchName, metadata, workspace, local) {
  const client = await createWorkspaceClient({
    workspace,
    local
  });
  try {
    const base64Content = Buffer.isBuffer(content) ? content.toString("base64") : Buffer.from(content).toString("base64");
    const response = await client.callTool({
      name: "PUT_FILE",
      arguments: {
        branch: branchName,
        path: filePath,
        content: { base64: base64Content },
        metadata
      }
    });
    if (response.isError) {
      const errorMessage = Array.isArray(response.content) ? response.content[0]?.text || "Failed to put file" : "Failed to put file";
      throw new Error(errorMessage);
    }
  } catch (error) {
    console.error(
      `\u274C Failed to put file ${filePath}:`,
      error instanceof Error ? error.message : String(error)
    );
    throw error;
  } finally {
    await client.close();
  }
}
async function watch2(options, callback) {
  const {
    branchName,
    fromCtime = 1,
    pathFilter,
    workspace,
    local = false
  } = options;
  console.log(`\u{1F4E1} Watching branch "${branchName}" for changes...`);
  if (pathFilter) {
    console.log(`   \u{1F50D} Path filter: ${pathFilter}`);
  }
  const { headers, url: baseUrl } = await workspaceClientParams({
    workspace,
    local,
    pathname: "/deconfig/watch"
  });
  const searchParams = new URLSearchParams();
  searchParams.set("branchName", branchName);
  searchParams.set("fromCtime", fromCtime.toString());
  if (pathFilter) {
    searchParams.set("pathFilter", pathFilter);
  }
  const sseUrlObj = new URL(baseUrl);
  sseUrlObj.search = searchParams.toString();
  const sseUrl = sseUrlObj.href;
  let retryCount = 0;
  const maxRetries = 5;
  const retryDelay = 2e3;
  const connect2 = async () => {
    console.log(`\u{1F504} Connecting to SSE stream... (attempt ${retryCount + 1})`);
    try {
      const response = await fetch(sseUrl, {
        headers: {
          Accept: "text/event-stream",
          "Cache-Control": "no-cache",
          ...headers
        }
      });
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }
      if (!response.body) {
        throw new Error("No response body");
      }
      console.log("\u2705 Connected to SSE stream");
      retryCount = 0;
      const reader = response.body.getReader();
      const decoder = new TextDecoder();
      let buffer = "";
      try {
        while (true) {
          const { done, value } = await reader.read();
          if (done) {
            console.log("\u{1F4E1} SSE stream ended");
            break;
          }
          const chunk = decoder.decode(value, { stream: true });
          console.log(`\u{1F4E6} Received chunk: ${JSON.stringify(chunk)}`);
          buffer += chunk;
          const lines = buffer.split("\n");
          buffer = lines.pop() || "";
          for (const line of lines) {
            if (line.trim()) {
              console.log(`\u{1F4DD} Processing line: ${JSON.stringify(line)}`);
            }
            await processSSELine(line, branchName, workspace, local, callback);
          }
        }
      } catch (error) {
        console.error("\u274C Error reading SSE stream:", error);
        throw error;
      }
    } catch (error) {
      console.error(
        "\u274C SSE connection failed:",
        error instanceof Error ? error.message : String(error)
      );
      if (retryCount < maxRetries) {
        retryCount++;
        console.log(`\u23F3 Retrying in ${retryDelay / 1e3} seconds...`);
        setTimeout(() => {
          connect2().catch((retryError) => {
            console.error(
              "\u274C Retry failed:",
              retryError instanceof Error ? retryError.message : String(retryError)
            );
          });
        }, retryDelay);
      } else {
        throw new Error(`Failed to connect after ${maxRetries} attempts`);
      }
    }
  };
  await connect2();
}
async function processSSELine(line, branchName, workspace, local, callback) {
  if (!line.trim()) return;
  if (line.startsWith("event:")) {
    line.substring(6).trim();
    return;
  }
  if (line.startsWith("data:")) {
    const jsonData = line.substring(5).trim();
    console.log(`\u{1F50D} Parsing JSON data: ${jsonData}`);
    try {
      const event = JSON.parse(jsonData);
      console.log(`\u2705 Parsed event:`, event);
      const eventWithContent = { ...event };
      if (event.type === "added" || event.type === "modified") {
        console.log(`\u{1F4E5} Fetching content for ${event.path}...`);
        try {
          eventWithContent.content = await fetchFileContent(
            event.path,
            branchName,
            workspace,
            local
          );
          console.log(
            `\u2705 Fetched content: ${eventWithContent.content?.length} bytes`
          );
        } catch (error) {
          console.error(
            `\u274C Failed to fetch content for ${event.path}:`,
            error instanceof Error ? error.message : String(error)
          );
        }
      }
      console.log(`\u{1F504} Calling callback for event: ${event.type} ${event.path}`);
      await callback(eventWithContent);
    } catch (error) {
      console.error("\u274C Failed to parse SSE data:", jsonData, error);
    }
  }
}
async function getCommand(options) {
  const { path: filePath, branch, output, workspace, local } = options;
  console.log(`\u{1F4E5} Getting file "${filePath}" from branch "${branch}"`);
  try {
    const content = await fetchFileContent(filePath, branch, workspace, local);
    if (output) {
      const dir = dirname(output);
      if (!existsSync(dir)) {
        mkdirSync(dir, { recursive: true });
      }
      writeFileSync(output, content);
      console.log(`\u2705 File saved to: ${output} (${content.length} bytes)`);
    } else {
      process28.stdout.write(content);
    }
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    if (errorMessage.includes("Session not found") || errorMessage.includes("Session expired")) {
      console.error("\u{1F4A5} Get failed: Authentication required");
      console.error(
        "   Please run 'deco login' first to authenticate with deco.chat"
      );
    } else if (errorMessage.includes("File not found")) {
      console.error(`\u{1F4A5} File not found: ${filePath} (branch: ${branch})`);
    } else {
      console.error("\u{1F4A5} Get failed:", errorMessage);
    }
    process28.exit(1);
  }
}
async function putCommand(options) {
  const {
    path: filePath,
    branch,
    file,
    content,
    metadata,
    workspace,
    local
  } = options;
  console.log(`\u{1F4E4} Putting file "${filePath}" to branch "${branch}"`);
  try {
    let fileContent;
    if (file) {
      if (!existsSync(file)) {
        throw new Error(`Local file not found: ${file}`);
      }
      fileContent = readFileSync(file);
      console.log(`   \u{1F4C1} Reading from: ${file}`);
    } else if (content !== void 0) {
      fileContent = content;
    } else {
      console.log("   \u{1F4DD} Reading from stdin...");
      const chunks = [];
      for await (const chunk of process28.stdin) {
        chunks.push(chunk);
      }
      fileContent = Buffer.concat(chunks);
    }
    let parsedMetadata;
    if (metadata) {
      try {
        parsedMetadata = JSON.parse(metadata);
      } catch {
        throw new Error(`Invalid metadata JSON: ${metadata}`);
      }
    }
    await putFileContent(
      filePath,
      fileContent,
      branch,
      parsedMetadata,
      workspace,
      local
    );
    const size = Buffer.isBuffer(fileContent) ? fileContent.length : Buffer.from(fileContent).length;
    console.log(`\u2705 File uploaded successfully (${size} bytes)`);
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    if (errorMessage.includes("Session not found") || errorMessage.includes("Session expired")) {
      console.error("\u{1F4A5} Put failed: Authentication required");
      console.error(
        "   Please run 'deco login' first to authenticate with deco.chat"
      );
    } else {
      console.error("\u{1F4A5} Put failed:", errorMessage);
    }
    process28.exit(1);
  }
}
async function watchCommand(options) {
  const { path: pathFilter, branch, fromCtime, workspace, local } = options;
  console.log(`\u{1F440} Watching branch "${branch}" for changes`);
  if (pathFilter) {
    console.log(`   \u{1F3AF} Filtering path: ${pathFilter}`);
  }
  const logChanges = (event) => {
    const timestamp = new Date(event.timestamp).toISOString();
    console.log(`[${timestamp}] \u{1F4DD} ${event.type.toUpperCase()}: ${event.path}`);
    if (event.content) {
      console.log(`   \u{1F4CA} Size: ${event.content.length} bytes`);
    }
    if (event.metadata) {
      console.log(
        `   \u23F0 Modified: ${new Date(event.metadata.mtime).toISOString()}`
      );
    }
    console.log(`   \u{1F522} Patch ID: ${event.patchId}`);
    console.log("");
  };
  process28.on("SIGINT", () => {
    console.log("\n\u{1F6D1} Received SIGINT, shutting down gracefully...");
    process28.exit(0);
  });
  process28.on("SIGTERM", () => {
    console.log("\n\u{1F6D1} Received SIGTERM, shutting down gracefully...");
    process28.exit(0);
  });
  try {
    await watch2(
      {
        branchName: branch,
        pathFilter,
        fromCtime,
        workspace,
        local
      },
      logChanges
    );
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    if (errorMessage.includes("Session not found") || errorMessage.includes("Session expired")) {
      console.error("\u{1F4A5} Watch failed: Authentication required");
      console.error(
        "   Please run 'deco login' first to authenticate with deco.chat"
      );
    } else {
      console.error("\u{1F4A5} Watch failed:", errorMessage);
    }
    process28.exit(1);
  }
}
async function cloneCommand(options) {
  const { branchName, path: localPath, pathFilter, workspace, local } = options;
  console.log(`\u{1F4E5} Cloning branch "${branchName}" to local path: ${localPath}`);
  if (!existsSync(localPath)) {
    mkdirSync(localPath, { recursive: true });
    console.log(`\u{1F4C1} Created local directory: ${localPath}`);
  }
  const { createWorkspaceClient: createWorkspaceClient2 } = await import('./mcp-7MUYOFGZ.js');
  const client = await createWorkspaceClient2({ workspace, local });
  try {
    const response = await client.callTool({
      name: "LIST_FILES",
      arguments: {
        branch: branchName,
        prefix: pathFilter
      }
    });
    if (response.isError) {
      const errorMessage = Array.isArray(response.content) ? response.content[0]?.text || "Failed to list files" : "Failed to list files";
      throw new Error(errorMessage);
    }
    const result = response.structuredContent;
    console.log(`\u{1F4CB} Found ${result.count} files to clone`);
    for (const [filePath] of Object.entries(result.files)) {
      const localFilePath = join(
        localPath,
        filePath.startsWith("/") ? filePath.slice(1) : filePath
      );
      try {
        console.log(`\u{1F4E5} Downloading: ${filePath}`);
        const content = await fetchFileContent(
          filePath,
          branchName,
          workspace,
          local
        );
        const dir = dirname(localFilePath);
        if (!existsSync(dir)) {
          mkdirSync(dir, { recursive: true });
        }
        writeFileSync(localFilePath, content);
        console.log(
          `   \u2705 Cloned to: ${localFilePath} (${content.length} bytes)`
        );
      } catch (error) {
        console.error(
          `   \u274C Failed to clone ${filePath}:`,
          error instanceof Error ? error.message : String(error)
        );
      }
    }
    console.log(
      `\u{1F389} Clone completed! Downloaded ${result.count} files to ${localPath}`
    );
    await writeDeconfigHead({
      workspace: workspace || "",
      branch: branchName,
      path: localPath,
      pathFilter,
      local
    });
    console.log(`\u{1F4DD} Saved deconfig HEAD to .deconfig/head`);
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    if (errorMessage.includes("Session not found") || errorMessage.includes("Session expired")) {
      console.error("\u{1F4A5} Clone failed: Authentication required");
      console.error(
        "   Please run 'deco login' first to authenticate with deco.chat"
      );
    } else {
      console.error("\u{1F4A5} Clone failed:", errorMessage);
    }
    process28.exit(1);
  } finally {
    await client.close();
  }
}
var DeconfigIgnore = class {
  ig;
  rootPath;
  patternCount = 0;
  constructor(rootPath) {
    this.rootPath = rootPath;
    this.ig = ignore();
    this.loadIgnoreFiles();
  }
  /**
   * Load .deconfigignore files and add default patterns
   */
  loadIgnoreFiles() {
    this.addDefaultPatterns();
    const ignoreFilePath = join(this.rootPath, ".deconfigignore");
    if (existsSync(ignoreFilePath)) {
      this.loadIgnoreFile(ignoreFilePath);
    }
  }
  /**
   * Add default ignore patterns
   */
  addDefaultPatterns() {
    const defaultPatterns = [
      "node_modules/",
      ".git/",
      ".deconfig/",
      ".DS_Store",
      "*.tmp",
      "*.temp",
      ".env.local",
      ".env.*.local"
    ];
    this.ig.add(defaultPatterns);
    this.patternCount += defaultPatterns.length;
  }
  /**
   * Load patterns from a specific .deconfigignore file
   */
  loadIgnoreFile(filePath) {
    try {
      const content = readFileSync(filePath, "utf-8");
      const lines = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
      if (lines.length > 0) {
        this.ig.add(lines);
        this.patternCount += lines.length;
      }
    } catch (error) {
      console.warn(
        `Warning: Could not read ignore file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
      );
    }
  }
  /**
   * Check if a file path should be ignored
   */
  isIgnored(filePath) {
    const relativePath = relative(this.rootPath, filePath);
    if (relativePath.startsWith("..")) {
      return false;
    }
    const normalizedPath = relativePath.replace(/\\/g, "/");
    return this.ig.ignores(normalizedPath);
  }
  /**
   * Filter an array of file paths, removing ignored ones
   */
  filter(filePaths) {
    const relativePaths = filePaths.map((path4) => {
      const rel = relative(this.rootPath, path4);
      return rel.replace(/\\/g, "/");
    });
    const filtered = this.ig.filter(relativePaths);
    return filtered.map((relPath) => join(this.rootPath, relPath));
  }
  /**
   * Get the number of loaded patterns (for logging)
   */
  getPatternCount() {
    return this.patternCount;
  }
  /**
   * Create RegExp patterns compatible with the walk() function
   * Since the ignore package handles complex logic, we create a single
   * RegExp that checks each path against the ignore checker
   */
  toWalkSkipPatterns() {
    const ignoreRegex = new RegExp(".*");
    ignoreRegex.test = (path4) => {
      const relativePath = relative(this.rootPath, path4);
      const normalizedPath = relativePath.replace(/\\/g, "/");
      return this.ig.ignores(normalizedPath);
    };
    return [ignoreRegex];
  }
};
function createIgnoreChecker(rootPath) {
  return new DeconfigIgnore(rootPath);
}
async function pushSingleFile(localFilePath, remotePath, branchName, workspace, local) {
  try {
    const stats = statSync(localFilePath);
    console.log(`\u{1F4E4} Pushing: ${remotePath} (${stats.size} bytes)`);
    const content = readFileSync(localFilePath);
    await putFileContent(
      remotePath,
      content,
      branchName,
      void 0,
      // no metadata for now
      workspace,
      local
    );
    console.log(`   \u2705 Pushed: ${remotePath}`);
  } catch (error) {
    console.error(
      `   \u274C Failed to push ${remotePath}:`,
      error instanceof Error ? error.message : String(error)
    );
  }
}
async function watchAndSync(options) {
  const { localPath, branchName, pathFilter, workspace, local } = options;
  console.log(`\u{1F440} Watching directory "${localPath}" for changes...`);
  console.log("   Press Ctrl+C to stop watching");
  const ignoreChecker = createIgnoreChecker(localPath);
  console.log(`\u{1F4CB} Loaded ${ignoreChecker.getPatternCount()} ignore patterns`);
  const debounceMap = /* @__PURE__ */ new Map();
  const DEBOUNCE_DELAY = 500;
  try {
    const watcher = watch(localPath, { recursive: true }, (_, filename) => {
      if (!filename) return;
      const fullPath = join(localPath, filename);
      const relativePath = relative(localPath, fullPath);
      const remotePath = `/${relativePath.replace(/\\/g, "/")}`;
      if (pathFilter && !remotePath.startsWith(pathFilter)) {
        return;
      }
      if (ignoreChecker.isIgnored(fullPath)) {
        return;
      }
      try {
        const stats = statSync(fullPath);
        if (!stats.isFile()) {
          return;
        }
      } catch {
        return;
      }
      const existingTimeout = debounceMap.get(fullPath);
      if (existingTimeout) {
        clearTimeout(existingTimeout);
      }
      const timeout = setTimeout(async () => {
        console.log(`\u{1F504} File changed: ${remotePath}`);
        await pushSingleFile(
          fullPath,
          remotePath,
          branchName,
          workspace,
          local
        );
        debounceMap.delete(fullPath);
      }, DEBOUNCE_DELAY);
      debounceMap.set(fullPath, timeout);
    });
    const cleanup = () => {
      console.log("\n\u{1F6D1} Stopping file watcher...");
      watcher.close();
      for (const timeout of debounceMap.values()) {
        clearTimeout(timeout);
      }
      process28.exit(0);
    };
    process28.on("SIGINT", cleanup);
    process28.on("SIGTERM", cleanup);
    await new Promise(() => {
    });
  } catch (error) {
    console.error(
      "\u274C Watch failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
}
function calculateFileHash(filePath) {
  const content = readFileSync(filePath);
  return createHash("sha256").update(content).digest("hex");
}
function extractHashFromAddress(address) {
  const parts = address.split(":");
  return parts.length >= 3 ? parts[2] : "";
}
async function pushCommand(options) {
  const {
    branchName,
    path: localPath,
    pathFilter,
    workspace,
    local,
    dryRun,
    watch: watchMode
  } = options;
  console.log(
    `\u{1F4E4} ${watchMode ? "Watching and pushing" : "Pushing"} files from "${localPath}" to branch "${branchName}"${dryRun ? " (dry run)" : ""}...`
  );
  try {
    const pathStats = statSync(localPath);
    if (!pathStats.isDirectory()) {
      throw new Error(`Path is not a directory: ${localPath}`);
    }
    const ignoreChecker = createIgnoreChecker(localPath);
    console.log(`\u{1F4CB} Loaded ${ignoreChecker.getPatternCount()} ignore patterns`);
    if (watchMode) {
      if (dryRun) {
        console.error("\u274C Cannot use --watch with --dry-run");
        process28.exit(1);
      }
      console.log("\u{1F680} Performing initial push...");
      await pushCommand({
        ...options,
        watch: false
        // Disable watch for initial push
      });
      console.log("\u2705 Initial push completed, starting watch mode...\n");
      await watchAndSync({
        localPath,
        branchName,
        pathFilter,
        workspace,
        local
      });
      return;
    }
    const currentLocalFiles = /* @__PURE__ */ new Map();
    for await (const entry of walk(localPath, {
      includeFiles: true,
      includeDirs: false,
      skip: ignoreChecker.toWalkSkipPatterns()
    })) {
      const relativePath = relative(localPath, entry.path);
      const remotePath = `/${relativePath.replace(/\\/g, "/")}`;
      if (pathFilter && !remotePath.startsWith(pathFilter)) {
        continue;
      }
      const stats = statSync(entry.path);
      const hash = calculateFileHash(entry.path);
      currentLocalFiles.set(remotePath, {
        hash,
        size: stats.size
      });
    }
    const client = await createWorkspaceClient({ workspace, local });
    let remoteFiles = {};
    try {
      const response = await client.callTool({
        name: "LIST_FILES",
        arguments: {
          branch: branchName,
          prefix: pathFilter
        }
      });
      if (response.isError) {
        const errorMessage = Array.isArray(response.content) ? response.content[0]?.text || "Failed to list files" : "Failed to list files";
        throw new Error(errorMessage);
      }
      const result = response.structuredContent;
      remoteFiles = result.files;
      console.log(`\u{1F4CB} Found ${result.count} remote files`);
    } finally {
      await client.close();
    }
    const toUpload = [];
    const toUpdate = [];
    for (const [remotePath, localInfo] of currentLocalFiles) {
      const remoteInfo = remoteFiles[remotePath];
      if (!remoteInfo) {
        toUpload.push(remotePath);
      } else {
        const remoteHash = extractHashFromAddress(remoteInfo.address);
        if (localInfo.hash !== remoteHash) {
          toUpdate.push(remotePath);
        }
      }
    }
    console.log(
      `\u{1F4CA} Changes detected: ${toUpload.length} new, ${toUpdate.length} modified`
    );
    if (dryRun) {
      if (toUpload.length > 0) {
        console.log("\n\u{1F4E4} Files to upload:");
        for (const path4 of toUpload) {
          const info = currentLocalFiles.get(path4);
          console.log(`   + ${path4} (${info.size} bytes)`);
        }
      }
      if (toUpdate.length > 0) {
        console.log("\n\u{1F4DD} Files to update:");
        for (const path4 of toUpdate) {
          const info = currentLocalFiles.get(path4);
          console.log(`   ~ ${path4} (${info.size} bytes)`);
        }
      }
      console.log(
        `
\u2705 Dry run completed. ${toUpload.length + toUpdate.length} changes detected.`
      );
      return;
    }
    let successCount = 0;
    let errorCount = 0;
    const totalOperations = toUpload.length + toUpdate.length;
    if (totalOperations === 0) {
      console.log("\u2705 No changes detected. Branch is up to date!");
      return;
    }
    for (const remotePath of [...toUpload, ...toUpdate]) {
      try {
        const isUpdate = toUpdate.includes(remotePath);
        const localInfo = currentLocalFiles.get(remotePath);
        const localFilePath = join(localPath, remotePath.substring(1));
        console.log(
          `\u{1F4E4} ${isUpdate ? "Updating" : "Uploading"}: ${remotePath} (${localInfo.size} bytes)`
        );
        const content = readFileSync(localFilePath);
        await putFileContent(
          remotePath,
          content,
          branchName,
          void 0,
          // no metadata for now
          workspace,
          local
        );
        console.log(
          `   \u2705 ${isUpdate ? "Updated" : "Uploaded"}: ${remotePath}`
        );
        successCount++;
      } catch (error) {
        console.error(
          `   \u274C Failed to ${toUpdate.includes(remotePath) ? "update" : "upload"} ${remotePath}:`,
          error instanceof Error ? error.message : String(error)
        );
        errorCount++;
      }
    }
    if (errorCount > 0) {
      console.log(
        `
\u26A0\uFE0F  Push completed with errors: ${successCount} succeeded, ${errorCount} failed`
      );
      process28.exit(1);
    } else {
      console.log(
        `
\u{1F389} Push completed successfully! ${successCount} operations completed on ${branchName}`
      );
    }
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    if (errorMessage.includes("Session not found") || errorMessage.includes("Session expired")) {
      console.error("\u{1F4A5} Push failed: Authentication required");
      console.error(
        "   Please run 'deco login' first to authenticate with deco.chat"
      );
    } else {
      console.error("\u{1F4A5} Push failed:", errorMessage);
    }
    process28.exit(1);
  }
}
function getFileHash(filePath) {
  try {
    const content = readFileSync(filePath);
    return createHash("sha256").update(content).digest("hex");
  } catch {
    return "";
  }
}
async function pullCommand(options) {
  const {
    branchName,
    path: localPath,
    pathFilter,
    workspace,
    local,
    dryRun
  } = options;
  console.log(
    `\u{1F4E5} Pulling changes from branch "${branchName}" to "${localPath}"${dryRun ? " (dry run)" : ""}...`
  );
  if (!existsSync(localPath)) {
    mkdirSync(localPath, { recursive: true });
    console.log(`\u{1F4C1} Created local directory: ${localPath}`);
  }
  const { createWorkspaceClient: createWorkspaceClient2 } = await import('./mcp-7MUYOFGZ.js');
  const client = await createWorkspaceClient2({ workspace, local });
  try {
    const response = await client.callTool({
      name: "LIST_FILES",
      arguments: {
        branch: branchName,
        prefix: pathFilter
      }
    });
    if (response.isError) {
      const errorMessage = Array.isArray(response.content) ? response.content[0]?.text || "Failed to list files" : "Failed to list files";
      throw new Error(errorMessage);
    }
    const result = response.structuredContent;
    console.log(`\u{1F4CB} Found ${result.count} remote files`);
    const localFiles = /* @__PURE__ */ new Map();
    if (existsSync(localPath)) {
      const ignoreChecker = createIgnoreChecker(localPath);
      for await (const entry of walk(localPath, {
        includeFiles: true,
        includeDirs: false,
        skip: ignoreChecker.toWalkSkipPatterns()
      })) {
        const relativePath = relative(localPath, entry.path);
        const remotePath = `/${relativePath.replace(/\\/g, "/")}`;
        const hash = getFileHash(entry.path);
        localFiles.set(remotePath, { hash, path: entry.path });
      }
    }
    const toDownload = [];
    const toUpdate = [];
    const toDelete = [];
    for (const [remoteFilePath, remoteMeta] of Object.entries(result.files)) {
      if (pathFilter && !remoteFilePath.startsWith(pathFilter)) {
        continue;
      }
      const localFile = localFiles.get(remoteFilePath);
      if (!localFile) {
        toDownload.push(remoteFilePath);
      } else {
        const parts = (remoteMeta.address || "").split(":");
        const remoteHash = parts.length >= 3 ? parts[2] : "";
        if (!remoteHash || localFile.hash !== remoteHash) {
          toUpdate.push(remoteFilePath);
        }
        localFiles.delete(remoteFilePath);
      }
    }
    for (const [remoteFilePath] of localFiles) {
      if (!pathFilter || remoteFilePath.startsWith(pathFilter)) {
        toDelete.push(remoteFilePath);
      }
    }
    console.log(
      `\u{1F4CA} Changes: ${toDownload.length} new, ${toUpdate.length} modified, ${toDelete.length} to delete`
    );
    if (dryRun) {
      if (toDownload.length > 0) {
        console.log("\n\u{1F4E5} Files to download:");
        toDownload.forEach((path4) => console.log(`   + ${path4}`));
      }
      if (toUpdate.length > 0) {
        console.log("\n\u{1F4DD} Files to update:");
        toUpdate.forEach((path4) => console.log(`   ~ ${path4}`));
      }
      if (toDelete.length > 0) {
        console.log("\n\u{1F5D1}\uFE0F  Files to delete:");
        toDelete.forEach((path4) => console.log(`   - ${path4}`));
      }
      console.log(
        `
\u2705 Dry run completed. ${toDownload.length + toUpdate.length + toDelete.length} changes detected.`
      );
      return;
    }
    let successCount = 0;
    let errorCount = 0;
    for (const filePath of toDownload) {
      try {
        console.log(`\u{1F4E5} Downloading: ${filePath}`);
        const content = await fetchFileContent(
          filePath,
          branchName,
          workspace,
          local
        );
        const localFilePath = join(
          localPath,
          filePath.startsWith("/") ? filePath.slice(1) : filePath
        );
        const dir = dirname(localFilePath);
        if (!existsSync(dir)) {
          mkdirSync(dir, { recursive: true });
        }
        writeFileSync(localFilePath, content);
        console.log(
          `   \u2705 Downloaded: ${localFilePath} (${content.length} bytes)`
        );
        successCount++;
      } catch (error) {
        console.error(
          `   \u274C Failed to download ${filePath}:`,
          error instanceof Error ? error.message : String(error)
        );
        errorCount++;
      }
    }
    for (const filePath of toUpdate) {
      try {
        console.log(`\u{1F4DD} Updating: ${filePath}`);
        const content = await fetchFileContent(
          filePath,
          branchName,
          workspace,
          local
        );
        const localFilePath = join(
          localPath,
          filePath.startsWith("/") ? filePath.slice(1) : filePath
        );
        writeFileSync(localFilePath, content);
        console.log(
          `   \u2705 Updated: ${localFilePath} (${content.length} bytes)`
        );
        successCount++;
      } catch (error) {
        console.error(
          `   \u274C Failed to update ${filePath}:`,
          error instanceof Error ? error.message : String(error)
        );
        errorCount++;
      }
    }
    for (const filePath of toDelete) {
      const localFile = localFiles.get(filePath);
      if (localFile) {
        try {
          console.log(`\u{1F5D1}\uFE0F  Deleting: ${filePath}`);
          unlinkSync(localFile.path);
          console.log(`   \u2705 Deleted: ${localFile.path}`);
          successCount++;
        } catch (error) {
          console.error(
            `   \u274C Failed to delete ${filePath}:`,
            error instanceof Error ? error.message : String(error)
          );
          errorCount++;
        }
      }
    }
    if (errorCount > 0) {
      console.log(
        `
\u26A0\uFE0F  Pull completed with errors: ${successCount} succeeded, ${errorCount} failed`
      );
    } else {
      console.log(
        `
\u{1F389} Pull completed successfully! Applied ${successCount} changes from ${branchName}`
      );
    }
    await writeDeconfigHead({
      workspace: workspace || "",
      branch: branchName,
      path: localPath,
      pathFilter,
      local
    });
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    if (errorMessage.includes("Session not found") || errorMessage.includes("Session expired")) {
      console.error("\u{1F4A5} Pull failed: Authentication required");
      console.error(
        "   Please run 'deco login' first to authenticate with deco.chat"
      );
    } else {
      console.error("\u{1F4A5} Pull failed:", errorMessage);
    }
    process28.exit(1);
  } finally {
    await client.close();
  }
}
async function listCommand(options) {
  const {
    branchName,
    pathFilter,
    workspace,
    local,
    format: format2 = "plainString"
  } = options;
  console.log(`\u{1F4CB} Listing files in branch "${branchName}"...`);
  if (pathFilter) {
    console.log(`   \u{1F50D} Path filter: ${pathFilter}`);
  }
  const { createWorkspaceClient: createWorkspaceClient2 } = await import('./mcp-7MUYOFGZ.js');
  const client = await createWorkspaceClient2({ workspace, local });
  try {
    const response = await client.callTool({
      name: "LIST_FILES",
      arguments: {
        branch: branchName,
        prefix: pathFilter
      }
    });
    if (response.isError) {
      const errorMessage = Array.isArray(response.content) ? response.content[0]?.text || "Failed to list files" : "Failed to list files";
      throw new Error(errorMessage);
    }
    const result = response.structuredContent;
    if (result.count === 0) {
      console.log("\u{1F4C2} No files found in this branch.");
      return;
    }
    console.log(`\u{1F4CB} Found ${result.count} files`);
    const fileChoices = Object.entries(result.files).map(([path4, info]) => {
      const size = formatFileSize(info.sizeInBytes);
      const lastModified = new Date(info.mtime).toLocaleString();
      return {
        name: `${path4} (${size}, modified: ${lastModified})`,
        value: path4,
        short: path4
      };
    });
    fileChoices.push({
      name: "\u{1F6AA} Exit",
      value: "__EXIT__",
      short: "Exit"
    });
    while (true) {
      const { selectedFile } = await inquirer6.prompt([
        {
          type: "list",
          name: "selectedFile",
          message: "Select a file to view its content:",
          choices: fileChoices,
          pageSize: 15
        }
      ]);
      if (selectedFile === "__EXIT__") {
        console.log("\u{1F44B} Goodbye!");
        break;
      }
      try {
        console.log(`
\u{1F4C4} Loading content for: ${selectedFile}`);
        const content = await fetchFileContent(
          selectedFile,
          branchName,
          workspace,
          local
        );
        const fileInfo = result.files[selectedFile];
        console.log(`
${"=".repeat(60)}`);
        console.log(`\u{1F4C1} File: ${selectedFile}`);
        console.log(`\u{1F4CA} Size: ${formatFileSize(fileInfo.sizeInBytes)}`);
        console.log(
          `\u23F0 Modified: ${new Date(fileInfo.mtime).toLocaleString()}`
        );
        console.log(`\u{1F3F7}\uFE0F  Address: ${fileInfo.address}`);
        if (Object.keys(fileInfo.metadata).length > 0) {
          console.log(
            `\u{1F4CB} Metadata: ${JSON.stringify(fileInfo.metadata, null, 2)}`
          );
        }
        console.log(`${"=".repeat(60)}
`);
        let displayContent;
        switch (format2) {
          case "json":
            try {
              const text = content.toString("utf-8");
              const parsed = JSON.parse(text);
              displayContent = JSON.stringify(parsed, null, 2);
            } catch {
              displayContent = content.toString("utf-8");
            }
            break;
          case "base64":
            displayContent = content.toString("base64");
            break;
          case "plainString":
          default:
            displayContent = content.toString("utf-8");
            break;
        }
        const lines = displayContent.split("\n");
        const maxPreviewLines = 50;
        if (lines.length > maxPreviewLines) {
          console.log(lines.slice(0, maxPreviewLines).join("\n"));
          console.log(`
... (${lines.length - maxPreviewLines} more lines)`);
          const { showMore } = await inquirer6.prompt([
            {
              type: "confirm",
              name: "showMore",
              message: "Show the complete file content?",
              default: false
            }
          ]);
          if (showMore) {
            console.log(`
${"=".repeat(60)}`);
            console.log("\u{1F4C4} Complete file content:");
            console.log(`${"=".repeat(60)}
`);
            console.log(displayContent);
          }
        } else {
          console.log(displayContent);
        }
        console.log(`
${"=".repeat(60)}
`);
        const { continueReading } = await inquirer6.prompt([
          {
            type: "confirm",
            name: "continueReading",
            message: "Continue browsing files?",
            default: true
          }
        ]);
        if (!continueReading) {
          console.log("\u{1F44B} Goodbye!");
          break;
        }
      } catch (error) {
        console.error(
          `\u274C Failed to read file ${selectedFile}:`,
          error instanceof Error ? error.message : String(error)
        );
        const { tryAgain } = await inquirer6.prompt([
          {
            type: "confirm",
            name: "tryAgain",
            message: "Continue browsing other files?",
            default: true
          }
        ]);
        if (!tryAgain) {
          break;
        }
      }
    }
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    if (errorMessage.includes("Session not found") || errorMessage.includes("Session expired")) {
      console.error("\u{1F4A5} List failed: Authentication required");
      console.error(
        "   Please run 'deco login' first to authenticate with deco.chat"
      );
    } else {
      console.error("\u{1F4A5} List failed:", errorMessage);
    }
    process28.exit(1);
  } finally {
    await client.close();
  }
}
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]}`;
}
async function deleteCommand(options) {
  const { path: filePath, branchName, workspace, local } = options;
  console.log(`\u{1F5D1}\uFE0F  Deleting file "${filePath}" from branch "${branchName}"`);
  const { createWorkspaceClient: createWorkspaceClient2 } = await import('./mcp-7MUYOFGZ.js');
  const client = await createWorkspaceClient2({ workspace, local });
  try {
    const response = await client.callTool({
      name: "DELETE_FILE",
      arguments: {
        branch: branchName,
        path: filePath
      }
    });
    if (response.isError) {
      const errorMessage = Array.isArray(response.content) ? response.content[0]?.text || "Failed to delete file" : "Failed to delete file";
      throw new Error(errorMessage);
    }
    const result = response.structuredContent;
    if (result.deleted) {
      console.log(`\u2705 File deleted successfully: ${filePath}`);
    } else {
      console.log(`\u2139\uFE0F  File was not found or already deleted: ${filePath}`);
    }
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    if (errorMessage.includes("Session not found") || errorMessage.includes("Session expired")) {
      console.error("\u{1F4A5} Delete failed: Authentication required");
      console.error(
        "   Please run 'deco login' first to authenticate with deco.chat"
      );
    } else if (errorMessage.includes("File not found")) {
      console.error(`\u{1F4A5} File not found: ${filePath} (branch: ${branchName})`);
    } else {
      console.error("\u{1F4A5} Delete failed:", errorMessage);
    }
    process28.exit(1);
  } finally {
    await client.close();
  }
}
async function promptProject(orgSlug, local = false, current = "") {
  try {
    inquirer6.registerPrompt("search-list", inquirerSearchList);
  } catch {
    console.warn(
      "Could not load search functionality, falling back to basic list"
    );
  }
  const session = await readSession();
  if (!session) {
    throw new Error("No session found. Please run 'deco login' first.");
  }
  const client = await createWorkspaceClient({
    workspace: "",
    local
  });
  try {
    const response = await client.callTool({
      name: "PROJECTS_LIST",
      arguments: { org: orgSlug }
    });
    if (response.isError) {
      throw new Error(`Failed to fetch projects: ${response.content}`);
    }
    const { items: projects } = response.structuredContent;
    if (!projects || projects.length === 0) {
      throw new Error(
        `No projects found in organization '${orgSlug}'. Please create a project first.`
      );
    }
    const choices = projects.map((project2) => ({
      name: `${project2.title} (${project2.slug})`,
      value: project2.slug,
      short: project2.slug
    }));
    let selectedSlug;
    try {
      const result = await inquirer6.prompt([
        {
          type: "search-list",
          name: "selectedSlug",
          message: "Select a project:",
          choices,
          default: current
        }
      ]);
      selectedSlug = result.selectedSlug;
    } catch {
      const result = await inquirer6.prompt([
        {
          type: "list",
          name: "selectedSlug",
          message: "Select a project:",
          choices,
          default: current
        }
      ]);
      selectedSlug = result.selectedSlug;
    }
    const selectedProject = projects.find((p) => p.slug === selectedSlug);
    if (!selectedProject) {
      throw new Error(`Project '${selectedSlug}' not found`);
    }
    return selectedProject;
  } finally {
    await client.close();
  }
}
var manifestProjectSchema = z.object({
  slug: z.string().min(1),
  title: z.string().min(1),
  description: z.string().optional()
});
var manifestAuthorSchema = z.object({
  orgSlug: z.string().min(1),
  orgId: z.string().optional(),
  userId: z.string().optional(),
  userEmail: z.string().email().optional()
});
var manifestResourcesSchema = z.object({
  tools: z.array(z.string()),
  views: z.array(z.string()),
  workflows: z.array(z.string()),
  documents: z.array(z.string()),
  database: z.array(z.string()).optional().default([])
});
var manifestDependenciesSchema = z.object({
  mcps: z.array(z.string())
});
var manifestSchema = z.object({
  schemaVersion: z.literal("1.0"),
  project: manifestProjectSchema,
  author: manifestAuthorSchema,
  resources: manifestResourcesSchema,
  dependencies: manifestDependenciesSchema,
  createdAt: z.string().datetime()
});
function parseManifest(data) {
  return manifestSchema.parse(data);
}

// src/lib/mcp-manifest.ts
var MANIFEST_FILENAME = "deco.mcp.json";
async function readManifestFile(dirPath) {
  const manifestPath = path2.join(dirPath, MANIFEST_FILENAME);
  const content = await fs11.readFile(manifestPath, "utf-8");
  const data = JSON.parse(content);
  return parseManifest(data);
}
async function writeManifestFile(dirPath, manifest) {
  const manifestPath = path2.join(dirPath, MANIFEST_FILENAME);
  await fs11.writeFile(
    manifestPath,
    JSON.stringify(manifest, null, 2) + "\n",
    "utf-8"
  );
}
async function manifestExists(dirPath) {
  const manifestPath = path2.join(dirPath, MANIFEST_FILENAME);
  try {
    await fs11.access(manifestPath);
    return true;
  } catch {
    return false;
  }
}
async function extractDependenciesFromTools(toolFiles) {
  const integrationIds = /* @__PURE__ */ new Set();
  for (const file of toolFiles) {
    try {
      const tool = JSON.parse(file.content);
      if (tool.integration_id && typeof tool.integration_id === "string") {
        integrationIds.add(tool.integration_id);
      }
      if (tool.integrationId && typeof tool.integrationId === "string") {
        integrationIds.add(tool.integrationId);
      }
      if (Array.isArray(tool.dependencies)) {
        for (const dependency of tool.dependencies) {
          if (dependency && typeof dependency === "object") {
            if (dependency.integrationId && typeof dependency.integrationId === "string") {
              integrationIds.add(dependency.integrationId);
            }
            if (dependency.integration_id && typeof dependency.integration_id === "string") {
              integrationIds.add(dependency.integration_id);
            }
          }
        }
      }
      if (tool.tools_set && typeof tool.tools_set === "object") {
        for (const key of Object.keys(tool.tools_set)) {
          if (key.startsWith("i:")) {
            integrationIds.add(key);
          }
        }
      }
    } catch (err) {
      console.warn(`Warning: Could not parse tool file ${file.path}: ${err}`);
    }
  }
  return Array.from(integrationIds).sort();
}

// src/lib/projects.ts
function containsControlCharacters(value) {
  for (let index = 0; index < value.length; index++) {
    const code = value.charCodeAt(index);
    if (code >= 0 && code <= 31 || code === 127) {
      return true;
    }
  }
  return false;
}
function sanitizeProjectPath(rawPath) {
  if (!rawPath) {
    return null;
  }
  const trimmed = rawPath.trim();
  if (!trimmed) {
    return null;
  }
  let normalized = trimmed.replace(/\\/g, "/");
  normalized = normalized.replace(/^\.\/+/, "");
  normalized = normalized.replace(/^\/+/, "");
  if (!normalized) {
    return null;
  }
  if (normalized.includes("..")) {
    return null;
  }
  if (containsControlCharacters(normalized)) {
    return null;
  }
  return normalized;
}

// src/lib/code-conversion.ts
function viewJsonToCode(view) {
  const lines = [];
  lines.push(view.code);
  lines.push("");
  lines.push("// Metadata exports");
  lines.push(`export const name = ${JSON.stringify(view.name)};`);
  lines.push(`export const description = ${JSON.stringify(view.description)};`);
  if (view.inputSchema) {
    lines.push(
      `export const inputSchema = ${JSON.stringify(view.inputSchema, null, 2)};`
    );
  }
  if (view.importmap) {
    lines.push(
      `export const importmap = ${JSON.stringify(view.importmap, null, 2)};`
    );
  }
  if (view.icon) {
    lines.push(`export const icon = ${JSON.stringify(view.icon)};`);
  }
  if (view.tags && view.tags.length > 0) {
    lines.push(`export const tags = ${JSON.stringify(view.tags)};`);
  }
  return lines.join("\n");
}
function viewCodeToJson(code) {
  const view = {};
  const nameMatch = code.match(/export const name = (.+);/);
  const descMatch = code.match(/export const description = (.+);/);
  const inputSchemaMatch = code.match(
    /export const inputSchema = ([\s\S]+?);(?=\n(?:export const |$))/
  );
  const importmapMatch = code.match(
    /export const importmap = ([\s\S]+?);(?=\n(?:export const |$))/
  );
  const iconMatch = code.match(/export const icon = (.+);/);
  const tagsMatch = code.match(/export const tags = (.+);/);
  if (!nameMatch || !descMatch) {
    throw new Error(
      "Invalid view file: missing required 'name' or 'description' export"
    );
  }
  view.name = JSON.parse(nameMatch[1]);
  view.description = JSON.parse(descMatch[1]);
  if (inputSchemaMatch) {
    view.inputSchema = JSON.parse(inputSchemaMatch[1]);
  }
  if (importmapMatch) {
    view.importmap = JSON.parse(importmapMatch[1]);
  }
  if (iconMatch) {
    view.icon = JSON.parse(iconMatch[1]);
  }
  if (tagsMatch) {
    view.tags = JSON.parse(tagsMatch[1]);
  }
  const metadataMarkerMatch = code.match(/\n\/\/ Metadata exports\n/);
  if (metadataMarkerMatch) {
    view.code = code.slice(0, metadataMarkerMatch.index).trim();
  } else {
    const firstExportMatch = code.match(/\nexport const name = /);
    if (firstExportMatch && firstExportMatch.index) {
      view.code = code.slice(0, firstExportMatch.index).trim();
    } else {
      throw new Error("Invalid view file: cannot locate code section");
    }
  }
  if (!view.code) {
    throw new Error("Invalid view file: no code found");
  }
  return view;
}
function toolJsonToCode(tool) {
  const lines = [];
  lines.push(tool.execute);
  lines.push("");
  lines.push("// Metadata exports");
  lines.push(`export const name = ${JSON.stringify(tool.name)};`);
  lines.push(`export const description = ${JSON.stringify(tool.description)};`);
  lines.push(
    `export const inputSchema = ${JSON.stringify(tool.inputSchema, null, 2)};`
  );
  lines.push(
    `export const outputSchema = ${JSON.stringify(tool.outputSchema, null, 2)};`
  );
  if (tool.dependencies && tool.dependencies.length > 0) {
    lines.push(
      `export const dependencies = ${JSON.stringify(tool.dependencies, null, 2)};`
    );
  }
  return lines.join("\n");
}
function toolCodeToJson(code) {
  const tool = {};
  const nameMatch = code.match(/export const name = (.+);/);
  const descMatch = code.match(/export const description = (.+);/);
  const inputSchemaMatch = code.match(
    /export const inputSchema = ({[\s\S]*?});/
  );
  const outputSchemaMatch = code.match(
    /export const outputSchema = ({[\s\S]*?});/
  );
  const dependenciesMatch = code.match(
    /export const dependencies = (\[[\s\S]*?]);/
  );
  if (!nameMatch || !descMatch || !inputSchemaMatch || !outputSchemaMatch) {
    throw new Error(
      "Invalid tool file: missing required exports (name, description, inputSchema, outputSchema)"
    );
  }
  tool.name = JSON.parse(nameMatch[1]);
  tool.description = JSON.parse(descMatch[1]);
  tool.inputSchema = JSON.parse(inputSchemaMatch[1]);
  tool.outputSchema = JSON.parse(outputSchemaMatch[1]);
  if (dependenciesMatch) {
    tool.dependencies = JSON.parse(dependenciesMatch[1]);
  }
  const metadataMarkerMatch = code.match(/\n\/\/ Metadata exports\n/);
  if (metadataMarkerMatch) {
    tool.execute = code.slice(0, metadataMarkerMatch.index).trim();
  } else {
    const firstExportMatch = code.match(/\nexport const name = /);
    if (firstExportMatch && firstExportMatch.index) {
      tool.execute = code.slice(0, firstExportMatch.index).trim();
    } else {
      throw new Error("Invalid tool file: cannot locate execute code");
    }
  }
  if (!tool.execute) {
    throw new Error("Invalid tool file: no execute code found");
  }
  return tool;
}
function workflowJsonToCode(workflow) {
  const lines = [];
  lines.push("// Step execution functions");
  workflow.steps.forEach((step, index) => {
    lines.push("");
    lines.push(`// Step: ${step.def.name}`);
    lines.push(`export const step_${index}_execute = ${step.def.execute};`);
  });
  lines.push("");
  lines.push("// Metadata exports");
  lines.push(`export const name = ${JSON.stringify(workflow.name)};`);
  lines.push(
    `export const description = ${JSON.stringify(workflow.description)};`
  );
  const stepsMetadata = workflow.steps.map((step) => ({
    def: {
      name: step.def.name,
      title: step.def.title,
      description: step.def.description,
      inputSchema: step.def.inputSchema,
      outputSchema: step.def.outputSchema,
      dependencies: step.def.dependencies
    },
    input: step.input,
    output: step.output,
    options: step.options,
    views: step.views
  }));
  lines.push(
    `export const stepsMetadata = ${JSON.stringify(stepsMetadata, null, 2)};`
  );
  return lines.join("\n");
}
function workflowCodeToJson(code) {
  const workflow = {};
  const nameMatch = code.match(/export const name = (.+);/);
  const descMatch = code.match(/export const description = (.+);/);
  const stepsMetadataMatch = code.match(
    /export const stepsMetadata = ([\s\S]+?);(?=\n*$)/
  );
  if (!nameMatch || !descMatch || !stepsMetadataMatch) {
    throw new Error(
      "Invalid workflow file: missing required exports (name, description, stepsMetadata)"
    );
  }
  workflow.name = JSON.parse(nameMatch[1]);
  workflow.description = JSON.parse(descMatch[1]);
  const stepsMetadata = JSON.parse(stepsMetadataMatch[1]);
  const stepExecuteMatches = Array.from(
    code.matchAll(
      /export const step_(\d+)_execute = ([\s\S]+?)(?=\n(?:\/\/ Step:|export const step_|\n\/\/ Metadata exports))/g
    )
  );
  workflow.steps = stepsMetadata.map(
    (stepMeta, index) => {
      const executeMatch = stepExecuteMatches.find(
        (match) => Number.parseInt(match[1], 10) === index
      );
      if (!executeMatch) {
        throw new Error(
          `Invalid workflow file: missing execute function for step ${index}`
        );
      }
      const executeCode = executeMatch[2].trim();
      const cleanExecute = executeCode.endsWith(";") ? executeCode.slice(0, -1) : executeCode;
      return {
        def: {
          ...stepMeta.def,
          execute: cleanExecute
        },
        input: stepMeta.input,
        output: stepMeta.output,
        options: stepMeta.options,
        views: stepMeta.views
      };
    }
  );
  return workflow;
}
function detectResourceType(filePath) {
  const normalizedPath = filePath.startsWith("/") ? filePath : `/${filePath}`;
  if (normalizedPath.includes("/views/") && normalizedPath.endsWith(".tsx")) {
    return "view";
  }
  if (normalizedPath.includes("/tools/") && normalizedPath.endsWith(".ts")) {
    return "tool";
  }
  if (normalizedPath.includes("/workflows/") && normalizedPath.endsWith(".ts")) {
    return "workflow";
  }
  return null;
}

// src/commands/projects/export.ts
var ALLOWED_ROOTS = [
  "/src/tools",
  "/src/views",
  "/src/workflows",
  "/src/documents"
];
var AGENTS_DIR = "agents";
var DATABASE_DIR = "database";
function sanitizeTableFilename(tableName) {
  return tableName.replace(/[^a-zA-Z0-9-_]/g, "-");
}
async function runWithConcurrency(items, limit, worker) {
  if (items.length === 0 || limit <= 0) {
    return;
  }
  let nextIndex = 0;
  const size = Math.min(limit, items.length);
  const runners = Array.from({ length: size }, async () => {
    while (true) {
      const currentIndex = nextIndex;
      nextIndex += 1;
      if (currentIndex >= items.length) {
        break;
      }
      await worker(items[currentIndex], currentIndex);
    }
  });
  await Promise.all(runners);
}
async function exportCommand(options) {
  const { local, force } = options;
  console.log("\u{1F4E6} Starting project export...\n");
  let orgSlug = options.org;
  if (!orgSlug) {
    orgSlug = await promptWorkspace(local);
  }
  console.log(`\u{1F4CD} Organization: ${orgSlug}`);
  let project2 = options.project;
  let projectData;
  if (!project2) {
    projectData = await promptProject(orgSlug, local);
    project2 = projectData.slug;
  } else {
    const client2 = await createWorkspaceClient({ workspace: "", local });
    try {
      const response = await client2.callTool({
        name: "PROJECTS_LIST",
        arguments: { org: orgSlug }
      });
      if (response.isError) {
        throw new Error(`Failed to fetch projects: ${response.content}`);
      }
      const { items: projects } = response.structuredContent;
      projectData = projects.find((p) => p.slug === project2);
      if (!projectData) {
        throw new Error(
          `Project '${project2}' not found in organization '${orgSlug}'`
        );
      }
    } finally {
      await client2.close();
    }
  }
  console.log(`\u{1F4CD} Project: ${projectData.title} (${projectData.slug})
`);
  let outDir = options.out || "";
  if (!outDir) {
    const defaultOut = `./${orgSlug}__${projectData.slug}`;
    const result = await inquirer6.prompt([
      {
        type: "input",
        name: "outDir",
        message: "Output directory:",
        default: defaultOut
      }
    ]);
    outDir = result.outDir;
  }
  if (existsSync(outDir)) {
    const files = await fs11.readdir(outDir);
    if (files.length > 0) {
      if (!force) {
        throw new Error(
          `Output directory '${outDir}' is not empty. Use --force to overwrite existing files.`
        );
      }
      console.log(
        `\u26A0\uFE0F  Output directory is not empty. Using --force to overwrite.
`
      );
    }
  } else {
    mkdirSync(outDir, { recursive: true });
    console.log(`\u{1F4C1} Created output directory: ${outDir}
`);
  }
  const resolvedOutDir = path2.resolve(outDir);
  const workspace = `/${orgSlug}/${projectData.slug}`;
  const client = await createWorkspaceClient({ workspace, local });
  try {
    console.log("\u{1F4CB} Fetching project files...");
    const allFiles = [];
    const resourcesByType = {
      tools: [],
      views: [],
      workflows: [],
      documents: [],
      database: []
    };
    for (const root of ALLOWED_ROOTS) {
      const response = await client.callTool({
        name: "LIST_FILES",
        arguments: {
          branch: "main",
          prefix: root
        }
      });
      if (response.isError) {
        console.warn(`\u26A0\uFE0F  Failed to list files in ${root}: ${response.content}`);
        continue;
      }
      const result = response.structuredContent;
      if (result.count === 0) {
        console.log(`   ${root}: 0 files`);
        continue;
      }
      console.log(`   ${root}: ${result.count} files`);
      const filePaths = Object.keys(result.files);
      await runWithConcurrency(filePaths, 5, async (filePath) => {
        try {
          const content = await fetchFileContent(
            filePath,
            "main",
            workspace,
            local
          );
          const contentStr = content.toString("utf-8");
          allFiles.push({ path: filePath, content: contentStr });
          if (filePath.startsWith("/src/tools/")) {
            resourcesByType.tools.push(filePath);
          } else if (filePath.startsWith("/src/views/")) {
            resourcesByType.views.push(filePath);
          } else if (filePath.startsWith("/src/workflows/")) {
            resourcesByType.workflows.push(filePath);
          } else if (filePath.startsWith("/src/documents/")) {
            resourcesByType.documents.push(filePath);
          }
          let relativePath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
          if (relativePath.startsWith("src/")) {
            relativePath = relativePath.slice(4);
          }
          const sanitizedRelativePath = sanitizeProjectPath(relativePath);
          if (!sanitizedRelativePath) {
            console.warn(`   \u26A0\uFE0F  Skipping unsafe path: ${filePath}`);
            return;
          }
          const localPath = path2.join(outDir, sanitizedRelativePath);
          const resolvedLocalPath = path2.resolve(localPath);
          const relativeToOut = path2.relative(
            resolvedOutDir,
            resolvedLocalPath
          );
          if (relativeToOut.startsWith("..") || path2.isAbsolute(relativeToOut)) {
            console.warn(
              `   \u26A0\uFE0F  Skipping path outside output directory: ${sanitizedRelativePath}`
            );
            return;
          }
          await fs11.mkdir(path2.dirname(resolvedLocalPath), { recursive: true });
          let finalContent = contentStr;
          let finalPath = resolvedLocalPath;
          if (filePath.endsWith(".json")) {
            try {
              const parsed = JSON.parse(contentStr);
              if (filePath.startsWith("/src/views/")) {
                const viewResource = parsed;
                finalContent = viewJsonToCode(viewResource);
                finalPath = resolvedLocalPath.replace(/\.json$/, ".tsx");
              } else if (filePath.startsWith("/src/tools/")) {
                const toolResource = parsed;
                finalContent = toolJsonToCode(toolResource);
                finalPath = resolvedLocalPath.replace(/\.json$/, ".ts");
              } else if (filePath.startsWith("/src/workflows/")) {
                const workflowResource = parsed;
                finalContent = workflowJsonToCode(workflowResource);
                finalPath = resolvedLocalPath.replace(/\.json$/, ".ts");
              }
            } catch (conversionError) {
              console.warn(
                `   \u26A0\uFE0F  Failed to convert ${filePath} to code file: ${conversionError instanceof Error ? conversionError.message : String(conversionError)}`
              );
            }
          }
          await fs11.writeFile(finalPath, finalContent, "utf-8");
        } catch (error) {
          console.warn(
            `   \u26A0\uFE0F  Failed to download ${filePath}: ${error instanceof Error ? error.message : String(error)}`
          );
        }
      });
    }
    console.log(`\u2705 Downloaded ${allFiles.length} files
`);
    console.log("\u{1F464} Fetching agents...");
    const agentsDir = path2.join(outDir, AGENTS_DIR);
    mkdirSync(agentsDir, { recursive: true });
    let agentCount = 0;
    try {
      const agentsListResponse = await client.callTool({
        name: "AGENTS_LIST",
        arguments: {}
      });
      if (agentsListResponse.isError) {
        console.warn(
          `\u26A0\uFE0F  Failed to fetch agents: ${agentsListResponse.content}`
        );
      } else {
        const agentsListData = agentsListResponse.structuredContent;
        console.log(`   Found ${agentsListData.items.length} agents`);
        await runWithConcurrency(
          agentsListData.items,
          5,
          async (agentSummary) => {
            try {
              const agentResponse = await client.callTool({
                name: "AGENTS_GET",
                arguments: { id: agentSummary.id }
              });
              if (agentResponse.isError) {
                console.warn(
                  `   \u26A0\uFE0F  Failed to fetch agent ${agentSummary.name}: ${agentResponse.content}`
                );
                return;
              }
              const agent = agentResponse.structuredContent;
              const exportAgent = {
                name: agent.name,
                avatar: agent.avatar,
                instructions: agent.instructions,
                description: agent.description,
                tools_set: agent.tools_set,
                max_steps: agent.max_steps,
                max_tokens: agent.max_tokens,
                model: agent.model,
                memory: agent.memory,
                views: agent.views,
                visibility: agent.visibility,
                temperature: agent.temperature
              };
              const safeFilename = agent.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
              const agentFile = path2.join(agentsDir, `${safeFilename}.json`);
              await fs11.writeFile(
                agentFile,
                JSON.stringify(exportAgent, null, 2) + "\n",
                "utf-8"
              );
              const current = ++agentCount;
              if (current % 5 === 0 || current === agentsListData.items.length) {
                console.log(
                  `   Exported ${current}/${agentsListData.items.length} agents...`
                );
              }
            } catch (error) {
              console.warn(
                `   \u26A0\uFE0F  Failed to export agent ${agentSummary.name}: ${error instanceof Error ? error.message : String(error)}`
              );
            }
          }
        );
        console.log(`   \u2705 Exported ${agentCount} agents
`);
      }
    } catch (error) {
      console.warn(`\u26A0\uFE0F  Failed to export agents: ${error}`);
    }
    console.log("\u{1F5C4}\uFE0F Exporting database schema...");
    const databaseDir = path2.join(outDir, DATABASE_DIR);
    mkdirSync(databaseDir, { recursive: true });
    let tableCount = 0;
    try {
      const schemaResponse = await client.callTool({
        name: "DATABASES_RUN_SQL",
        arguments: {
          sql: "SELECT type, name, tbl_name, sql FROM sqlite_master WHERE sql IS NOT NULL"
        }
      });
      if (schemaResponse.isError) {
        console.warn(
          `\u26A0\uFE0F  Failed to fetch database schema: ${schemaResponse.content}`
        );
      }
      const statements = schemaResponse.structuredContent?.result ?? [];
      const rows = statements.flatMap(
        (statement) => Array.isArray(statement.results) ? statement.results : []
      );
      const tables = rows.map((row) => ({
        type: String(row.type ?? ""),
        name: String(row.name ?? ""),
        tableName: String(row.tbl_name ?? row.name ?? ""),
        sql: String(row.sql ?? "")
      })).filter(
        (entry) => entry.type.toLowerCase() === "table" && entry.name && entry.sql && !entry.name.startsWith("sqlite_") && !entry.name.startsWith("mastra_") && entry.sql.trim().toLowerCase().startsWith("create table")
      );
      const indexes = rows.map((row) => ({
        type: String(row.type ?? ""),
        name: String(row.name ?? ""),
        tableName: String(row.tbl_name ?? ""),
        sql: String(row.sql ?? "")
      })).filter(
        (entry) => entry.type.toLowerCase() === "index" && entry.sql && !entry.name.startsWith("sqlite_") && !entry.name.startsWith("mastra_") && tables.some((table) => table.tableName === entry.tableName)
      );
      const indexesByTable = /* @__PURE__ */ new Map();
      for (const index of indexes) {
        const collection = indexesByTable.get(index.tableName) ?? [];
        collection.push({ name: index.name, sql: index.sql });
        indexesByTable.set(index.tableName, collection);
      }
      for (const table of tables) {
        const safeFilename = `${sanitizeTableFilename(table.tableName || table.name)}.json`;
        const tablePath = path2.join(databaseDir, safeFilename);
        const payload = {
          name: table.tableName || table.name,
          createSql: table.sql,
          indexes: indexesByTable.get(table.tableName) ?? []
        };
        await fs11.writeFile(
          tablePath,
          JSON.stringify(payload, null, 2) + "\n",
          "utf-8"
        );
        resourcesByType.database.push(`/${DATABASE_DIR}/${safeFilename}`);
        tableCount++;
      }
      console.log(`   \u2705 Exported ${tableCount} tables
`);
    } catch (error) {
      console.warn(
        `\u26A0\uFE0F  Failed to export database schema: ${error instanceof Error ? error.message : String(error)}`
      );
    }
    console.log("\u{1F50D} Extracting dependencies...");
    const toolFiles = allFiles.filter((f) => f.path.startsWith("/src/tools/"));
    const dependencies = await extractDependenciesFromTools(toolFiles);
    console.log(
      `   Found ${dependencies.length} MCP dependencies: ${dependencies.join(", ") || "none"}
`
    );
    console.log("\u{1F464} Fetching author info...");
    let userEmail;
    let userId;
    try {
      const profileResponse = await client.callTool({
        name: "PROFILES_GET",
        arguments: {}
      });
      if (!profileResponse.isError) {
        const profile = profileResponse.structuredContent;
        userEmail = profile.email;
        userId = profile.id;
      }
    } catch {
    }
    console.log(`   User: ${userEmail || "unknown"}
`);
    console.log("\u{1F4DD} Writing manifest...");
    const stripSrcPrefix = (paths) => paths.map((p) => p.replace(/^\/src\//, "/"));
    const manifest = {
      schemaVersion: "1.0",
      project: {
        slug: projectData.slug,
        title: projectData.title,
        description: projectData.description
      },
      author: {
        orgSlug,
        userId,
        userEmail
      },
      resources: {
        tools: stripSrcPrefix(resourcesByType.tools),
        views: stripSrcPrefix(resourcesByType.views),
        workflows: stripSrcPrefix(resourcesByType.workflows),
        documents: stripSrcPrefix(resourcesByType.documents),
        database: resourcesByType.database
      },
      dependencies: {
        mcps: dependencies
      },
      createdAt: (/* @__PURE__ */ new Date()).toISOString()
    };
    await writeManifestFile(outDir, manifest);
    console.log(
      `   \u2705 Manifest written to ${path2.join(outDir, "deco.mcp.json")}
`
    );
    console.log("\u{1F389} Export completed successfully!\n");
    console.log("\u{1F4CA} Summary:");
    console.log(`   Tools: ${resourcesByType.tools.length}`);
    console.log(`   Views: ${resourcesByType.views.length}`);
    console.log(`   Workflows: ${resourcesByType.workflows.length}`);
    console.log(`   Documents: ${resourcesByType.documents.length}`);
    console.log(`   Database tables: ${resourcesByType.database.length}`);
    console.log(`   Agents: ${agentCount}`);
    console.log(`   Dependencies: ${dependencies.length}`);
    console.log(`   Output: ${outDir}`);
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    console.error("\n\u{1F4A5} Export failed:", errorMessage);
    process.exit(1);
  } finally {
    await client.close();
  }
}
var ALLOWED_ROOTS2 = ["/tools", "/views", "/workflows", "/documents"];
var AGENTS_DIR2 = "agents";
var DATABASE_DIR2 = "database";
async function runWithConcurrency2(items, limit, worker) {
  if (items.length === 0 || limit <= 0) {
    return;
  }
  let nextIndex = 0;
  const size = Math.min(limit, items.length);
  const runners = Array.from({ length: size }, async () => {
    while (true) {
      const currentIndex = nextIndex;
      nextIndex += 1;
      if (currentIndex >= items.length) {
        break;
      }
      await worker(items[currentIndex], currentIndex);
    }
  });
  await Promise.all(runners);
}
var mapToRemotePath = (localPath) => {
  for (const root of ALLOWED_ROOTS2) {
    if (localPath.startsWith(root)) {
      return `/src${localPath}`;
    }
  }
  return localPath;
};
async function importCommand(options) {
  const { local } = options;
  console.log("\u{1F4E6} Starting project import...\n");
  let fromDir = options.from || "./";
  fromDir = path2.resolve(fromDir);
  if (!existsSync(fromDir)) {
    throw new Error(`Source directory '${fromDir}' does not exist`);
  }
  console.log(`\u{1F4CB} Reading manifest from ${fromDir}...`);
  if (!await manifestExists(fromDir)) {
    throw new Error(
      `Manifest file 'deco.mcp.json' not found in '${fromDir}'. This directory is not a valid MCP project.`
    );
  }
  const manifest = await readManifestFile(fromDir);
  console.log(
    `   \u2705 Manifest validated (schema version ${manifest.schemaVersion})
`
  );
  let projectSlug = options.slug || manifest.project.slug;
  const projectTitle = options.title || manifest.project.title;
  const projectDescription = manifest.project.description;
  console.log("\u{1F4CD} Project to import:");
  console.log(`   Slug: ${projectSlug}`);
  console.log(`   Title: ${projectTitle}`);
  if (projectDescription) {
    console.log(`   Description: ${projectDescription}`);
  }
  console.log();
  let orgSlug = options.org;
  if (!orgSlug) {
    orgSlug = await promptWorkspace(local);
  }
  console.log(`\u{1F4CD} Destination organization: ${orgSlug}
`);
  console.log(`\u{1F528} Creating project '${projectSlug}'...`);
  let client = await createWorkspaceClient({ workspace: "", local });
  let projectId;
  try {
    const createResponse = await client.callTool({
      name: "PROJECTS_CREATE",
      arguments: {
        org: orgSlug,
        slug: projectSlug,
        title: projectTitle,
        description: projectDescription
      }
    });
    if (createResponse.isError) {
      const errorMsg = Array.isArray(createResponse.content) ? createResponse.content[0]?.text || "Failed to create project" : String(createResponse.content);
      if (errorMsg.includes("already exists") || errorMsg.includes("duplicate")) {
        console.error(
          `   \u274C Project with slug '${projectSlug}' already exists in '${orgSlug}'`
        );
        const result = await inquirer6.prompt([
          {
            type: "input",
            name: "newSlug",
            message: "Enter a new slug (or press Ctrl+C to abort):",
            validate: (input) => input.trim().length > 0 ? true : "Slug cannot be empty"
          }
        ]);
        const newSlug = result.newSlug.trim();
        const retryResponse = await client.callTool({
          name: "PROJECTS_CREATE",
          arguments: {
            org: orgSlug,
            slug: newSlug,
            title: projectTitle,
            description: projectDescription
          }
        });
        if (retryResponse.isError) {
          throw new Error(
            `Failed to create project with slug '${newSlug}': ${retryResponse.content}`
          );
        }
        const retryResult = retryResponse.structuredContent;
        projectId = retryResult.id;
        projectSlug = newSlug;
        console.log(
          `   \u2705 Project created with slug '${newSlug}' (ID: ${projectId})
`
        );
      } else {
        throw new Error(errorMsg);
      }
    } else {
      const result = createResponse.structuredContent;
      projectId = result.id;
      console.log(`   \u2705 Project created (ID: ${projectId})
`);
    }
  } finally {
    await client.close();
  }
  console.log("\u{1F4E4} Pushing files to project...");
  const projectWorkspace = `/${orgSlug}/${projectSlug}`;
  const ignoreChecker = createIgnoreChecker(fromDir);
  const filesToUpload = [];
  for (const root of ALLOWED_ROOTS2) {
    const localRoot = path2.join(fromDir, root.slice(1));
    if (!existsSync(localRoot)) {
      continue;
    }
    async function walkDir(dir, baseRemotePath) {
      const entries = await fs11.readdir(dir, { withFileTypes: true });
      const basePrefix = baseRemotePath.replace(/^\/+/, "");
      for (const entry of entries) {
        const localPath = path2.join(dir, entry.name);
        if (ignoreChecker.isIgnored(localPath)) {
          continue;
        }
        const joinedRemote = `${baseRemotePath}/${entry.name}`.replace(
          /\\/g,
          "/"
        );
        const sanitizedRelativePath = sanitizeProjectPath(joinedRemote);
        if (!sanitizedRelativePath) {
          console.warn(`   \u26A0\uFE0F  Skipping unsafe path: ${joinedRemote}`);
          continue;
        }
        if (!sanitizedRelativePath.startsWith(basePrefix)) {
          continue;
        }
        const nextRemotePath = `/${sanitizedRelativePath}`;
        if (entry.isDirectory()) {
          await walkDir(localPath, nextRemotePath);
        } else if (entry.isFile()) {
          filesToUpload.push({ remotePath: nextRemotePath, localPath });
        }
      }
    }
    await walkDir(localRoot, root);
  }
  console.log(`   Found ${filesToUpload.length} files to upload`);
  let uploadedCount = 0;
  await runWithConcurrency2(
    filesToUpload,
    5,
    async ({ remotePath, localPath }) => {
      try {
        const content = await fs11.readFile(localPath, "utf-8");
        let finalContent = content;
        let finalRemotePath = remotePath;
        const resourceType = detectResourceType(localPath);
        if (resourceType) {
          try {
            let jsonResource;
            if (resourceType === "view") {
              jsonResource = viewCodeToJson(content);
              finalRemotePath = remotePath.replace(/\.tsx$/, ".json");
            } else if (resourceType === "tool") {
              jsonResource = toolCodeToJson(content);
              finalRemotePath = remotePath.replace(/\.ts$/, ".json");
            } else if (resourceType === "workflow") {
              jsonResource = workflowCodeToJson(content);
              finalRemotePath = remotePath.replace(/\.ts$/, ".json");
            }
            if (jsonResource) {
              finalContent = JSON.stringify(jsonResource, null, 2);
            }
          } catch (conversionError) {
            console.warn(
              `   \u26A0\uFE0F  Failed to convert ${localPath} to JSON: ${conversionError instanceof Error ? conversionError.message : String(conversionError)}`
            );
            return;
          }
        } else if (remotePath.endsWith(".json")) {
          try {
            JSON.parse(content);
          } catch {
            console.warn(`   \u26A0\uFE0F  Skipping malformed JSON file: ${remotePath}`);
            return;
          }
        }
        if (/[^\x20-\x7E\r\n\t]/.test(finalContent)) {
          console.warn(`   \u26A0\uFE0F  Skipping binary file: ${remotePath}`);
          return;
        }
        const deconfigPath = mapToRemotePath(finalRemotePath);
        await putFileContent(
          deconfigPath,
          finalContent,
          "main",
          void 0,
          projectWorkspace,
          local
        );
        const current = ++uploadedCount;
        if (current % 10 === 0 || current === filesToUpload.length) {
          console.log(
            `   Uploaded ${current}/${filesToUpload.length} files...`
          );
        }
      } catch (error) {
        console.error(
          `   \u274C Failed to upload ${remotePath}:`,
          error instanceof Error ? error.message : String(error)
        );
      }
    }
  );
  console.log(`   \u2705 Uploaded ${uploadedCount} files
`);
  const databasesDir = path2.join(fromDir, DATABASE_DIR2);
  const agentsDir = path2.join(fromDir, AGENTS_DIR2);
  let tablesImported = 0;
  let agentCount = 0;
  let projectClient = null;
  const ensureProjectClient = async () => {
    if (!projectClient) {
      projectClient = await createWorkspaceClient({
        workspace: projectWorkspace,
        local
      });
    }
    return projectClient;
  };
  try {
    if (existsSync(databasesDir)) {
      const tableFiles = (await fs11.readdir(databasesDir)).filter(
        (name) => name.endsWith(".json")
      );
      if (tableFiles.length > 0) {
        console.log("\u{1F5C4}\uFE0F Importing database schema...");
        const projectClientInstance = await ensureProjectClient();
        await runWithConcurrency2(tableFiles, 3, async (fileName) => {
          try {
            const filePath = path2.join(databasesDir, fileName);
            const raw = await fs11.readFile(filePath, "utf-8");
            const parsed = JSON.parse(raw);
            if (!parsed?.name || !parsed?.createSql) {
              console.warn(
                `   \u26A0\uFE0F  Skipping invalid database schema file: ${fileName}`
              );
              return;
            }
            const tableName = parsed.name;
            const indexes = Array.isArray(parsed.indexes) ? parsed.indexes.filter((index) => typeof index?.sql === "string") : [];
            await projectClientInstance.callTool({
              name: "DATABASES_RUN_SQL",
              arguments: {
                sql: parsed.createSql
              }
            });
            for (const index of indexes) {
              await projectClientInstance.callTool({
                name: "DATABASES_RUN_SQL",
                arguments: {
                  sql: String(index.sql)
                }
              });
            }
            tablesImported++;
            console.log(`   Imported table ${tableName}`);
          } catch (error) {
            console.error(
              `   \u274C Failed to import database schema from ${fileName}:`,
              error instanceof Error ? error.message : String(error)
            );
          }
        });
        console.log(`   \u2705 Imported ${tablesImported} tables
`);
      } else {
        console.log("   No database tables found, skipping\n");
      }
    } else {
      console.log("   No database schema directory found, skipping\n");
    }
    if (existsSync(agentsDir)) {
      console.log("\u{1F464} Importing agents...");
      const projectClientInstance = await ensureProjectClient();
      const agentFiles = await fs11.readdir(agentsDir);
      const jsonFiles = agentFiles.filter((f) => f.endsWith(".json"));
      console.log(`   Found ${jsonFiles.length} agent files`);
      await runWithConcurrency2(jsonFiles, 5, async (agentFile) => {
        try {
          const agentPath = path2.join(agentsDir, agentFile);
          const agentContent = await fs11.readFile(agentPath, "utf-8");
          const agentData = JSON.parse(agentContent);
          const createAgentResponse = await projectClientInstance.callTool({
            name: "AGENTS_CREATE",
            arguments: agentData
          });
          if (createAgentResponse.isError) {
            console.error(
              `   \u274C Failed to create agent from ${agentFile}:`,
              createAgentResponse.content
            );
            return;
          }
          const current = ++agentCount;
          if (current % 5 === 0 || current === jsonFiles.length) {
            console.log(`   Created ${current}/${jsonFiles.length} agents...`);
          }
        } catch (error) {
          console.error(
            `   \u274C Failed to import agent ${agentFile}:`,
            error instanceof Error ? error.message : String(error)
          );
        }
      });
      console.log(`   \u2705 Imported ${agentCount} agents
`);
    } else {
      console.log("\u{1F464} No agents directory found, skipping\n");
    }
  } finally {
    const maybeClosable = projectClient;
    if (maybeClosable?.close) {
      await maybeClosable.close();
    }
  }
  console.log("\u{1F389} Import completed successfully!\n");
  console.log("\u{1F4CA} Summary:");
  console.log(`   Project ID: ${projectId}`);
  console.log(`   Project slug: ${projectSlug}`);
  console.log(`   Organization: ${orgSlug}`);
  console.log(`   Files uploaded: ${uploadedCount}`);
  console.log(`   Database tables imported: ${tablesImported}`);
  console.log(`   Agents created: ${agentCount}`);
  if (manifest.dependencies.mcps.length > 0) {
    console.log(`
\u26A0\uFE0F  Dependencies detected (not installed):`);
    for (const mcp of manifest.dependencies.mcps) {
      console.log(`      - ${mcp}`);
    }
    console.log(
      `   You may need to install these integrations for full functionality.`
    );
  }
}
async function readStdin() {
  return new Promise((resolve3, reject) => {
    let data = "";
    if (process28.stdin.isTTY) {
      reject(
        new Error("No input provided. Use -f <file> or pipe JSON via stdin.")
      );
      return;
    }
    process28.stdin.setEncoding("utf-8");
    process28.stdin.on("data", (chunk) => {
      data += chunk;
    });
    process28.stdin.on("end", () => {
      resolve3(data);
    });
    process28.stdin.on("error", (err) => {
      reject(err);
    });
  });
}
function validateConfig(config) {
  if (!config || typeof config !== "object") {
    return false;
  }
  const c = config;
  if (typeof c.scopeName !== "string" || !c.scopeName.trim()) {
    throw new Error("Missing or invalid 'scopeName' field");
  }
  if (typeof c.name !== "string" || !c.name.trim()) {
    throw new Error("Missing or invalid 'name' field");
  }
  if (!c.connection || typeof c.connection !== "object") {
    throw new Error("Missing or invalid 'connection' field");
  }
  const conn = c.connection;
  const validTypes = ["HTTP", "SSE", "Websocket", "Deco", "INNATE", "BINDING"];
  if (!validTypes.includes(conn.type)) {
    throw new Error(
      `Invalid connection type '${conn.type}'. Must be one of: ${validTypes.join(", ")}.`
    );
  }
  return true;
}
async function publishApp({
  file,
  workspace,
  local,
  skipConfirmation
}) {
  console.log(`
\u{1F4E6} Publishing app to registry...
`);
  let fileContent;
  const source = file ? `file "${file}"` : "stdin";
  if (file) {
    try {
      fileContent = await promises.readFile(file, "utf-8");
    } catch (error) {
      throw new Error(
        `Failed to read file "${file}": ${error instanceof Error ? error.message : String(error)}`
      );
    }
  } else {
    try {
      fileContent = await readStdin();
    } catch (error) {
      throw new Error(
        `Failed to read from stdin: ${error instanceof Error ? error.message : String(error)}`
      );
    }
  }
  let config;
  try {
    config = JSON.parse(fileContent);
  } catch (error) {
    throw new Error(
      `Failed to parse JSON from ${source}: ${error instanceof Error ? error.message : String(error)}`
    );
  }
  validateConfig(config);
  const appConfig = config;
  console.log("\u{1F4CB} Publish summary:");
  console.log(`  Scope: ${appConfig.scopeName}`);
  console.log(`  Name: ${appConfig.name}`);
  console.log(`  Full name: @${appConfig.scopeName}/${appConfig.name}`);
  console.log(`  Connection type: ${appConfig.connection.type}`);
  if (appConfig.friendlyName) {
    console.log(`  Friendly name: ${appConfig.friendlyName}`);
  }
  if (appConfig.description) {
    console.log(`  Description: ${appConfig.description}`);
  }
  if (appConfig.icon) {
    console.log(`  Icon: ${appConfig.icon}`);
  }
  console.log(`  Unlisted: ${appConfig.unlisted ?? true}`);
  console.log(`  Workspace: ${workspace}`);
  console.log();
  const confirmed = skipConfirmation || (await inquirer6.prompt([
    {
      type: "confirm",
      name: "proceed",
      message: "Proceed with publishing?",
      default: true
    }
  ])).proceed;
  if (!confirmed) {
    console.log("\u274C Publishing cancelled");
    process28.exit(0);
  }
  const client = await createWorkspaceClientStub({ workspace, local });
  const response = await client.callTool({
    name: "REGISTRY_PUBLISH_APP",
    arguments: {
      scopeName: appConfig.scopeName,
      name: appConfig.name,
      connection: appConfig.connection,
      friendlyName: appConfig.friendlyName,
      description: appConfig.description,
      icon: appConfig.icon,
      metadata: appConfig.metadata,
      unlisted: appConfig.unlisted,
      tools: appConfig.tools
    }
  });
  if (response.isError && Array.isArray(response.content)) {
    const errorText = response.content[0]?.text ?? "Unknown error";
    throw new Error(`Failed to publish app: ${errorText}`);
  }
  const result = response.structuredContent;
  console.log(`
\u{1F389} Successfully published!`);
  console.log(`  App: @${appConfig.scopeName}/${appConfig.name}`);
  if (result?.appName) {
    console.log(`  Registry name: ${result.appName}`);
  }
  console.log();
}

// src/commands.ts
var MIN_NODE_VERSION = "18.0.0";
var currentNodeVersion = process28.version.slice(1);
function compareVersions(version1, version2) {
  const v1parts = version1.split(".").map(Number);
  const v2parts = version2.split(".").map(Number);
  for (let i = 0; i < Math.max(v1parts.length, v2parts.length); i++) {
    const v1part = v1parts[i] || 0;
    const v2part = v2parts[i] || 0;
    if (v1part < v2part) return -1;
    if (v1part > v2part) return 1;
  }
  return 0;
}
if (compareVersions(currentNodeVersion, MIN_NODE_VERSION) < 0) {
  console.error(`\u274C Error: Node.js ${MIN_NODE_VERSION} or higher is required.`);
  console.error(`   Current version: ${process28.version}`);
  console.error(`   Please upgrade Node.js: https://nodejs.org/`);
  process28.exit(1);
}
process28.removeAllListeners("warning");
process28.on("warning", (warning) => {
  if (warning.name === "DeprecationWarning" && warning.message.includes("punycode")) {
    return;
  }
  console.warn(warning.message);
});
var login = new Command("login").description("Log in to admin.decocms.com and retrieve tokens for CLI usage.").action(async () => {
  try {
    await loginCommand();
    console.log("\u2705 Successfully logged in to admin.decocms.com");
  } catch (error) {
    console.error(
      "\u274C Login failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var logout = new Command("logout").description("Log out of admin.decocms.com and remove local session data.").action(async () => {
  try {
    await deleteSession();
    console.log("Logged out successfully. Session data removed.");
  } catch (e) {
    if (e instanceof Error) {
      console.error("Failed to log out:", e.message);
    } else {
      console.error("Failed to log out:", String(e));
    }
  }
});
var whoami = new Command("whoami").description("Print info about the current session.").action(whoamiCommand);
var configure = new Command("configure").alias("config").description("Save configuration options for the current directory.").action(async () => {
  try {
    await configureCommand(getLocal());
  } catch (error) {
    console.error(
      "\u274C Configuration failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var hostingList = new Command("list").description("List all apps in the current workspace.").option("-w, --workspace <workspace>", "Workspace name").action(async (options) => {
  try {
    const session = await readSession();
    const workspace = options.workspace || session?.workspace;
    if (!workspace) {
      console.error(
        "\u274C No workspace specified. Use -w flag or run 'deco configure' first."
      );
      process28.exit(1);
    }
    await listApps({ workspace });
  } catch (error) {
    console.error(
      "\u274C Failed to list apps:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var hostingDeploy = new Command("deploy").description("Deploy the current directory into the current workspace.").option("-w, --workspace <workspace>", "Workspace name").option("-a, --app <app>", "App name").option("-y, --yes", "Skip confirmation").option("-p, --public", "Make the app public in the registry").option(
  "-f, --force",
  "Force the deployment even if there are breaking changes"
).option(
  "--dry-run",
  "Write deploy manifest to local filesystem instead of deploying"
).option("--no-promote", "Do not promote the deployment to production routes").option(
  "-e, --env <value>",
  'Set environment variables: KEY=VALUE, JSON object {"KEY":"VALUE"}, or file path /path/to/.env (can be used multiple times, overrides .dev.vars)',
  (value, previous) => {
    return previous ? [...previous, value] : [value];
  }
).argument("[cwd]", "Working directory").action(async (cwd, options) => {
  try {
    const config = await getConfig({
      inlineOptions: options
    });
    const wranglerConfig = await readWranglerConfig();
    const assetsDirectory = wranglerConfig.assets?.directory;
    const app = options.app ?? (typeof wranglerConfig.name === "string" ? wranglerConfig.name : "my-app");
    await deploy({
      ...config,
      app,
      skipConfirmation: options.yes,
      cwd: cwd ?? process28.cwd(),
      unlisted: !options.public,
      assetsDirectory,
      force: options.force,
      dryRun: options.dryRun,
      promote: options.promote ?? true,
      inlineEnvVars: options.env
    });
  } catch (error) {
    console.error(
      "\u274C Deployment failed:",
      error instanceof Error ? error.message : JSON.stringify(error)
    );
    process28.exit(1);
  }
});
var hostingPromote = new Command("promote").description("Promote a deployment to an existing route pattern.").option("-w, --workspace <workspace>", "Workspace name").option("-a, --app <app>", "App name").option("-d, --deployment <deployment>", "Deployment ID").option(
  "-r, --route <route>",
  "Route pattern (defaults to appName.deco.page)"
).option("-y, --yes", "Skip confirmation").action(async (options) => {
  try {
    const config = await getConfig({
      inlineOptions: options
    });
    let app = options.app;
    if (!app) {
      try {
        const wranglerConfig = await readWranglerConfig();
        app = typeof wranglerConfig.name === "string" ? wranglerConfig.name : void 0;
      } catch {
      }
    }
    await promoteApp({
      workspace: config.workspace,
      local: config.local,
      appSlug: app,
      deploymentId: options.deployment,
      routePattern: options.route,
      skipConfirmation: options.yes
    });
  } catch (error) {
    console.error(
      "\u274C Promotion failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var linkCmd = new Command("link").description("Link the project to be accessed through a remote domain.").option("-p, --port <port>", "Port to link", parseInt).option("-e, --env <env>", "Environment variable to set").allowUnknownOption().action(async (options, cmd) => {
  try {
    const runCommand2 = cmd.args;
    await link({
      port: options.port,
      onBeforeRegister: (server) => {
        if (runCommand2.length === 0) {
          console.log(
            "\u26A0\uFE0F  No command provided. Tunnel will connect to existing service on port."
          );
          return;
        }
        const [command, ...args] = runCommand2;
        console.log(`\u{1F517} Starting command: ${command} ${args.join(" ")}`);
        const childProcess = spawn(command, args, {
          stdio: "inherit",
          shell: true,
          env: { ...process28.env, [options.env ?? "BASE_URL"]: server }
        });
        childProcess.on("error", (error) => {
          console.error("\u274C Failed to start command:", error.message);
          process28.exit(1);
        });
        return childProcess;
      }
    });
  } catch (error) {
    console.error(
      "\u274C Link failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var upgrade2 = new Command("upgrade").description("Upgrade the deco CLI to the latest version.").action(upgradeCommand);
var update = new Command("update").description("Update Deco dependencies to their latest versions.").option("-y, --yes", "Skip confirmation prompts").action(async (options) => {
  try {
    await updateCommand({ yes: options.yes });
  } catch (error) {
    console.error(
      "\u274C Update failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var dev = new Command("dev").description("Start a development server.").option(
  "--clean-build-dir <directory>",
  "Clean the build directory before starting the development server",
  (directory) => {
    return {
      enabled: true,
      directory
    };
  }
).option(
  "--gen-watch [path]",
  "Watch for TypeScript file changes and regenerate deco.gen.ts (defaults to current directory)"
).option("--vite", "Use Vite for development server").action((options) => {
  devCommand({
    cleanBuildDirectory: options.cleanBuildDir,
    genWatch: options.genWatch === true ? "." : options.genWatch,
    command: options.vite ? ["vite"] : void 0
  });
});
var create = new Command("create").description("Create a new project from a template.").argument("[project-name]", "Name of the project").action(async (projectName) => {
  try {
    const config = await getConfig().catch(() => ({}));
    await createCommand(projectName, config);
  } catch (error) {
    console.error(
      "\u274C Project creation failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var addInstalled = new Command("installed").description("Add installed integrations to the current project.").option("-w, --workspace <workspace>", "Workspace name").action(async (options) => {
  try {
    await addCommand({
      workspace: options.workspace,
      local: getLocal()
    });
  } catch (error) {
    console.error(
      "\u274C Failed to add integrations:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var addRegistry = new Command("registry").description("Add apps from the registry to the current project.").option("-w, --workspace <workspace>", "Workspace name").action(async (options) => {
  try {
    await addRegistryCommand({
      workspace: options.workspace,
      local: getLocal()
    });
  } catch (error) {
    console.error(
      "\u274C Failed to add registry apps:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var add = new Command("add").description("Add integrations from the registry to the current project.").argument("[app-name]", "Registry app name (e.g., @deco/pinecone-assistant)").option("-w, --workspace <workspace>", "Workspace name").option("--no-gen", "Skip generating types after adding").addCommand(addInstalled).addCommand(addRegistry).action(async (appName, options) => {
  if (appName) {
    try {
      await addRegistryCommand({
        workspace: options.workspace,
        local: getLocal(),
        appName,
        skipGen: !options.gen
      });
    } catch (error) {
      console.error(
        "\u274C Failed to add registry app:",
        error instanceof Error ? error.message : String(error)
      );
      process28.exit(1);
    }
    return;
  }
  try {
    await addRegistryCommand({
      workspace: options.workspace,
      local: getLocal()
    });
  } catch (error) {
    console.error(
      "\u274C Failed to add registry apps:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var callTool = new Command("call-tool").description("Call a tool on an integration using MCP protocol.").argument("<tool>", "Name of the tool to call").option(
  "-i, --integration <integration>",
  "Integration ID to call the tool on"
).option("-p, --payload <payload>", "JSON payload to send to the tool").option(
  "--set <key=value>",
  "Set a key-value pair in the payload (can be used multiple times)",
  (value, previous) => {
    return previous ? [...previous, value] : [value];
  }
).option("-w, --workspace <workspace>", "Workspace name").configureHelp({
  subcommandTerm: (cmd) => cmd.name()
  // for auto-completion
}).action(async (toolName, options) => {
  if (!options.integration) {
    console.error(
      "\u274C Integration ID is required. Use -i or --integration flag."
    );
    try {
      console.log("\u{1F50D} Available integrations:");
      const integrations = await autocompleteIntegrations("");
      if (integrations.length > 0) {
        integrations.slice(0, 10).forEach((id) => console.log(`  \u2022 ${id}`));
        if (integrations.length > 10) {
          console.log(`  ... and ${integrations.length - 10} more`);
        }
      } else {
        console.log(
          "  No integrations found. Run 'deco add' to add integrations."
        );
      }
    } catch {
      console.log("  Run 'deco add' to add integrations.");
    }
    process28.exit(1);
  }
  try {
    await callToolCommand(toolName, {
      integration: options.integration,
      payload: options.payload,
      set: options.set,
      workspace: options.workspace
    });
  } catch (error) {
    console.error(
      "\u274C Tool call failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var completion = new Command("completion").description("Generate shell completions (internal command)").argument("<type>", "Type of completion to generate").option("--current <current>", "Current word being completed").option("--previous <previous>", "Previous word in command line").option("--line <line>", "Full command line").action(async (type, options) => {
  try {
    await completionCommand(type, {
      current: options.current,
      previous: options.previous,
      line: options.line
    });
  } catch {
  }
});
var installCompletion = new Command("install-completion").description("Install shell completion scripts").argument(
  "[shell]",
  "Target shell (bash, zsh). Auto-detected if not specified"
).option("-o, --output <path>", "Output path for completion script").action(async (shell, options) => {
  try {
    await installCompletionCommand(shell, {
      output: options.output
    });
  } catch (error) {
    console.error(
      "\u274C Failed to install completion:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var hosting = new Command("hosting").description("Manage hosting apps in a workspace.").addCommand(hostingList).addCommand(hostingDeploy).addCommand(hostingPromote);
var gen = new Command("gen").description("Generate the environment that will be used to run the app.").option(
  "-s, --self <url>",
  "Useful to generate a SELF binding for own types based on local mcp server."
).option(
  "-o, --output <path>",
  "Output path for the generated environment file."
).action(async (options) => {
  try {
    const wranglerConfig = await readWranglerConfig();
    const config = await getConfig({});
    const env = await genEnv({
      workspace: config.workspace,
      local: config.local,
      bindings: config.bindings,
      selfUrl: options.self ?? `https://${getAppDomain(
        config.workspace,
        wranglerConfig.name ?? "my-app"
      )}/mcp`
    });
    if (options.output) {
      await writeFile(options.output, env);
    } else {
      console.log(env);
    }
  } catch (error) {
    console.error(
      "\u274C Failed to generate environment:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfigGet = new Command("get").description("Get a file from a deconfig branch.").argument("<path>", "File path to get").option("-b, --branch <branchName>", "Branch name", "main").option("-o, --output <file>", "Output file (defaults to stdout)").option("-w, --workspace <workspace>", "Workspace name").action(async (path4, options) => {
  try {
    const headConfig = await readDeconfigHead();
    const finalOptions = {
      branch: options.branch || headConfig?.branch || "main",
      workspace: options.workspace || headConfig?.workspace
    };
    const config = await getConfig({
      inlineOptions: { workspace: finalOptions.workspace }
    });
    await getCommand({
      path: path4,
      branch: finalOptions.branch,
      output: options.output,
      workspace: config.workspace,
      local: config.local
    });
    if (options.branch || options.workspace || headConfig) {
      await writeDeconfigHead({
        workspace: config.workspace,
        branch: finalOptions.branch,
        path: headConfig?.path || ".",
        pathFilter: headConfig?.pathFilter,
        local: config.local
      });
    }
  } catch (error) {
    console.error(
      "\u274C Get failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfigPut = new Command("put").description("Put a file to a deconfig branch.").argument("<path>", "File path to put").option("-b, --branch <branchName>", "Branch name", "main").option("-f, --file <file>", "Local file to upload").option("-c, --content <content>", "Content to upload").option("-m, --metadata <metadata>", "Metadata JSON string").option("-w, --workspace <workspace>", "Workspace name").action(async (path4, options) => {
  try {
    const headConfig = await readDeconfigHead();
    const finalOptions = {
      branch: options.branch || headConfig?.branch || "main",
      workspace: options.workspace || headConfig?.workspace
    };
    const config = await getConfig({
      inlineOptions: { workspace: finalOptions.workspace }
    });
    await putCommand({
      path: path4,
      branch: finalOptions.branch,
      file: options.file,
      content: options.content,
      metadata: options.metadata,
      workspace: config.workspace,
      local: config.local
    });
    if (options.branch || options.workspace || headConfig) {
      await writeDeconfigHead({
        workspace: config.workspace,
        branch: finalOptions.branch,
        path: headConfig?.path || ".",
        pathFilter: headConfig?.pathFilter,
        local: config.local
      });
    }
  } catch (error) {
    console.error(
      "\u274C Put failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfigWatch = new Command("watch").description("Watch a deconfig branch for changes.").option("-b, --branch <branchName>", "Branch name", "main").option("-p, --path <path>", "Path filter for watching specific files", ".").option(
  "--from-ctime <ctime>",
  "Start watching from this ctime",
  (value) => parseInt(value),
  1
).option("-w, --workspace <workspace>", "Workspace name").action(async (options) => {
  try {
    const headConfig = await readDeconfigHead();
    const finalOptions = {
      branch: options.branch || headConfig?.branch || "main",
      workspace: options.workspace || headConfig?.workspace,
      path: options.path || headConfig?.path || "."
    };
    const config = await getConfig({
      inlineOptions: { workspace: finalOptions.workspace }
    });
    await watchCommand({
      branch: finalOptions.branch,
      path: finalOptions.path,
      fromCtime: options.fromCtime,
      workspace: config.workspace,
      local: config.local
    });
    if (options.branch || options.workspace || options.path || headConfig) {
      await writeDeconfigHead({
        workspace: config.workspace,
        branch: finalOptions.branch,
        path: finalOptions.path,
        pathFilter: headConfig?.pathFilter,
        local: config.local
      });
    }
  } catch (error) {
    console.error(
      "\u274C Watch failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfigClone = new Command("clone").description("Clone a deconfig branch to a local directory.").option("-b, --branch <branchName>", "Branch name to clone", "main").requiredOption(
  "--path <path>",
  "Local directory path to clone files to",
  "."
).option("--path-filter <filter>", "Filter files by path pattern").option("-w, --workspace <workspace>", "Workspace name").action(async (options) => {
  try {
    const config = await getConfig({
      inlineOptions: { workspace: options.workspace }
    });
    await cloneCommand({
      branchName: options.branch,
      path: options.path,
      pathFilter: options.pathFilter,
      workspace: config.workspace,
      local: config.local
    });
  } catch (error) {
    console.error(
      "\u274C Clone failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfigPush = new Command("push").description(
  "Push local files to a deconfig branch (rsync-like behavior with change detection)"
).option("-b, --branch <branchName>", "Branch name to push to", "main").requiredOption(
  "--path <path>",
  "Local directory path to push files from",
  "."
).option("--path-filter <filter>", "Filter files by path pattern").option("--dry-run", "Show what would be pushed without making changes").option("--watch", "Watch directory for changes and auto-push modified files").option("-w, --workspace <workspace>", "Workspace name").addHelpText(
  "after",
  `
Examples:
  $ deco deconfig push --path ./src --branch main
  $ deco deconfig push --path ./docs --path-filter "/docs/" --dry-run
  $ deco deconfig push --path ./src --watch --branch main

This command works like rsync:
- Compares local file hashes with remote file hashes
- Only uploads changed files (new or modified content)
- Respects .deconfigignore files (gitignore-style patterns)
- Built-in patterns: node_modules/, .git/, .deconfig/, .DS_Store, *.tmp, *.temp, .env.local
- Watch mode: Monitors directory and auto-pushes changes (500ms debounce)

.deconfigignore syntax (like .gitignore):
  *.log        # ignore all .log files
  /temp        # ignore temp in project root only
  build/       # ignore build directories
  !important.txt # negate pattern (include file)

Watch mode features:
- Performs initial push, then monitors for file changes
- Debounces rapid changes (500ms delay) to avoid spam
- Respects .deconfigignore patterns
- Graceful shutdown with Ctrl+C

Note: Deletion detection is not yet implemented - files deleted locally
will remain on the remote branch until manually deleted with 'deco deconfig delete'.
`
).action(async (options) => {
  try {
    const headConfig = await readDeconfigHead();
    const finalOptions = {
      branch: options.branch || headConfig?.branch || "main",
      workspace: options.workspace || headConfig?.workspace,
      path: options.path || headConfig?.path || ".",
      pathFilter: options.pathFilter || headConfig?.pathFilter
    };
    const config = await getConfig({
      inlineOptions: { workspace: finalOptions.workspace }
    });
    await pushCommand({
      branchName: finalOptions.branch,
      path: finalOptions.path,
      pathFilter: finalOptions.pathFilter,
      dryRun: options.dryRun,
      watch: options.watch,
      workspace: config.workspace,
      local: config.local
    });
    if (options.branch || options.workspace || options.path || options.pathFilter || headConfig) {
      await writeDeconfigHead({
        workspace: config.workspace,
        branch: finalOptions.branch,
        path: finalOptions.path,
        pathFilter: finalOptions.pathFilter,
        local: config.local
      });
    }
  } catch (error) {
    console.error(
      "\u274C Push failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfigPull = new Command("pull").description("Pull changes from a deconfig branch to local directory.").option("-b, --branch <branchName>", "Branch name to pull from", "main").requiredOption("--path <path>", "Local directory path to pull files to", ".").option("--path-filter <filter>", "Filter files by path pattern").option("--dry-run", "Show what would be changed without making changes").option("-w, --workspace <workspace>", "Workspace name").action(async (options) => {
  try {
    const headConfig = await readDeconfigHead();
    const finalOptions = {
      branch: options.branch || headConfig?.branch || "main",
      workspace: options.workspace || headConfig?.workspace,
      path: options.path || headConfig?.path || ".",
      pathFilter: options.pathFilter || headConfig?.pathFilter
    };
    const config = await getConfig({
      inlineOptions: { workspace: finalOptions.workspace }
    });
    await pullCommand({
      branchName: finalOptions.branch,
      path: finalOptions.path,
      pathFilter: finalOptions.pathFilter,
      dryRun: options.dryRun,
      workspace: config.workspace,
      local: config.local
    });
    if (options.branch || options.workspace || options.path || options.pathFilter || headConfig) {
      await writeDeconfigHead({
        workspace: config.workspace,
        branch: finalOptions.branch,
        path: finalOptions.path,
        pathFilter: finalOptions.pathFilter,
        local: config.local
      });
    }
  } catch (error) {
    console.error(
      "\u274C Pull failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfigList = new Command("list").description("Interactively browse and view files in a deconfig branch.").option("-b, --branch <branchName>", "Branch name to list files from", "main").option("--path-filter <filter>", "Filter files by path pattern").option(
  "--format <format>",
  "Content display format: plainString, json, base64",
  "plainString"
).option("-w, --workspace <workspace>", "Workspace name").action(async (options) => {
  try {
    const headConfig = await readDeconfigHead();
    const finalOptions = {
      branch: options.branch || headConfig?.branch || "main",
      workspace: options.workspace || headConfig?.workspace,
      pathFilter: options.pathFilter || headConfig?.pathFilter
    };
    const config = await getConfig({
      inlineOptions: { workspace: finalOptions.workspace }
    });
    await listCommand({
      branchName: finalOptions.branch,
      pathFilter: finalOptions.pathFilter,
      format: options.format,
      workspace: config.workspace,
      local: config.local
    });
    if (options.branch || options.workspace || options.pathFilter || headConfig) {
      await writeDeconfigHead({
        workspace: config.workspace,
        branch: finalOptions.branch,
        path: headConfig?.path || ".",
        pathFilter: finalOptions.pathFilter,
        local: config.local
      });
    }
  } catch (error) {
    console.error(
      "\u274C List failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfigDelete = new Command("delete").description("Delete a file from a deconfig branch.").argument("<path>", "File path to delete").option("-b, --branch <branchName>", "Branch name", "main").option("-w, --workspace <workspace>", "Workspace name").action(async (path4, options) => {
  try {
    const headConfig = await readDeconfigHead();
    const finalOptions = {
      branch: options.branch || headConfig?.branch || "main",
      workspace: options.workspace || headConfig?.workspace
    };
    const config = await getConfig({
      inlineOptions: { workspace: finalOptions.workspace }
    });
    await deleteCommand({
      path: path4,
      branchName: finalOptions.branch,
      workspace: config.workspace,
      local: config.local
    });
    if (options.branch || options.workspace || headConfig) {
      await writeDeconfigHead({
        workspace: config.workspace,
        branch: finalOptions.branch,
        path: headConfig?.path || ".",
        pathFilter: headConfig?.pathFilter,
        local: config.local
      });
    }
  } catch (error) {
    console.error(
      "\u274C Delete failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var deconfig = new Command("deconfig").description("Manage deconfig filesystem operations.").addCommand(deconfigGet).addCommand(deconfigPut).addCommand(deconfigWatch).addCommand(deconfigClone).addCommand(deconfigPush).addCommand(deconfigPull).addCommand(deconfigList).addCommand(deconfigDelete);
var projectExport = new Command("export").description("Export a project to a local directory.").option("--org <slug>", "Organization slug").option("--project <slug>", "Project slug").option("--out <dir>", "Output directory").option("--force", "Overwrite existing files in output directory").option("--local", "Use local API server (http://localhost:8787)").action(async (options) => {
  try {
    const config = await getConfig();
    await exportCommand({
      org: options.org,
      project: options.project,
      out: options.out,
      force: options.force,
      local: options.local || config.local
    });
  } catch (error) {
    console.error(
      "\u274C Export failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var projectImport = new Command("import").description("Import a project from a local directory.").argument(
  "[directory]",
  "Source directory (default: current directory)",
  "./"
).option("--from <dir>", "Source directory (alternative to positional arg)").option("--org <slug>", "Destination organization slug").option("--slug <slug>", "Project slug override").option("--title <title>", "Project title override").action(async (directory, options) => {
  try {
    const config = await getConfig();
    const fromDir = options.from || directory;
    await importCommand({
      from: fromDir,
      org: options.org,
      slug: options.slug,
      title: options.title,
      local: config.local
    });
  } catch (error) {
    console.error(
      "\u274C Import failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var project = new Command("project").description("Manage MCP project import/export.").addCommand(projectExport).addCommand(projectImport);
var registryPublish = new Command("publish").description(
  "Publish an app to the registry from a JSON config file or stdin."
).option(
  "-f, --file <file>",
  "Path to JSON config file (reads from stdin if not provided)"
).option("-w, --workspace <workspace>", "Workspace name").option("-y, --yes", "Skip confirmation").action(async (options) => {
  try {
    const session = await readSession();
    const workspace = options.workspace || session?.workspace;
    if (!workspace) {
      console.error(
        "\u274C No workspace specified. Use -w flag or run 'deco configure' first."
      );
      process28.exit(1);
    }
    await publishApp({
      file: options.file,
      workspace,
      local: getLocal(),
      skipConfirmation: options.yes
    });
  } catch (error) {
    console.error(
      "\u274C Publish failed:",
      error instanceof Error ? error.message : String(error)
    );
    process28.exit(1);
  }
});
var registry = new Command("registry").description("Manage apps in the registry.").addCommand(registryPublish);
var program = new Command().name(packageInfo.name).version(packageInfo.version).description(packageInfo.description).configureOutput({
  writeOut: (str) => {
    if (str.includes(packageInfo.version) && str.trim() === packageInfo.version) {
      const runtime = detectRuntime();
      process28.stdout.write(`${packageInfo.version} (${runtime})
`);
    } else {
      process28.stdout.write(str);
    }
  },
  writeErr: (str) => process28.stderr.write(str)
}).option(
  "-t, --token <token>",
  "Authentication token to use for API requests",
  (token) => {
    setToken(token);
  }
).option(
  "-l, --local",
  `Deploy the app locally (Needs admin.decocms.com running at ${DECO_CMS_API_LOCAL})`,
  () => {
    setLocal(true);
  }
).addHelpText("after", () => {
  const runtime = detectRuntime();
  return `
Runtime: ${runtime}`;
}).addCommand(login).addCommand(logout).addCommand(whoami).addCommand(hosting).addCommand(hostingDeploy).addCommand(hostingPromote).addCommand(dev).addCommand(configure).addCommand(add).addCommand(callTool).addCommand(upgrade2).addCommand(update).addCommand(linkCmd).addCommand(gen).addCommand(create).addCommand(deconfig).addCommand(project).addCommand(registry).addCommand(completion).addCommand(installCompletion);

export { deconfig, program };
//# sourceMappingURL=chunk-KHGXWUCH.js.map
//# sourceMappingURL=chunk-KHGXWUCH.js.map