UNPKG

@botpress/adk-cli

Version:

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

1,800 lines 58.2 kB
// @bun
import {
  createCliLogger
} from "./chunk-gzwt1qdr.js";
import {
  Uk
} from "./chunk-3xrpxgq4.js";

// src/server/handlers/agent-map/deployed-snapshot.ts
import { createHash } from "crypto";

// src/server/handlers/agent-map/ast/locations.ts
import ts2 from "typescript";

// src/server/handlers/agent-map/ast/source-cache.ts
import ts from "typescript";
import { readFileSync } from "fs";
import { resolve } from "path";
var cache = new Map;
function getCachedSourceFile(agentRoot, relativePath) {
  const absPath = resolve(agentRoot, relativePath);
  const cached = cache.get(absPath);
  if (cached !== undefined)
    return cached;
  let source;
  try {
    source = readFileSync(absPath, "utf-8");
  } catch {
    cache.set(absPath, null);
    return null;
  }
  const sourceFile = ts.createSourceFile(absPath, source, ts.ScriptTarget.Latest, true);
  cache.set(absPath, sourceFile);
  return sourceFile;
}
function clearSourceFileCache() {
  cache.clear();
}

// src/server/handlers/agent-map/ast/locations.ts
function getExportLocation(opts) {
  const sourceFile = getCachedSourceFile(opts.agentRoot, opts.relativePath);
  if (!sourceFile)
    return null;
  const found = findExportNode(sourceFile, opts.exportName);
  if (!found)
    return null;
  const start = sourceFile.getLineAndCharacterOfPosition(found.getStart());
  const end = sourceFile.getLineAndCharacterOfPosition(found.getEnd());
  return {
    path: opts.relativePath,
    startLine: start.line + 1,
    endLine: end.line + 1
  };
}
function findExportNode(sourceFile, exportName) {
  let found;
  ts2.forEachChild(sourceFile, (node) => {
    if (found)
      return;
    if (exportName === "default" && ts2.isExportAssignment(node)) {
      found = node;
      return;
    }
    if (!hasExportModifier(node))
      return;
    if (ts2.isVariableStatement(node)) {
      for (const decl of node.declarationList.declarations) {
        if (ts2.isIdentifier(decl.name) && decl.name.text === exportName) {
          found = node;
          return;
        }
      }
      return;
    }
    if (ts2.isFunctionDeclaration(node) && node.name?.text === exportName) {
      found = node;
      return;
    }
    if (ts2.isClassDeclaration(node) && node.name?.text === exportName) {
      found = node;
      return;
    }
    if (exportName === "default" && hasDefaultModifier(node) && (ts2.isFunctionDeclaration(node) || ts2.isClassDeclaration(node))) {
      found = node;
      return;
    }
  });
  return found;
}
function hasExportModifier(node) {
  if (!ts2.canHaveModifiers(node))
    return false;
  const modifiers = ts2.getModifiers(node);
  return !!modifiers?.some((m) => m.kind === ts2.SyntaxKind.ExportKeyword);
}
function hasDefaultModifier(node) {
  if (!ts2.canHaveModifiers(node))
    return false;
  const modifiers = ts2.getModifiers(node);
  return !!modifiers?.some((m) => m.kind === ts2.SyntaxKind.DefaultKeyword);
}
function fallbackLocation(relativePath) {
  return { path: relativePath, startLine: 1, endLine: 1 };
}

// src/server/handlers/agent-map/ast/compiled-bot.ts
import ts3 from "typescript";
import { readFileSync as readFileSync2 } from "fs";
import { join } from "path";
function parseCompiledBotIntegrations(agentRoot) {
  const result = new Map;
  const botDefPath = join(agentRoot, ".adk", "bot", "bot.definition.ts");
  let source;
  try {
    source = readFileSync2(botDefPath, "utf-8");
  } catch {
    return result;
  }
  const sourceFile = ts3.createSourceFile(botDefPath, source, ts3.ScriptTarget.Latest, true);
  for (const call of findAddIntegrationCalls(sourceFile)) {
    const configArg = call.arguments[1];
    if (!configArg || !ts3.isObjectLiteralExpression(configArg))
      continue;
    const alias = getStringProperty(configArg, "alias");
    if (!alias)
      continue;
    result.set(alias, {
      alias,
      enabled: getBooleanProperty(configArg, "enabled") ?? true,
      hasConfiguration: hasProperty(configArg, "configuration")
    });
  }
  return result;
}
function findAddIntegrationCalls(sourceFile) {
  const results = [];
  function visit(node) {
    if (ts3.isCallExpression(node) && ts3.isPropertyAccessExpression(node.expression) && node.expression.name.text === "addIntegration") {
      results.push(node);
    }
    ts3.forEachChild(node, visit);
  }
  visit(sourceFile);
  return results;
}
function getPropertyName(prop) {
  if (ts3.isIdentifier(prop.name))
    return prop.name.text;
  if (ts3.isStringLiteral(prop.name))
    return prop.name.text;
  return;
}
function findProperty(obj, name) {
  for (const prop of obj.properties) {
    if (ts3.isPropertyAssignment(prop) && getPropertyName(prop) === name) {
      return prop;
    }
  }
  return;
}
function getStringProperty(obj, name) {
  const prop = findProperty(obj, name);
  if (prop && ts3.isStringLiteral(prop.initializer)) {
    return prop.initializer.text;
  }
  return;
}
function getBooleanProperty(obj, name) {
  const prop = findProperty(obj, name);
  if (!prop)
    return;
  if (prop.initializer.kind === ts3.SyntaxKind.TrueKeyword)
    return true;
  if (prop.initializer.kind === ts3.SyntaxKind.FalseKeyword)
    return false;
  return;
}
function hasProperty(obj, name) {
  return findProperty(obj, name) !== undefined;
}

// src/server/handlers/agent-map/ast/workflow-steps.ts
import ts4 from "typescript";
function parseWorkflowSteps(opts) {
  const sourceFile = getCachedSourceFile(opts.agentRoot, opts.relativePath);
  if (!sourceFile)
    return [];
  const handlerBody = findWorkflowHandlerBody(sourceFile, opts.exportName);
  if (!handlerBody)
    return [];
  const ctx = {
    sourceFile,
    relativePath: opts.relativePath,
    workflowId: opts.workflowId,
    counter: 0
  };
  const result = [];
  walk(handlerBody, result, ctx);
  return result;
}
function walk(node, parent, ctx) {
  ts4.forEachChild(node, (child) => {
    if (ts4.isCallExpression(child)) {
      const classification = classifyStepCall(child);
      if (classification) {
        const step = {
          id: `${ctx.workflowId}/step:${ctx.counter++}`,
          name: classification.name,
          kind: classification.kind,
          definedAt: nodeLocation(child, ctx)
        };
        if (classification.kind === "iterate") {
          step.children = [];
          const cb = child.arguments[2];
          if (cb && (ts4.isArrowFunction(cb) || ts4.isFunctionExpression(cb))) {
            walk(cb.body, step.children, ctx);
          }
        }
        parent.push(step);
        return;
      }
    }
    walk(child, parent, ctx);
  });
}
function nodeLocation(node, ctx) {
  const start = ctx.sourceFile.getLineAndCharacterOfPosition(node.getStart(ctx.sourceFile));
  const end = ctx.sourceFile.getLineAndCharacterOfPosition(node.getEnd());
  return {
    path: ctx.relativePath,
    startLine: start.line + 1,
    endLine: end.line + 1
  };
}
var METHOD_KINDS = {
  listen: "listen",
  progress: "progress",
  request: "request",
  notify: "notify",
  sleep: "sleep",
  sleepUntil: "sleep",
  forEach: "iterate",
  map: "iterate",
  batch: "iterate",
  waitForWorkflow: "waitForWorkflow",
  executeWorkflow: "waitForWorkflow"
};
function classifyStepCall(call) {
  const expr = call.expression;
  if (ts4.isIdentifier(expr) && expr.text === "step") {
    const name = stringArg(call.arguments[0]);
    if (name === undefined)
      return null;
    return { kind: "generic", name };
  }
  if (ts4.isPropertyAccessExpression(expr) && ts4.isIdentifier(expr.expression) && expr.expression.text === "step") {
    const method = expr.name.text;
    if (method === "fail" || method === "abort")
      return null;
    const kind = METHOD_KINDS[method];
    if (!kind) {
      const name2 = stringArg(call.arguments[0]) ?? `step.${method}`;
      return { kind: "unknown", name: name2 };
    }
    let name;
    if (kind === "request" || kind === "notify") {
      name = stringArg(call.arguments[2]) ?? stringArg(call.arguments[0]);
    } else {
      name = stringArg(call.arguments[0]);
    }
    if (name === undefined)
      return null;
    return { kind, name };
  }
  return null;
}
function stringArg(node) {
  if (!node)
    return;
  if (ts4.isStringLiteral(node) || ts4.isNoSubstitutionTemplateLiteral(node)) {
    return node.text;
  }
  return;
}
function findWorkflowHandlerBody(sourceFile, exportName) {
  let exactMatch;
  let firstMatch;
  function visit(node) {
    if (exactMatch)
      return;
    if (ts4.isNewExpression(node) && ts4.isIdentifier(node.expression) && node.expression.text === "Workflow") {
      const arg = node.arguments?.[0];
      if (arg && ts4.isObjectLiteralExpression(arg)) {
        const handlerBody = extractHandlerBody(arg);
        if (handlerBody) {
          if (firstMatch === undefined)
            firstMatch = handlerBody;
          if (isExportedAs(node, exportName)) {
            exactMatch = handlerBody;
            return;
          }
        }
      }
    }
    ts4.forEachChild(node, visit);
  }
  visit(sourceFile);
  return exactMatch ?? firstMatch;
}
function extractHandlerBody(obj) {
  for (const prop of obj.properties) {
    if (ts4.isPropertyAssignment(prop) && propName(prop.name) === "handler") {
      const init = prop.initializer;
      if (ts4.isArrowFunction(init) || ts4.isFunctionExpression(init)) {
        return init.body;
      }
    }
    if (ts4.isMethodDeclaration(prop) && propName(prop.name) === "handler") {
      if (prop.body)
        return prop.body;
    }
  }
  return;
}
function isExportedAs(newExpr, exportName) {
  let cursor = newExpr.parent;
  while (cursor) {
    if (ts4.isVariableDeclaration(cursor)) {
      const decl = cursor;
      const matchesName = ts4.isIdentifier(decl.name) && decl.name.text === exportName;
      if (!matchesName)
        return false;
      const stmt = decl.parent.parent;
      if (stmt && ts4.isVariableStatement(stmt) && ts4.canHaveModifiers(stmt) && ts4.getModifiers(stmt)?.some((m) => m.kind === ts4.SyntaxKind.ExportKeyword)) {
        return true;
      }
      return false;
    }
    cursor = cursor.parent;
  }
  return false;
}
function propName(name) {
  if (ts4.isIdentifier(name))
    return name.text;
  if (ts4.isStringLiteral(name))
    return name.text;
  return;
}

// src/server/handlers/agent-map/ast/facts-to-graph.ts
function factsToGraph(facts) {
  const edges = [];
  const seenEdges = new Set;
  const integrationActions = new Map;
  const aiAgents = [];
  function addEdge(edge) {
    if (seenEdges.has(edge.id))
      return;
    seenEdges.add(edge.id);
    edges.push(edge);
  }
  for (const fact of facts) {
    switch (fact.kind) {
      case "primitiveCall": {
        addEdge(makeEdge({
          sourceId: fact.sourceId,
          sourceType: fact.sourceType,
          target: fact.target,
          type: fact.edgeType,
          via: "handler"
        }));
        break;
      }
      case "integrationActionCall": {
        if (!integrationActions.has(fact.actionId)) {
          integrationActions.set(fact.actionId, { id: fact.actionId, name: fact.name, alias: fact.alias });
        }
        addEdge(makeEdge({
          sourceId: fact.sourceId,
          sourceType: fact.sourceType,
          target: { id: fact.actionId, type: "integrationAction" },
          type: "invokes",
          via: "handler"
        }));
        break;
      }
      case "executeBlock": {
        const aiAgent = makeAIAgent(fact);
        aiAgents.push(aiAgent);
        addEdge(makeEdge({
          sourceId: fact.parentId,
          sourceType: fact.parentType,
          target: { id: aiAgent.id, type: "aiAgent" },
          type: "invokes",
          via: "handler"
        }));
        for (const ref of fact.toolRefRecords) {
          addEdge(makeEdge({
            sourceId: aiAgent.id,
            sourceType: "aiAgent",
            target: ref,
            type: "invokes",
            via: "agent-loop"
          }));
        }
        for (const ref of fact.knowledgeRefRecords) {
          addEdge(makeEdge({
            sourceId: aiAgent.id,
            sourceType: "aiAgent",
            target: ref,
            type: "queries",
            via: "agent-loop"
          }));
        }
        break;
      }
    }
  }
  return {
    edges,
    integrationActions: [...integrationActions.values()],
    aiAgents
  };
}
function makeAIAgent(fact) {
  const definedAt = {
    path: fact.callsite.path,
    startLine: fact.callsite.startLine,
    endLine: fact.callsite.endLine
  };
  return {
    id: makeAIAgentId(fact),
    parentId: fact.parentId,
    parentType: fact.parentType,
    definedAt,
    model: fact.model ?? "default",
    toolRefs: fact.toolRefs,
    knowledgeRefs: fact.knowledgeRefs,
    ...fact.iterations !== undefined && { iterations: fact.iterations },
    ...fact.mode !== undefined && { mode: fact.mode },
    ...fact.temperature !== undefined && { temperature: fact.temperature },
    ...fact.reasoningEffort !== undefined && { reasoningEffort: fact.reasoningEffort },
    ...fact.instructions !== undefined && { instructions: fact.instructions },
    ...fact.exits !== undefined && { exits: fact.exits },
    ...fact.hooks !== undefined && { hooks: fact.hooks },
    ...fact.objects !== undefined && { objects: fact.objects },
    parseStatus: { ok: true }
  };
}
function makeAIAgentId(fact) {
  return `aiAgent:${fact.parentId}:${fact.callsite.startLine}:${fact.callsite.startColumn}`;
}
function makeEdge(opts) {
  return {
    id: `edge:${opts.sourceId}->${opts.type}->${opts.target.id}`,
    source: opts.sourceId,
    sourceType: opts.sourceType,
    target: opts.target.id,
    targetType: opts.target.type,
    type: opts.type,
    via: opts.via
  };
}

// src/server/handlers/agent-map/ast/project-index.ts
var logger = createCliLogger({ tag: "agent-map" });
function buildProjectIndex(project) {
  const exportLookup = new Map;
  const actionByName = new Map;
  const knownIntegrationAliases = new Set;
  function register(exportName, ref) {
    const existing = exportLookup.get(exportName);
    if (existing && existing.id !== ref.id) {
      logger.warn(`export-name collision on "${exportName}": "${existing.id}" overwritten by "${ref.id}". ` + `Edges from handlers that imported "${existing.id}" will resolve to "${ref.id}". ` + `Rename one of the exports to disambiguate.`);
    }
    exportLookup.set(exportName, ref);
  }
  for (const ref of project.actions) {
    if (isBuiltInPrimitive(ref))
      continue;
    const primitiveRef = { id: `action:${ref.definition.name}`, type: "action" };
    register(ref.export, primitiveRef);
    actionByName.set(ref.definition.name, primitiveRef);
  }
  for (const ref of project.tools) {
    if (isBuiltInPrimitive(ref))
      continue;
    register(ref.export, { id: `tool:${ref.definition.name}`, type: "tool" });
  }
  for (const ref of project.workflows) {
    if (isBuiltInPrimitive(ref))
      continue;
    register(ref.export, { id: `workflow:${ref.definition.name}`, type: "workflow" });
  }
  for (const ref of project.tables) {
    register(ref.export, { id: `table:${ref.definition.name}`, type: "table" });
  }
  for (const ref of project.knowledge) {
    register(ref.export, { id: `knowledge:${ref.definition.name}`, type: "knowledge" });
  }
  for (const ref of project.integrations) {
    knownIntegrationAliases.add(ref.alias);
  }
  return { exportLookup, actionByName, knownIntegrationAliases };
}
function isBuiltInPrimitive(ref) {
  if (ref.path === "<adk:builtin>")
    return true;
  if (ref.definition?.name?.startsWith("data_source_sync_"))
    return true;
  return false;
}

// src/server/handlers/agent-map/ast/source-walk.ts
import ts10 from "typescript";

// src/server/handlers/agent-map/ast/import-resolution.ts
import ts5 from "typescript";
function buildImportResolution(sourceFile, globalLookup) {
  const resolution = new Map;
  for (const stmt of sourceFile.statements) {
    if (!ts5.isImportDeclaration(stmt) || !stmt.importClause)
      continue;
    if (stmt.importClause.name) {
      const localName = stmt.importClause.name.text;
      const ref = globalLookup.get(localName);
      if (ref !== undefined)
        resolution.set(localName, ref);
    }
    const bindings = stmt.importClause.namedBindings;
    if (bindings && ts5.isNamedImports(bindings)) {
      for (const elem of bindings.elements) {
        const localName = elem.name.text;
        const lookupName = elem.propertyName?.text ?? localName;
        const ref = globalLookup.get(lookupName);
        if (ref !== undefined)
          resolution.set(localName, ref);
      }
    }
  }
  return resolution;
}

// src/server/handlers/agent-map/ast/matchers/actions-proxy.ts
import ts6 from "typescript";
var matchActionsProxyCall = (node, ctx) => {
  if (!ts6.isCallExpression(node) || !ts6.isPropertyAccessExpression(node.expression))
    return null;
  const inner = node.expression.expression;
  const lastName = node.expression.name.text;
  if (ts6.isIdentifier(inner) && inner.text === "actions") {
    const ref = ctx.projectIndex.actionByName.get(lastName);
    if (!ref)
      return null;
    return {
      facts: [
        {
          kind: "primitiveCall",
          sourceId: ctx.callerId,
          sourceType: ctx.callerType,
          target: ref,
          edgeType: "invokes"
        }
      ],
      traversal: "continue"
    };
  }
  if (ts6.isPropertyAccessExpression(inner) && ts6.isIdentifier(inner.expression) && inner.expression.text === "actions") {
    const alias = inner.name.text;
    if (!ctx.projectIndex.knownIntegrationAliases.has(alias))
      return null;
    const actionId = `integrationAction:${alias}:${lastName}`;
    return {
      facts: [
        {
          kind: "integrationActionCall",
          sourceId: ctx.callerId,
          sourceType: ctx.callerType,
          alias,
          name: lastName,
          actionId
        }
      ],
      traversal: "continue"
    };
  }
  return null;
};

// src/server/handlers/agent-map/ast/matchers/execute.ts
import ts8 from "typescript";

// src/server/handlers/agent-map/ast/execute-blocks.ts
import ts7 from "typescript";
function extractExecuteBlockFact(opts) {
  const { call, sourceFile, resolution, parentId, parentType, relativePath } = opts;
  const start = sourceFile.getLineAndCharacterOfPosition(call.getStart(sourceFile));
  const startLine = start.line + 1;
  const startColumn = start.character + 1;
  const endLine = sourceFile.getLineAndCharacterOfPosition(call.getEnd()).line + 1;
  const props = extractExecuteProps(call, resolution);
  return {
    kind: "executeBlock",
    parentId,
    parentType,
    callsite: {
      path: relativePath,
      startLine,
      startColumn,
      endLine
    },
    ...props.model !== undefined && { model: props.model },
    toolRefs: props.toolRefs,
    knowledgeRefs: props.knowledgeRefs,
    toolRefRecords: props.toolRefRecords,
    knowledgeRefRecords: props.knowledgeRefRecords,
    ...props.iterations !== undefined && { iterations: props.iterations },
    ...props.mode !== undefined && { mode: props.mode },
    ...props.temperature !== undefined && { temperature: props.temperature },
    ...props.reasoningEffort !== undefined && { reasoningEffort: props.reasoningEffort },
    ...props.instructions !== undefined && { instructions: props.instructions },
    ...props.exits !== undefined && { exits: props.exits },
    ...props.hooks !== undefined && { hooks: props.hooks },
    ...props.objects !== undefined && { objects: props.objects }
  };
}
function isExecuteCall(call) {
  const expr = call.expression;
  if (ts7.isIdentifier(expr) && expr.text === "execute")
    return true;
  if (ts7.isPropertyAccessExpression(expr) && expr.name.text === "execute" && ts7.isIdentifier(expr.expression) && expr.expression.text === "Autonomous") {
    return true;
  }
  return false;
}
var TOOL_TYPES = new Set(["action", "tool", "workflow"]);
function extractExecuteProps(call, resolution) {
  const props = {
    toolRefs: [],
    knowledgeRefs: [],
    toolRefRecords: [],
    knowledgeRefRecords: []
  };
  const arg = call.arguments[0];
  if (!arg || !ts7.isObjectLiteralExpression(arg))
    return props;
  for (const prop of arg.properties) {
    if (!ts7.isPropertyAssignment(prop))
      continue;
    const key = ts7.isIdentifier(prop.name) ? prop.name.text : null;
    if (!key)
      continue;
    const init = prop.initializer;
    switch (key) {
      case "model":
      case "mode":
      case "reasoningEffort": {
        const s = stringLiteral(init);
        if (s !== null)
          props[key] = s;
        break;
      }
      case "instructions": {
        const instructions = instructionText(init);
        if (instructions !== null)
          props.instructions = instructions;
        break;
      }
      case "iterations":
      case "temperature": {
        const n = numberLiteral(init);
        if (n !== null)
          props[key] = n;
        break;
      }
      case "exits":
      case "objects": {
        const names = identifierArray(init);
        if (names.length > 0)
          props[key] = names;
        break;
      }
      case "hooks": {
        const names = objectKeyNames(init);
        if (names.length > 0)
          props[key] = names;
        break;
      }
      case "tools":
      case "knowledge": {
        if (!ts7.isArrayLiteralExpression(init))
          break;
        for (const elem of init.elements) {
          const ref = resolveToolElement(elem, resolution);
          if (!ref)
            continue;
          if (key === "tools" && !TOOL_TYPES.has(ref.type))
            continue;
          if (key === "knowledge" && ref.type !== "knowledge")
            continue;
          const records = key === "tools" ? props.toolRefRecords : props.knowledgeRefRecords;
          const ids = key === "tools" ? props.toolRefs : props.knowledgeRefs;
          if (!ids.includes(ref.id)) {
            ids.push(ref.id);
            records.push(ref);
          }
        }
        break;
      }
      default:
        break;
    }
  }
  return props;
}
function resolveToolElement(elem, resolution) {
  if (ts7.isIdentifier(elem)) {
    return resolution.get(elem.text) ?? null;
  }
  if (ts7.isCallExpression(elem) && ts7.isPropertyAccessExpression(elem.expression) && elem.expression.name.text === "asTool" && ts7.isIdentifier(elem.expression.expression)) {
    return resolution.get(elem.expression.expression.text) ?? null;
  }
  return null;
}
function stringLiteral(node) {
  if (ts7.isStringLiteral(node) || ts7.isNoSubstitutionTemplateLiteral(node))
    return node.text;
  return null;
}
function instructionText(node) {
  const unwrapped = unwrapStringExpression(node);
  const literal = stringLiteral(unwrapped);
  if (literal !== null)
    return literal.trim();
  if (ts7.isTemplateExpression(unwrapped)) {
    const parts = [unwrapped.head.text];
    for (const span of unwrapped.templateSpans) {
      parts.push(`\${${span.expression.getText()}}`);
      parts.push(span.literal.text);
    }
    return parts.join("").trim();
  }
  return null;
}
function unwrapStringExpression(node) {
  if (ts7.isParenthesizedExpression(node))
    return unwrapStringExpression(node.expression);
  if (ts7.isCallExpression(node) && ts7.isPropertyAccessExpression(node.expression) && node.expression.name.text === "trim") {
    return unwrapStringExpression(node.expression.expression);
  }
  return node;
}
function numberLiteral(node) {
  if (ts7.isNumericLiteral(node))
    return Number(node.text);
  return null;
}
function identifierArray(node) {
  if (!ts7.isArrayLiteralExpression(node))
    return [];
  const names = [];
  for (const elem of node.elements) {
    if (ts7.isIdentifier(elem))
      names.push(elem.text);
  }
  return names;
}
function objectKeyNames(node) {
  if (!ts7.isObjectLiteralExpression(node))
    return [];
  const names = [];
  for (const prop of node.properties) {
    const name = ts7.isPropertyAssignment(prop) || ts7.isShorthandPropertyAssignment(prop) || ts7.isMethodDeclaration(prop) ? ts7.isIdentifier(prop.name) ? prop.name.text : ts7.isStringLiteral(prop.name) ? prop.name.text : null : null;
    if (name)
      names.push(name);
  }
  return names;
}

// src/server/handlers/agent-map/ast/matchers/execute.ts
var matchExecuteCall = (node, ctx) => {
  if (!ts8.isCallExpression(node) || !isExecuteCall(node))
    return null;
  return {
    facts: [
      extractExecuteBlockFact({
        call: node,
        sourceFile: ctx.sourceFile,
        resolution: ctx.fileResolution,
        parentId: ctx.callerId,
        parentType: ctx.callerType,
        relativePath: ctx.relativePath
      })
    ],
    traversal: "skip-subtree"
  };
};

// src/server/handlers/agent-map/ast/matchers/primitive-calls.ts
import ts9 from "typescript";
var TABLE_READ_METHODS = new Set(["findRows", "getRow", "getRows", "list", "select", "find"]);
var TABLE_WRITE_METHODS = new Set([
  "createRows",
  "insertRows",
  "updateRows",
  "upsertRows",
  "deleteRows",
  "deleteRowIds",
  "deleteRow"
]);
var KB_SEARCH_METHODS = new Set(["search", "find", "query"]);
var WORKFLOW_INVOKE_METHODS = new Set(["start", "startAndWait", "getOrCreate"]);
var matchPrimitiveCall = (node, ctx) => {
  if (!ts9.isCallExpression(node))
    return null;
  if (ts9.isPropertyAccessExpression(node.expression)) {
    const target = node.expression.expression;
    const method = node.expression.name.text;
    if (ts9.isIdentifier(target)) {
      const ref = ctx.fileResolution.get(target.text);
      if (ref) {
        const edgeType = classifyMethodOnPrimitive(ref.type, method);
        if (edgeType) {
          return {
            facts: [
              {
                kind: "primitiveCall",
                sourceId: ctx.callerId,
                sourceType: ctx.callerType,
                target: ref,
                edgeType
              }
            ],
            traversal: "continue"
          };
        }
      }
    }
  }
  if (ts9.isIdentifier(node.expression)) {
    const ref = ctx.fileResolution.get(node.expression.text);
    if (ref && (ref.type === "action" || ref.type === "workflow")) {
      return {
        facts: [
          {
            kind: "primitiveCall",
            sourceId: ctx.callerId,
            sourceType: ctx.callerType,
            target: ref,
            edgeType: "invokes"
          }
        ],
        traversal: "continue"
      };
    }
  }
  return null;
};
function classifyMethodOnPrimitive(type, method) {
  if (type === "table") {
    if (TABLE_READ_METHODS.has(method))
      return "reads";
    if (TABLE_WRITE_METHODS.has(method))
      return "writes";
    return null;
  }
  if (type === "workflow") {
    if (WORKFLOW_INVOKE_METHODS.has(method))
      return "invokes";
    return null;
  }
  if (type === "knowledge") {
    if (KB_SEARCH_METHODS.has(method))
      return "queries";
    return null;
  }
  return null;
}

// src/server/handlers/agent-map/ast/source-walk.ts
var MATCHERS = [matchExecuteCall, matchPrimitiveCall, matchActionsProxyCall];
function extractFactsFromFile(opts) {
  const sourceFile = getCachedSourceFile(opts.agentRoot, opts.relativePath);
  if (!sourceFile)
    return [];
  const ctx = {
    sourceFile,
    relativePath: opts.relativePath,
    callerId: opts.callerId,
    callerType: opts.callerType,
    fileResolution: buildImportResolution(sourceFile, opts.projectIndex.exportLookup),
    projectIndex: opts.projectIndex
  };
  const facts = [];
  function visit(node) {
    for (const matcher of MATCHERS) {
      const result = matcher(node, ctx);
      if (!result)
        continue;
      facts.push(...result.facts);
      if (result.traversal === "skip-subtree")
        return;
    }
    ts10.forEachChild(node, visit);
  }
  visit(sourceFile);
  return facts;
}

// src/server/handlers/agent-map/ast/handler-edges.ts
function extractAstEdges(opts) {
  const projectIndex = buildProjectIndex(opts.project);
  const facts = [];
  for (const caller of opts.callers) {
    facts.push(...extractFactsFromFile({
      agentRoot: opts.project.path,
      relativePath: caller.relativePath,
      callerId: caller.primitiveId,
      callerType: caller.primitiveType,
      projectIndex
    }));
  }
  return factsToGraph(facts);
}

// src/server/handlers/agent-map/ast/component-refs.ts
import ts11 from "typescript";
function extractComponentRefs(opts) {
  const sourceFile = getCachedSourceFile(opts.agentRoot, opts.relativePath);
  if (!sourceFile)
    return [];
  const fileResolution = buildImportResolution(sourceFile, opts.resolution);
  const found = new Set;
  function visit(node) {
    if (ts11.isNewExpression(node) && ts11.isIdentifier(node.expression) && node.expression.text === "Conversation") {
      const arg = node.arguments?.[0];
      if (arg && ts11.isObjectLiteralExpression(arg)) {
        const componentsProp = arg.properties.find((p) => ts11.isPropertyAssignment(p) && ts11.isIdentifier(p.name) && p.name.text === "components");
        if (componentsProp && ts11.isPropertyAssignment(componentsProp) && ts11.isArrayLiteralExpression(componentsProp.initializer)) {
          for (const elem of componentsProp.initializer.elements) {
            if (ts11.isIdentifier(elem)) {
              const id = fileResolution.get(elem.text);
              if (id)
                found.add(id);
            }
          }
        }
      }
    }
    if (ts11.isCallExpression(node) && ts11.isPropertyAccessExpression(node.expression) && node.expression.name.text === "send") {
      const arg = node.arguments[0];
      if (arg && ts11.isObjectLiteralExpression(arg)) {
        const typeProp = arg.properties.find((p) => ts11.isPropertyAssignment(p) && ts11.isIdentifier(p.name) && p.name.text === "type");
        const isCustomComponent = typeProp && ts11.isPropertyAssignment(typeProp) && ts11.isStringLiteral(typeProp.initializer) && typeProp.initializer.text === "customComponent";
        if (isCustomComponent) {
          const payloadProp = arg.properties.find((p) => ts11.isPropertyAssignment(p) && ts11.isIdentifier(p.name) && p.name.text === "payload");
          if (payloadProp && ts11.isPropertyAssignment(payloadProp) && ts11.isObjectLiteralExpression(payloadProp.initializer)) {
            const componentProp = payloadProp.initializer.properties.find((p) => ts11.isPropertyAssignment(p) && ts11.isIdentifier(p.name) && p.name.text === "component");
            if (componentProp && ts11.isPropertyAssignment(componentProp) && ts11.isIdentifier(componentProp.initializer)) {
              const id = fileResolution.get(componentProp.initializer.text);
              if (id)
                found.add(id);
            }
          }
        }
      }
    }
    ts11.forEachChild(node, visit);
  }
  visit(sourceFile);
  return [...found];
}

// src/server/handlers/agent-map/ast/conversation-lifecycle.ts
import ts12 from "typescript";
function extractConversationAstProps(opts) {
  const sourceFile = getCachedSourceFile(opts.agentRoot, opts.relativePath);
  if (!sourceFile)
    return {};
  let result;
  function visit(node) {
    if (result)
      return;
    if (ts12.isNewExpression(node) && ts12.isIdentifier(node.expression) && node.expression.text === "Conversation") {
      const arg = node.arguments?.[0];
      if (arg && ts12.isObjectLiteralExpression(arg)) {
        result = {
          lifecycle: lifecycleFromConversationProps(arg),
          stateSchema: stateSchemaFromConversationProps(arg)
        };
        if (result.lifecycle || result.stateSchema)
          return;
      }
    }
    ts12.forEachChild(node, visit);
  }
  visit(sourceFile);
  return result ?? {};
}
function lifecycleFromConversationProps(props) {
  const lifecycleProp = findObjectProperty(props, "lifecycle");
  if (!lifecycleProp || !ts12.isObjectLiteralExpression(lifecycleProp.initializer))
    return;
  const lifecycle = {};
  const nudgeProp = findObjectProperty(lifecycleProp.initializer, "nudge");
  if (nudgeProp && ts12.isObjectLiteralExpression(nudgeProp.initializer)) {
    const nudge = {
      after: stringProp(nudgeProp.initializer, "after"),
      interval: stringProp(nudgeProp.initializer, "interval"),
      max: numberProp(nudgeProp.initializer, "max")
    };
    if (nudge.after !== undefined || nudge.interval !== undefined || nudge.max !== undefined) {
      lifecycle.nudge = nudge;
    }
  }
  const expireProp = findObjectProperty(lifecycleProp.initializer, "expire");
  if (expireProp && ts12.isObjectLiteralExpression(expireProp.initializer)) {
    const expire = { after: stringProp(expireProp.initializer, "after") };
    if (expire.after !== undefined) {
      lifecycle.expire = expire;
    }
  }
  return lifecycle.nudge || lifecycle.expire ? lifecycle : undefined;
}
function stateSchemaFromConversationProps(props) {
  const stateProp = findObjectProperty(props, "state");
  if (!stateProp)
    return;
  return parseZuiSchema(stateProp.initializer)?.schema;
}
function parseZuiSchema(node) {
  if (ts12.isParenthesizedExpression(node))
    return parseZuiSchema(node.expression);
  if (!ts12.isCallExpression(node))
    return;
  const callee = node.expression;
  if (!ts12.isPropertyAccessExpression(callee))
    return;
  const method = callee.name.text;
  const receiver = callee.expression;
  if (ts12.isIdentifier(receiver) && receiver.text === "z") {
    return parseBaseZuiCall(method, node);
  }
  const base = parseZuiSchema(receiver);
  if (!base)
    return;
  switch (method) {
    case "optional":
    case "default":
      return { ...base, optional: true };
    case "describe": {
      const description = stringLiteral2(node.arguments[0]);
      return description ? { ...base, schema: { ...base.schema, description } } : base;
    }
    case "nullable":
      return { ...base, schema: { ...base.schema, nullable: true } };
    default:
      return base;
  }
}
function parseBaseZuiCall(method, call) {
  switch (method) {
    case "object":
      return parseZuiObject(call);
    case "string":
      return { schema: { type: "string" }, optional: false };
    case "number":
      return { schema: { type: "number" }, optional: false };
    case "boolean":
      return { schema: { type: "boolean" }, optional: false };
    case "array": {
      const item = call.arguments[0] ? parseZuiSchema(call.arguments[0]) : undefined;
      return { schema: { type: "array", ...item && { items: item.schema } }, optional: false };
    }
    case "record": {
      const valueSchema = call.arguments[1] ? parseZuiSchema(call.arguments[1]) : undefined;
      return {
        schema: { type: "object", ...valueSchema && { additionalProperties: valueSchema.schema } },
        optional: false
      };
    }
    case "enum": {
      const values = stringArray(call.arguments[0]);
      return { schema: values.length > 0 ? { type: "string", enum: values } : { type: "string" }, optional: false };
    }
    case "literal": {
      const value = literalValue(call.arguments[0]);
      return { schema: value === undefined ? {} : { enum: [value] }, optional: false };
    }
    case "any":
    case "unknown":
      return { schema: {}, optional: false };
    default:
      return;
  }
}
function parseZuiObject(call) {
  const shape = call.arguments[0];
  if (!shape || !ts12.isObjectLiteralExpression(shape))
    return { schema: { type: "object" }, optional: false };
  const properties = {};
  const required = [];
  for (const prop of shape.properties) {
    if (!ts12.isPropertyAssignment(prop))
      continue;
    const name = propertyName(prop.name);
    if (!name)
      continue;
    const parsed = parseZuiSchema(prop.initializer);
    if (!parsed)
      continue;
    properties[name] = parsed.schema;
    if (!parsed.optional)
      required.push(name);
  }
  return {
    schema: {
      type: "object",
      properties,
      ...required.length > 0 && { required }
    },
    optional: false
  };
}
function findObjectProperty(object, name) {
  return object.properties.find((prop) => ts12.isPropertyAssignment(prop) && propertyName(prop.name) === name);
}
function propertyName(name) {
  if (ts12.isIdentifier(name) || ts12.isStringLiteral(name) || ts12.isNumericLiteral(name))
    return name.text;
  return;
}
function stringProp(object, name) {
  const prop = findObjectProperty(object, name);
  const value = prop?.initializer;
  if (!value)
    return;
  if (ts12.isStringLiteral(value) || ts12.isNoSubstitutionTemplateLiteral(value))
    return value.text;
  return;
}
function stringLiteral2(value) {
  if (!value)
    return;
  if (ts12.isStringLiteral(value) || ts12.isNoSubstitutionTemplateLiteral(value))
    return value.text;
  return;
}
function numberProp(object, name) {
  const prop = findObjectProperty(object, name);
  const value = prop?.initializer;
  if (!value)
    return;
  if (ts12.isNumericLiteral(value))
    return Number(value.text);
  return;
}
function stringArray(node) {
  if (!node || !ts12.isArrayLiteralExpression(node))
    return [];
  return node.elements.map((elem) => ts12.isStringLiteral(elem) || ts12.isNoSubstitutionTemplateLiteral(elem) ? elem.text : undefined).filter((value) => value !== undefined);
}
function literalValue(node) {
  if (!node)
    return;
  if (ts12.isStringLiteral(node) || ts12.isNoSubstitutionTemplateLiteral(node))
    return node.text;
  if (ts12.isNumericLiteral(node))
    return Number(node.text);
  if (node.kind === ts12.SyntaxKind.TrueKeyword)
    return true;
  if (node.kind === ts12.SyntaxKind.FalseKeyword)
    return false;
  return;
}

// src/server/handlers/agent-map/snapshot.ts
function buildAgentSnapshot(project, options = {}) {
  clearSourceFileCache();
  const integrations = buildIntegrationMeta(project);
  const customComponents = parseCustomComponents(project);
  const componentResolution = new Map(project.customComponents.map((ref) => [ref.export, `customComponent:${ref.definition.name}`]));
  const conversations = parseConversations(project, integrations, componentResolution);
  const triggers = parseTriggers(project, integrations);
  const {
    edges: astEdges,
    integrationActions,
    aiAgents
  } = extractAstEdges({
    project,
    callers: collectCallerSources(project)
  });
  const declarativeEdges = buildDeclarativeUsesComponentEdges(conversations);
  const edges = mergeEdges(declarativeEdges, astEdges);
  return {
    origin: options.origin ?? { kind: "local" },
    agent: buildAgentConfigSummary(project),
    actions: parseActions(project),
    tools: parseTools(project),
    workflows: parseWorkflows(project),
    conversations,
    triggers,
    tables: parseTables(project),
    knowledge: parseKnowledge(project),
    customComponents,
    integrationActions,
    aiAgents,
    edges,
    integrations
  };
}
function buildAgentConfigSummary(project) {
  const config = project.config;
  const state = compactObject({
    user: schemaToJsonSchema(asRecord(config?.user)?.state),
    bot: schemaToJsonSchema(asRecord(config?.bot)?.state)
  });
  const configurationSchema = schemaToJsonSchema(asRecord(config?.configuration)?.schema);
  return {
    ...typeof config?.name === "string" && config.name.length > 0 && { name: config.name },
    ...typeof config?.description === "string" && config.description.length > 0 && { description: config.description },
    defaultModels: normalizeDefaultModels(config?.defaultModels),
    ...Object.keys(state).length > 0 && { state },
    ...normalizeTags(config),
    ...configurationSchema && { configuration: { schema: configurationSchema } },
    secrets: normalizeSecrets(config?.secrets),
    ...normalizeEvals(config?.evals)
  };
}
function normalizeDefaultModels(value) {
  const models = asRecord(value);
  return {
    autonomous: normalizeModelConfig(models.autonomous) ?? "auto",
    zai: normalizeModelConfig(models.zai) ?? "auto"
  };
}
function normalizeModelConfig(value) {
  if (typeof value === "string" && value.length > 0)
    return value;
  if (Array.isArray(value) && value.every((item) => typeof item === "string" && item.length > 0)) {
    return value;
  }
  return;
}
function normalizeTags(config) {
  if (!config)
    return {};
  const tags = {};
  for (const key of ["user", "bot", "conversation", "message", "workflow"]) {
    const normalized = normalizeTagDefinitions(asRecord(config[key])?.tags);
    if (Object.keys(normalized).length > 0) {
      tags[key] = normalized;
    }
  }
  return Object.keys(tags).length > 0 ? { tags } : {};
}
function normalizeTagDefinitions(value) {
  const out = {};
  for (const [name, rawDefinition] of Object.entries(asRecord(value))) {
    const definition = asRecord(rawDefinition);
    out[name] = {
      title: typeof definition.title === "string" && definition.title.length > 0 ? definition.title : name,
      ...typeof definition.description === "string" && definition.description.length > 0 && { description: definition.description }
    };
  }
  return out;
}
function normalizeSecrets(value) {
  return Object.entries(asRecord(value)).map(([name, rawDeclaration]) => {
    const declaration = asRecord(rawDeclaration);
    return {
      name,
      optional: declaration.optional === true,
      ...typeof declaration.description === "string" && declaration.description.length > 0 && { description: declaration.description }
    };
  });
}
function normalizeEvals(value) {
  const evals = asRecord(value);
  const normalized = {
    ...typeof evals.judgeModel === "string" && evals.judgeModel.length > 0 && { judgeModel: evals.judgeModel },
    ...typeof evals.judgePassThreshold === "number" && { judgePassThreshold: evals.judgePassThreshold },
    ...typeof evals.idleTimeout === "number" && { idleTimeout: evals.idleTimeout }
  };
  return Object.keys(normalized).length > 0 ? { evals: normalized } : {};
}
function schemaToJsonSchema(schema) {
  if (!isRecord(schema))
    return;
  if (typeof schema.toJSONSchema === "function") {
    try {
      return schema.toJSONSchema();
    } catch {
      return;
    }
  }
  return schema;
}
function compactObject(value) {
  return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
}
function asRecord(value) {
  return isRecord(value) ? value : {};
}
function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
function collectCallerSources(project) {
  const callers = [];
  for (const ref of project.actions) {
    if (isBuiltInPrimitive2(ref))
      continue;
    callers.push({
      primitiveId: `action:${ref.definition.name}`,
      primitiveType: "action",
      relativePath: ref.path
    });
  }
  for (const ref of project.tools) {
    if (isBuiltInPrimitive2(ref))
      continue;
    callers.push({
      primitiveId: `tool:${ref.definition.name}`,
      primitiveType: "tool",
      relativePath: ref.path
    });
  }
  for (const ref of project.workflows) {
    if (isBuiltInPrimitive2(ref))
      continue;
    callers.push({
      primitiveId: `workflow:${ref.definition.name}`,
      primitiveType: "workflow",
      relativePath: ref.path
    });
  }
  for (const ref of project.conversations) {
    callers.push({
      primitiveId: `conversation:${pathToId(ref.path)}`,
      primitiveType: "conversation",
      relativePath: ref.path
    });
  }
  for (const ref of project.triggers) {
    if (isBuiltInPrimitive2(ref))
      continue;
    callers.push({
      primitiveId: `trigger:${ref.definition.name}`,
      primitiveType: "trigger",
      relativePath: ref.path
    });
  }
  return callers;
}
function isBuiltInPrimitive2(ref) {
  if (ref.path === "<adk:builtin>")
    return true;
  if (ref.definition?.name?.startsWith("data_source_sync_"))
    return true;
  return false;
}
function mergeEdges(a, b) {
  const seen = new Set;
  const result = [];
  for (const e of [...a, ...b]) {
    if (seen.has(e.id))
      continue;
    seen.add(e.id);
    result.push(e);
  }
  return result;
}
function parseActions(project) {
  return project.actions.filter((ref) => !isBuiltInPrimitive2(ref)).map((ref) => {
    const def = ref.definition;
    const definedAt = getExportLocation({
      agentRoot: project.path,
      relativePath: ref.path,
      exportName: ref.export
    }) ?? fallbackLocation(ref.path);
    return {
      id: `action:${def.name}`,
      name: def.name,
      ...def.title !== undefined && { title: def.title },
      ...def.description !== undefined && { description: def.description },
      ...def.attributes !== undefined && { attributes: def.attributes },
      definedAt,
      ...def.input !== undefined && { inputSchema: def.input },
      ...def.output !== undefined && { outputSchema: def.output },
      ...def.cached !== undefined && { cached: def.cached },
      parseStatus: { ok: true }
    };
  });
}
function parseTools(project) {
  return project.tools.filter((ref) => !isBuiltInPrimitive2(ref)).map((ref) => {
    const def = ref.definition;
    const definedAt = getExportLocation({
      agentRoot: project.path,
      relativePath: ref.path,
      exportName: ref.export
    }) ?? fallbackLocation(ref.path);
    return {
      id: `tool:${def.name}`,
      name: def.name,
      ...def.description !== undefined && { description: def.description },
      definedAt,
      parseStatus: { ok: true }
    };
  });
}
function parseTriggers(project, integrations) {
  return project.triggers.filter((ref) => !isBuiltInPrimitive2(ref)).map((ref) => {
    const def = ref.definition;
    const definedAt = getExportLocation({
      agentRoot: project.path,
      relativePath: ref.path,
      exportName: ref.export
    }) ?? fallbackLocation(ref.path);
    return {
      id: `trigger:${def.name}`,
      name: def.name,
      ...def.description !== undefined && { description: def.description },
      definedAt,
      events: def.events.map((raw) => parseTriggerEvent(raw, integrations)),
      ...def.state !== undefined && { stateSchema: def.state },
      parseStatus: { ok: true }
    };
  });
}
function parseTriggerEvent(raw, integrations) {
  const colonIdx = raw.indexOf(":");
  if (colonIdx === -1)
    return { name: raw };
  const alias = raw.slice(0, colonIdx);
  const eventName = raw.slice(colonIdx + 1);
  if (integrations[alias])
    return { name: eventName, integrationAlias: alias };
  return { name: raw };
}
function parseTables(project) {
  return project.tables.map((ref) => {
    const def = ref.definition;
    const definedAt = getExportLocation({
      agentRoot: project.path,
      relativePath: ref.path,
      exportName: ref.export
    }) ?? fallbackLocation(ref.path);
    return {
      id: `table:${def.name}`,
      name: def.name,
      ...def.description !== undefined && { description: def.description },
      definedAt,
      schema: def.schema,
      ...def.keyColumn !== undefined && { keyColumn: def.keyColumn },
      factor: def.factor,
      ...def.tags !== undefined && { tags: def.tags },
      parseStatus: { ok: true }
    };
  });
}
function parseKnowledge(project) {
  return project.knowledge.map((ref) => {
    const def = ref.definition;
    const definedAt = getExportLocation({
      agentRoot: project.path,
      relativePath: ref.path,
      exportName: ref.export
    }) ?? fallbackLocation(ref.path);
    return {
      id: `knowledge:${def.name}`,
      name: def.name,
      ...def.description !== undefined && { description: def.description },
      definedAt,
      sources: parseKnowledgeSources(def.sources),
      parseStatus: { ok: true }
    };
  });
}
function parseKnowledgeSources(sources) {
  return sources.map((source) => {
    const ds = source;
    let config = {};
    try {
      if (typeof ds.getConfig === "function") {
        config = ds.getConfig();
      }
    } catch {}
    return {
      id: ds.id,
      type: ds.type,
      config
    };
  });
}
function parseWorkflows(project) {
  return project.workflows.filter((ref) => !isBuiltInPrimitive2(ref)).map((ref) => {
    const def = ref.definition;
    const definedAt = getExportLocation({
      agentRoot: project.path,
      relativePath: ref.path,
      exportName: ref.export
    }) ?? fallbackLocation(ref.path);
    return {
      id: `workflow:${def.name}`,
      name: def.name,
      ...def.description !== undefined && { description: def.description },
      definedAt,
      ...def.input !== undefined && { inputSchema: def.input },
      ...def.output !== undefined && { outputSchema: def.output },
      ...def.state !== undefined && { stateSchema: def.state },
      ...def.schedule !== undefined && { schedule: def.schedule },
      timeout: def.timeout,
      steps: parseWorkflowSteps({
        agentRoot: project.path,
        relativePath: ref.path,
        exportName: ref.export,
        workflowId: `workflow:${def.name}`
      }),
      parseStatus: { ok: true }
    };
  });
}
function parseConversations(project, integrations, componentResolution) {
  return project.conversations.map((ref) => {
    const def = ref.definition;
    const definedAt = getExportLocation({
      agentRoot: project.path,
      relativePath: ref.path,
      exportName: ref.export
    }) ?? fallbackLocation(ref.path);
    const componentRefs = extractComponentRefs({
      agentRoot: project.path,
      relativePath: ref.path,
      resolution: componentResolution
    });
    const astProps = extractConversationAstProps({
      agentRoot: project.path,
      relativePath: ref.path
    });
    const channelStrings = Array.isArray(def.channel) ? def.channel : [def.channel];
    const channels = channelStrings.map((s) => parseChannelBinding(s, integrations));
    return {
      id: `conversation:${pathToId(ref.path)}`,
      channels,
      ...def.description !== undefined && { description: def.description },
      definedAt,
      ...astProps.stateSchema !== undefined && { stateSchema: astProps.stateSchema },
      ...def.events !== undefined && { events: def.events },
      hasLifecycle: def.hasLifecycle ?? false,
      ...astProps.lifecycle !== undefined && { lifecycle: astProps.lifecycle },
      ...componentRefs.length > 0 && { componentRefs },
      parseStatus: { ok: true }
    };
  });
}
function parseChannelBinding(raw, integrations) {
  if (raw === "*")
    return { name: "*" };
  const dotIdx = raw.indexOf(".");
  if (dotIdx === -1)
    return { name: raw };
  const alias = raw.slice(0, dotIdx);
  const name = raw.slice(dotIdx + 1);
  if (integrations[alias])
    return { name, integrationAlias: alias };
  return { name: raw };
}
function pathToId(relativePath) {
  return relativePath.replace(/\.(ts|tsx|js|jsx)$/, "").replace(/_/g, "__").replace(/[/\\]/g, "_");
}
function buildIntegrationMeta(project) {
  const compiled = parseCompiledBotIntegrations(project.path);
  const out = {};
  for (const parsed of project.integrations) {
    const compiledEntry = compiled.get(parsed.alias);
    const enabled = compiledEntry?.enabled ?? parsed.enabled ?? true;
    const hasConfiguration = compiledEntry?.hasConfiguration ?? false;
    const def = parsed.definition;
    const iconUrl = def?.iconUrl ?? def?.icon;
    out[parsed.alias] = {
      alias: parsed.alias,
      ref: `${parsed.ref.fullName}@${parsed.ref.version}`,
      ...typeof iconUrl === "string" && iconUrl.length > 0 && { iconUrl },
      enabled,
      hasConfiguration
    };
  }
  return out;
}
function buildDeclarativeUsesComponentEdges(conversations) {
  const edges = [];
  for (const conv of conversations) {
    for (const componentId of conv.componentRefs ?? []) {
      edges.push({
        id: `edge:${conv.id}->uses_component->${componentId}`,
        source: conv.id,
        sourceType: "conversation",
        target: componentId,
        targetType: "customComponent",
        type: "uses_component",
        via: "handler"
      });
    }
  }
  return edges;
}
function parseCustomComponents(project) {
  return project.customComponents.map((ref) => {
    const def = ref.definition;
    const definedAt = getExportLocation({
      agentRoot: project.path,
      relativePath: ref.path,
      exportName: ref.export
    }) ?? fallbackLocation(ref.path);
    return {
      id: `customComponent:${def.name}`,
      name: def.name,
      definedAt,
      hasLlmMetadata: false,
      parseStatus: { ok: true }
    };
  });
}

// src/server/handlers/agent-map/deployed-snapshot.ts
var DEPLOYED_AGENT_MAP_SNAPSHOT_SCHEMA_VERSION = 1;
var DEPLOYED_AGENT_MAP_SNAPSHOT_FILE_KEY = ".adk/agent-map-snapshot.json";
var DEPLOYED_AGENT_MAP_SNAPSHOT_TAGS = {
  type: "adk-agent-map-snapshot",
  schemaVersion: String(DEPLOYED_AGENT_MAP_SNAPSHOT_SCHEMA_VERSION)
};
var AGENT_MAP_SNAPSHOT_NOT_PUBLISHED_MESSAGE = "Agent Map metadata has not been published yet. Redeploy this ADK bot to publish Agent Map metadata.";
var SNAPSHOT_CACHE_TTL_MS = 15000;

class AgentMapSnapshotNotPublishedError extends Error {
  constructor(message = AGENT_MAP_SNAPSHOT_NOT_PUBLISHED_MESSAGE) {
    super(message);
    this.name = "AgentMapSnapshotNotPublishedError";
  }
}
function createDeployedAgentMapSnapshot(project, options = {}) {
  const generatedAt = options.generatedAt ?? new Date().toISOString();
  return {
    schemaVersion: DEPLOYED_AGENT_MAP_SNAPSHOT_SCHEMA_VERSION,
    generatedAt,
    snapshot: buildAgentSnapshot(project, {
      origin: { kind: "deployed-snapshot", generatedAt }
    })
  };
}
function serializeDeployedAgentMapSnapshot(artifact) {
  return `${JSON.stringify(artifact, null, 2)}
`;
}
function parseDeployedAgentMapSnapshot(content) {
  let value;
  try {
    value = JSON.parse(content);
  } catch {
    throw new Error("Deployed Agent Map metadata is not valid JSON.");
  }
  if (!isRecord2(value)) {
    throw new Error("Invalid deployed Agent Map metadata: expected an object.");
  }
  if (value.schemaVersion !== DEPLOYED_AGENT_MAP_SNAPSHOT_SCHEMA_VERSION) {
    throw new Error(`Invalid deployed Agent Map metadata: unsupported schema version.`);
  }
  if (typeof value.generatedAt !== "string" || value.generatedAt.length === 0) {
    throw new Error("Invalid deployed Agent Map metadata: missing generatedAt.");
  }
  if (!isAgentSnapshot(value.snapshot)) {
    throw new Error("Invalid deployed Agent Map metadata: invalid snapshot shape.");
  }
  const snapshot = value.snapshot;
  return {
    schemaVersion: DEPLOYED_AGENT_MAP_SNAPSHOT_SCHEMA_VERSION,
    generatedAt: value.generatedAt,
    snapshot: {
      ...snapshot,
      origin: { kind: "deployed-snapshot", generatedAt: value.generatedAt }
    }
  };
}
async function uploadDeployedAgentMapSnapshot(client, artifact) {
  await client.uploadFile({
    key: DEPLOYED_AGENT_MAP_SNAPSHOT_FILE_KEY,
    content: serializeDeployedAgentMapSnapshot(artifact),
    contentType: "application/json",
    tags: DEPLOYED_AGENT_MAP_SNAPSHOT_TAGS,
    index: false
  });
  return { key: DEPLOYED_AGENT_MAP_SNAPSHOT_FILE_KEY };
}

class ProdAgentMapSnapshotFileService {
  cache = new Map;
  async getArtifact(target) {
    const cacheKey = this.getCacheKey(target);
    const cached = this.cache.get(cacheKey);
    if (cached && Date.now() - cached.fetchedAt < SNAPSHOT_CACHE_TTL_MS) {
      return cached.artifact;
    }
    const client = this.makeClient(target);
    const file = await this.findSnapshotFile(client);
    if (!file.url) {
      throw new Error("Deployed Agent Map metadata file does not have a download URL.");
    }
    const response = await fetch(file.url);
    if (!response.ok) {
      throw new Error(`Failed to download deployed Agent Map metadata: ${response.status} ${response.statusText}`);
    }
    const artifact = parseDeployedAgentMapSnapshot(await response.text());
    this.cache.set(cacheKey, { fetchedAt: Date.now(), artifact });
    return artifact;
  }
  clear(target) {
    if (!target) {
      this.cache.clear();
      return;
    }
    this.cache.delete(this.getCacheKey(target));
  }
  async findSnapshotFile(client) {
    try {
      const { file: file2 } = await client.getFile({ id: DEPLOYED_AGENT_MAP_SNAPSHOT_FILE_KEY });
      return file2;
    } catch (err) {
      if (!isFileLookupFallbackError(err)) {
        throw err;
      }
    }
    const { files } = await client.listFiles({ tags: { ...DEPLOYED_AGENT_MAP_SNAPSHOT_TAGS } });
    const file = files.find((candidate) => candidate.key === DEPLOYED_AGENT_MAP_SNAPSHOT_FILE_KEY) ?? files[0];
    if (!file) {
      throw new AgentMapSnapshotNotPublishedError;
    }
    return file;
  }
  makeClient(target) {
    return new Uk({
      token: target.token,
      apiUrl: target.apiUrl,
      workspaceId: target.workspaceId,
      botId: target.botId,
      headers: { "x-multiple-integrations": "true" }
    });
  }
  getCacheKey(target) {
    const tokenHash = createHash("sha256").update(target.token).digest("hex");
    return `${target.apiUrl}:${target.workspaceId}:${target.botId}:${tokenHash}`;
  }
}

class ProdAgentMapSnapshotService {
  fileService;
  constructor(fileService = new ProdAgentMapSnapshotFileService) {
    this.fileService = fileService;
  }
  async getSnapshot(target) {
    const artifact = await this.fileService.getArtifact(target);
    return artifact.snapshot;
  }
}
var prodAgentMapSnapshotService = new ProdAgentMapSnapshotService;
function isAgentSnapshot(value) {
  if (!isRecord2(value) || !isRecord2(value.agent) || !isRecord2(value.integrations))
    return false;
  return [
    value.actions,
    value.tools,
    value.workflows,
    value.conversations,
    value.triggers,
    value.tables,
    value.knowledge,
    value.customComponents,
    value.aiAgents,
    value.integrationActions,
    value.edges
  ].every(Array.isArray);
}
function isRecord2(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
function isFileLookupFallbackError(err) {
  if (!isRecord2(err))
    return false;
  const type = err.type;
  if (type === "ResourceNotFound" || type === "InvalidIdentifier" || type === "InvalidPayload") {
    return true;
  }
  const status = err.status ?? err.statusCode ?? err.code ?? (isRecord2(err.response) ? err.response.status : undefined);
  return status === 404 || status === 400;
}

export { buildAgentSnapshot, AgentMapSnapshotNotPublishedError, createDeployedAgentMapSnapshot, uploadDeployedAgentMapSnapshot, prodAgentMapSnapshotService };