UNPKG

@botpress/adk-cli

Version:

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

314 lines (309 loc) 11.8 kB
// @bun import { CLI_VERSION } from "./chunk-nxy2ya5r.js"; import { AdkError } from "./chunk-p0hjqn4r.js"; import { __require } from "./chunk-dhs2bg35.js"; // src/utils/agent0-capabilities.ts import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs"; import { basename, dirname, extname, join, normalize, sep } from "path"; import { fileURLToPath } from "url"; // src/utils/embedded-assets.ts var _assets; try { const mod = await import("./chunk-nt9nzenw.js"); _assets = Array.isArray(mod.embeddedAssets) ? mod.embeddedAssets : []; } catch (e) { if (e?.code !== "MODULE_NOT_FOUND" && e?.name !== "ResolveError" && e?.name !== "ResolveMessage") throw e; _assets = []; } function getEmbeddedAssets() { return _assets ?? []; } function getEmbeddedAsset(path) { return getEmbeddedAssets().find((asset) => asset.path === path); } function hasEmbeddedAssets() { return getEmbeddedAssets().length > 0; } // src/utils/agent0-capabilities.ts var AGENT0_PROJECT_DIR = ".agent0"; var AGENT0_PROJECT_CAPABILITIES_DIR = "capabilities"; var AGENT0_PROJECT_SKILLS_DIR = "skills"; var AGENT0_PROJECT_PLAYBOOKS_DIR = "playbooks"; var AGENT0_PROJECT_CAPABILITIES_MANIFEST = "manifest.json"; var EMBEDDED_CAPABILITIES_PREFIX = "/agent0-capabilities"; var EMBEDDED_SKILLS_PREFIX = `${EMBEDDED_CAPABILITIES_PREFIX}/skills/`; var EMBEDDED_PLAYBOOKS_PREFIX = `${EMBEDDED_CAPABILITIES_PREFIX}/playbooks/`; var EMBEDDED_COMMANDS_PREFIX = `${EMBEDDED_CAPABILITIES_PREFIX}/commands/`; function getCurrentAgent0CapabilityBundleVersion() { return CLI_VERSION; } function getAgent0ProjectCapabilitiesRoot(projectPath) { return join(projectPath, AGENT0_PROJECT_DIR, AGENT0_PROJECT_CAPABILITIES_DIR); } function getAgent0ProjectCapabilitiesManifestPath(projectPath) { return join(getAgent0ProjectCapabilitiesRoot(projectPath), AGENT0_PROJECT_CAPABILITIES_MANIFEST); } function readAgent0CapabilitiesManifest(projectPath) { const manifestPath = getAgent0ProjectCapabilitiesManifestPath(projectPath); if (!existsSync(manifestPath)) return; try { const value = JSON.parse(readFileSync(manifestPath, "utf8")); if (value.schemaVersion !== 1 || typeof value.capabilityBundleVersion !== "string") return; return { schemaVersion: 1, adkVersion: typeof value.adkVersion === "string" ? value.adkVersion : value.capabilityBundleVersion, capabilityBundleVersion: value.capabilityBundleVersion, generatedAt: typeof value.generatedAt === "string" ? value.generatedAt : "", capabilitiesRoot: typeof value.capabilitiesRoot === "string" ? value.capabilitiesRoot : "", skills: Array.isArray(value.skills) ? value.skills.filter((item) => typeof item === "string") : [], playbooks: Array.isArray(value.playbooks) ? value.playbooks.filter((item) => typeof item === "string") : [] }; } catch { return; } } function checkAgent0CapabilitiesStatus(projectPath) { const currentVersion = getCurrentAgent0CapabilityBundleVersion(); const manifestPath = getAgent0ProjectCapabilitiesManifestPath(projectPath); const manifest = readAgent0CapabilitiesManifest(projectPath); if (!manifest) { return { state: "missing", currentVersion, manifestPath }; } if (manifest.capabilityBundleVersion !== currentVersion) { return { state: "stale", currentVersion, installedVersion: manifest.capabilityBundleVersion, manifestPath }; } if (!manifestHasRequiredCapabilityFiles(projectPath, manifest)) { return { state: "stale", currentVersion, installedVersion: manifest.capabilityBundleVersion, manifestPath }; } return { state: "current", currentVersion, installedVersion: manifest.capabilityBundleVersion, manifestPath }; } function manifestHasRequiredCapabilityFiles(projectPath, manifest) { if (manifest.skills.length === 0 || manifest.playbooks.length === 0) return false; const capabilitiesRoot = getAgent0ProjectCapabilitiesRoot(projectPath); return manifest.skills.every((skill) => isFile(join(capabilitiesRoot, AGENT0_PROJECT_SKILLS_DIR, skill, "SKILL.md"))) && manifest.playbooks.every((playbook) => isFile(join(capabilitiesRoot, AGENT0_PROJECT_PLAYBOOKS_DIR, playbook))); } function isFile(path) { return existsSync(path) && statSync(path).isFile(); } async function installAgent0Capabilities(projectPath) { const capabilitiesRoot = getAgent0ProjectCapabilitiesRoot(projectPath); const manifestPath = getAgent0ProjectCapabilitiesManifestPath(projectPath); const previousManifest = readAgent0CapabilitiesManifest(projectPath); const status = checkAgent0CapabilitiesStatus(projectPath); const source = resolveCapabilitySource(); mkdirSync(capabilitiesRoot, { recursive: true }); cleanupManagedCapabilities(projectPath, previousManifest, source); await copyCapabilitiesToProject(capabilitiesRoot, source); const manifest = { schemaVersion: 1, adkVersion: getCurrentAgent0CapabilityBundleVersion(), capabilityBundleVersion: getCurrentAgent0CapabilityBundleVersion(), generatedAt: new Date().toISOString(), capabilitiesRoot: join(AGENT0_PROJECT_DIR, AGENT0_PROJECT_CAPABILITIES_DIR), skills: source.skills, playbooks: source.playbooks }; writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + ` `); return { success: true, projectPath, capabilitiesRoot, manifestPath, source: source.kind, currentVersion: getCurrentAgent0CapabilityBundleVersion(), previousVersion: status.state === "missing" ? undefined : status.installedVersion ?? previousManifest?.capabilityBundleVersion, wasCurrent: status.state === "current", skills: { installed: source.skills.length, names: source.skills }, playbooks: { installed: source.playbooks.length, files: source.playbooks } }; } function resolveCapabilitySource() { const embedded = resolveEmbeddedCapabilitySource(); if (embedded) return embedded; const skillsRoot = resolveBundledSkillsRoot(); const playbooksRoot = resolveBundledPlaybooksRoot(); if (!skillsRoot || !playbooksRoot) { throw new AdkError({ code: "AGENT0_BUNDLE_MISSING", message: "Agent(0) capability bundle is missing from this ADK installation." }); } return { kind: "filesystem", skillsRoot, playbooksRoot, skills: listSkillNames(skillsRoot), playbooks: listMarkdownFiles(playbooksRoot) }; } function resolveBundledSkillsRoot() { const baseDir = moduleDir(); return firstExistingDirectory([ join(baseDir, "agent0-assets", "skills"), join(baseDir, "..", "agent0-assets", "skills"), join(baseDir, "..", "..", "agent0-assets", "skills"), join(baseDir, "..", "..", "..", "adk", "src", "agent0", "capabilities", "skills"), join(baseDir, "..", "..", "..", "adk", "dist", "agent0", "capabilities", "skills") ]); } function resolveBundledPlaybooksRoot() { const baseDir = moduleDir(); return firstExistingDirectory([ join(baseDir, "agent0-assets", "playbooks"), join(baseDir, "..", "agent0-assets", "playbooks"), join(baseDir, "..", "..", "agent0-assets", "playbooks"), join(baseDir, "..", "..", "..", "adk", "src", "agent0", "capabilities", "commands"), join(baseDir, "..", "..", "..", "adk", "dist", "agent0", "capabilities", "commands") ]); } function resolveEmbeddedCapabilitySource() { const files = []; const skills = new Set; const playbooks = new Set; for (const asset of getAvailableEmbeddedAssets()) { const normalizedPath = asset.path.replace(/\\/g, "/"); const skillRelative = stripPrefix(normalizedPath, EMBEDDED_SKILLS_PREFIX); if (skillRelative) { const skillName = firstPathSegment(skillRelative); if (!skillName) continue; skills.add(skillName); files.push({ asset, relativePath: join(AGENT0_PROJECT_SKILLS_DIR, skillRelative) }); continue; } const playbookRelative = stripPrefix(normalizedPath, EMBEDDED_PLAYBOOKS_PREFIX) ?? stripPrefix(normalizedPath, EMBEDDED_COMMANDS_PREFIX); if (playbookRelative && extname(playbookRelative) === ".md") { playbooks.add(basename(playbookRelative)); files.push({ asset, relativePath: join(AGENT0_PROJECT_PLAYBOOKS_DIR, playbookRelative) }); } } if (skills.size === 0 || playbooks.size === 0) return; return { kind: "embedded", files, skills: [...skills].toSorted(), playbooks: [...playbooks].toSorted() }; } function getAvailableEmbeddedAssets() { const getEmbeddedAssets2 = getEmbeddedAssets; if (typeof getEmbeddedAssets2 !== "function") return []; const assets = getEmbeddedAssets2(); return Array.isArray(assets) ? assets : []; } async function copyCapabilitiesToProject(capabilitiesRoot, source) { if (source.kind === "embedded") { for (const file of source.files) { const destination = safeJoin(capabilitiesRoot, file.relativePath); mkdirSync(dirname(destination), { recursive: true }); const bytes = Buffer.from(await Bun.file(file.asset.file).arrayBuffer()); writeFileSync(destination, bytes); } return; } const skillsRoot = join(capabilitiesRoot, AGENT0_PROJECT_SKILLS_DIR); const playbooksRoot = join(capabilitiesRoot, AGENT0_PROJECT_PLAYBOOKS_DIR); mkdirSync(playbooksRoot, { recursive: true }); for (const skill of source.skills) { copyTree(join(source.skillsRoot, skill), join(skillsRoot, skill)); } for (const playbook of source.playbooks) { copyFileSync(join(source.playbooksRoot, playbook), join(playbooksRoot, playbook)); } } function cleanupManagedCapabilities(projectPath, _previousManifest, _source) { const capabilitiesRoot = getAgent0ProjectCapabilitiesRoot(projectPath); const skillsRoot = join(capabilitiesRoot, AGENT0_PROJECT_SKILLS_DIR); const playbooksRoot = join(capabilitiesRoot, AGENT0_PROJECT_PLAYBOOKS_DIR); rmSync(skillsRoot, { recursive: true, force: true }); rmSync(playbooksRoot, { recursive: true, force: true }); } function copyTree(source, destination) { const stats = statSync(source); if (stats.isDirectory()) { mkdirSync(destination, { recursive: true }); for (const entry of readdirSync(source)) { copyTree(join(source, entry), join(destination, entry)); } return; } mkdirSync(dirname(destination), { recursive: true }); copyFileSync(source, destination); } function listSkillNames(skillsRoot) { return readdirSync(skillsRoot).toSorted().filter((entry) => { const skillDir = join(skillsRoot, entry); return statSync(skillDir).isDirectory() && existsSync(join(skillDir, "SKILL.md")); }); } function listMarkdownFiles(root) { return readdirSync(root).toSorted().filter((entry) => extname(entry) === ".md" && statSync(join(root, entry)).isFile()); } function firstExistingDirectory(paths) { return paths.find((path) => existsSync(path) && statSync(path).isDirectory()); } function stripPrefix(value, prefix) { return value.startsWith(prefix) ? value.slice(prefix.length) : undefined; } function firstPathSegment(value) { return value.split("/").find(Boolean); } function safeJoin(root, relativePath) { const destination = normalize(join(root, relativePath)); const normalizedRoot = normalize(root); if (destination !== normalizedRoot && !destination.startsWith(normalizedRoot + sep)) { throw new AdkError({ code: "AGENT0_PATH_ESCAPE", message: `Refusing to write Agent(0) capability outside ${root}: ${relativePath}` }); } return destination; } function moduleDir() { return dirname(fileURLToPath(import.meta.url)); } export { getEmbeddedAssets, getEmbeddedAsset, hasEmbeddedAssets, readAgent0CapabilitiesManifest, checkAgent0CapabilitiesStatus, installAgent0Capabilities };