feat(managed-agent): add directory project workflow

This commit is contained in:
chenanran555
2026-08-31 15:55:10 +08:00
parent 9469556671
commit e53daf05eb
13 changed files with 1017 additions and 778 deletions
+22 -14
View File
@@ -139,14 +139,18 @@ import {
managedAgentPlan,
managedAgentApply,
managedAgentDestroy,
managedAgentWorkbench,
managedAgentPlayground,
managedAgentVersionEnable,
managedAgentVersionDisable,
managedAgentVersionStatus,
managedAgentVersionList,
managedAgentVersionPreview,
managedAgentVersionRestore,
managedAgentProjectInit,
managedAgentProjectValidate,
managedAgentProjectBuild,
managedAgentProjectPublish,
managedAgentProjectWorkbench,
managedAgentProjectVersionEnable,
managedAgentProjectVersionDisable,
managedAgentProjectVersionStatus,
managedAgentProjectVersionList,
managedAgentProjectVersionPreview,
managedAgentProjectVersionRestore,
managedAgentStateList,
managedAgentStateShow,
managedAgentStateRm,
@@ -308,14 +312,18 @@ export const commands: Record<string, AnyCommand> = {
"managed-agent plan": managedAgentPlan,
"managed-agent apply": managedAgentApply,
"managed-agent destroy": managedAgentDestroy,
"managed-agent workbench": managedAgentWorkbench,
"managed-agent playground": managedAgentPlayground,
"managed-agent version enable": managedAgentVersionEnable,
"managed-agent version disable": managedAgentVersionDisable,
"managed-agent version status": managedAgentVersionStatus,
"managed-agent version list": managedAgentVersionList,
"managed-agent version preview": managedAgentVersionPreview,
"managed-agent version restore": managedAgentVersionRestore,
"managed-agent project init": managedAgentProjectInit,
"managed-agent project validate": managedAgentProjectValidate,
"managed-agent project build": managedAgentProjectBuild,
"managed-agent project publish": managedAgentProjectPublish,
"managed-agent project workbench": managedAgentProjectWorkbench,
"managed-agent project version enable": managedAgentProjectVersionEnable,
"managed-agent project version disable": managedAgentProjectVersionDisable,
"managed-agent project version status": managedAgentProjectVersionStatus,
"managed-agent project version list": managedAgentProjectVersionList,
"managed-agent project version preview": managedAgentProjectVersionPreview,
"managed-agent project version restore": managedAgentProjectVersionRestore,
"managed-agent state list": managedAgentStateList,
"managed-agent state show": managedAgentStateShow,
"managed-agent state rm": managedAgentStateRm,
+1 -1
View File
@@ -40,7 +40,7 @@
"check": "vp check"
},
"dependencies": {
"@openagentpack/project-versions": "0.4.0",
"@openagentpack/project-workspace": "0.4.0",
"@openagentpack/sdk": "0.4.0",
"bailian-cli-core": "workspace:*",
"bailian-cli-runtime": "workspace:*",
@@ -13,7 +13,8 @@ const PLAYGROUND_URL_PATTERN = /running at http:\/\/localhost:(\d+)/i;
export interface PlaygroundLaunchOptions {
port?: number;
open: boolean;
file: string;
file?: string;
project?: string;
agent?: string;
surface: "preview" | "workbench";
client: Client;
@@ -51,8 +52,10 @@ export async function launchManagedAgentPlayground(
if (!Number.isInteger(port) || port <= 0 || port > 65_535) {
throw new BailianError(`Invalid --port '${port}'.`, ExitCode.USAGE);
}
const configPath = resolve(options.file);
const projectId = createHash("sha256").update(configPath).digest("hex").slice(0, 16);
const sourcePath = resolve(
options.surface === "workbench" ? (options.project ?? ".") : (options.file ?? "agents.yaml"),
);
const projectId = createHash("sha256").update(sourcePath).digest("hex").slice(0, 16);
const launcher = resolveLauncher();
const existing = await probeExistingPlayground(port);
if (existing) {
@@ -74,7 +77,7 @@ export async function launchManagedAgentPlayground(
}
}
const environment = buildPlaygroundEnvironment(options, port, configPath);
const environment = buildPlaygroundEnvironment(options, port, sourcePath);
if (launcher.fetched) {
emitBare(`Fetching ${PLAYGROUND_PACKAGE} (first run may take a moment)...`);
}
@@ -214,15 +217,21 @@ function findLocalPlaygroundBin(startDirectory: string): string | undefined {
function buildPlaygroundEnvironment(
options: PlaygroundLaunchOptions,
port: number,
configPath: string,
sourcePath: string,
): NodeJS.ProcessEnv {
const credential = options.client.exportApiCredential();
const environment: NodeJS.ProcessEnv = {
...process.env,
PORT: String(port),
AGENTS_CONFIG_PATH: configPath,
AGENTS_PLAYGROUND_TOKEN: randomBytes(32).toString("hex"),
};
if (options.surface === "workbench") {
delete environment.AGENTS_CONFIG_PATH;
environment.AGENTS_PROJECT_ROOT = sourcePath;
} else {
delete environment.AGENTS_PROJECT_ROOT;
environment.AGENTS_CONFIG_PATH = sourcePath;
}
if (credential) environment.DASHSCOPE_API_KEY = credential.token;
const baseUrl = options.client.baseUrl.replace(/\/+$/, "");
environment.BAILIAN_BASE_URL = baseUrl.endsWith("/api/v1/agentstudio")
@@ -16,13 +16,6 @@ import {
import { withStdoutProtected } from "./_engine/console-capture.ts";
import { withAgentErrors } from "./_engine/errors.ts";
import { renderAgentFeedback } from "./_engine/feedback.ts";
import {
commitPreparedProjectVersion,
type PreparedProjectVersion,
prepareProjectVersion,
readProjectVersionSource,
releasePreparedProjectVersion,
} from "@openagentpack/project-versions";
const APPLY_FLAGS = {
file: {
@@ -105,9 +98,7 @@ export default defineCommand({
return;
}
const versionSource = await readProjectVersionSource(file);
const { planned, runtime } = await withAgentErrors(() =>
const planned = await withAgentErrors(() =>
withStdoutProtected(async () => {
const runtime = await buildAgentRuntime(ctx, file);
assertProviderConfigured(runtime, flags.provider);
@@ -117,7 +108,7 @@ export default defineCommand({
quiet: true,
onFeedback: renderAgentFeedback,
});
return { planned, runtime };
return planned;
}),
);
@@ -137,13 +128,6 @@ export default defineCommand({
const actionable = plan.actions.filter((action) => action.action !== "no-op");
if (actionable.length === 0) {
if (!flags.refreshOnly) {
const preparedVersion = await prepareProjectVersion(
runtime.configPath,
versionSource.source,
);
await commitSuccessfulApplyVersion(preparedVersion, format);
}
if (format === "json")
emitResult({ succeeded: 0, failed: 0, skipped: 0, results: [] }, format);
else emitBare("No changes. Infrastructure is up-to-date.");
@@ -184,50 +168,31 @@ export default defineCommand({
);
}
const preparedVersion = await prepareProjectVersion(runtime.configPath, versionSource.source);
let versionCommitted = false;
try {
const result = await withAgentErrors(() =>
withStdoutProtected(() =>
executePlannedProject(planned, {
onFeedback: renderAgentFeedback,
policy: "force",
concurrency: flags.concurrency,
}),
),
const result = await withAgentErrors(() =>
withStdoutProtected(() =>
executePlannedProject(planned, {
onFeedback: renderAgentFeedback,
policy: "force",
concurrency: flags.concurrency,
}),
),
);
const succeeded = result.results.filter((entry) => entry.status === "success").length;
const failed = result.results.filter((entry) => entry.status === "failed").length;
const skipped = result.results.filter((entry) => entry.status === "skipped").length;
if (format === "json") {
emitResult({ succeeded, failed, skipped, results: result.results }, format);
} else {
emitBare(`\nApply finished: ${succeeded} succeeded, ${failed} failed, ${skipped} skipped.`);
}
if (failed > 0 || skipped > 0) {
throw new BailianError(
failed > 0 ? "Apply failed." : "Apply incomplete: one or more actions were skipped.",
ExitCode.GENERAL,
);
const succeeded = result.results.filter((entry) => entry.status === "success").length;
const failed = result.results.filter((entry) => entry.status === "failed").length;
const skipped = result.results.filter((entry) => entry.status === "skipped").length;
if (format === "json") {
emitResult({ succeeded, failed, skipped, results: result.results }, format);
} else {
emitBare(`\nApply finished: ${succeeded} succeeded, ${failed} failed, ${skipped} skipped.`);
}
if (failed > 0 || skipped > 0) {
throw new BailianError(
failed > 0 ? "Apply failed." : "Apply incomplete: one or more actions were skipped.",
ExitCode.GENERAL,
);
}
await commitSuccessfulApplyVersion(preparedVersion, format);
versionCommitted = true;
} finally {
if (!versionCommitted) await releasePreparedProjectVersion(preparedVersion);
}
},
});
async function commitSuccessfulApplyVersion(
prepared: PreparedProjectVersion | null,
format: "text" | "json",
): Promise<void> {
if (!prepared) return;
const version = await commitPreparedProjectVersion(prepared);
if (version && format !== "json") {
emitBare(`Created local version ${version.short_version} (${version.message}).`);
}
}
@@ -0,0 +1,443 @@
import {
BailianError,
defineCommand,
detectOutputFormat,
ExitCode,
type FlagsDef,
} from "bailian-cli-core";
import { confirmDangerousAction, emitBare, emitResult } from "bailian-cli-runtime";
import {
commitProjectBuild,
createDirectoryWorkspaceVersionService,
executeProjectPublish,
initializeDirectoryProject,
planProjectPublish,
previewProjectBuild,
validateDirectoryProject,
} from "@openagentpack/project-workspace";
import { CREDENTIALS_NOTE, resolveAgentProjectConfig } from "./_engine/config-loader.ts";
import { withStdoutProtected } from "./_engine/console-capture.ts";
import { withAgentErrors } from "./_engine/errors.ts";
import { renderAgentFeedback } from "./_engine/feedback.ts";
import { launchManagedAgentPlayground } from "./_engine/playground-launcher.ts";
import { installSdkTransport } from "./_engine/transport.ts";
import { formatResourceLabel } from "./_engine/address-utils.ts";
const PROJECT_FLAG = {
project: {
type: "string",
valueHint: "<directory>",
description: {
"en-US": "Directory project root (default: current directory)",
"zh-CN": "目录项目根路径(默认:当前目录)",
},
},
} satisfies FlagsDef;
const JSON_FORMAT = "json" as const;
export const managedAgentProjectInit = defineCommand({
description: {
"en-US": "Create a directory project or convert the local agents.yaml",
"zh-CN": "创建目录项目,或转换当前 agents.yaml",
},
auth: "none",
usageArgs: "[--project <directory>] [--provider bailian]",
flags: {
...PROJECT_FLAG,
provider: {
type: "string",
valueHint: "<name>",
description: { "en-US": "Provider for a new project", "zh-CN": "新项目使用的 Provider" },
},
},
exampleArgs: ["", "--project ./my-agent", "--provider bailian"],
async run(ctx) {
if (ctx.settings.dryRun) {
emitResult(
{ would_initialize_project: ctx.flags.project ?? "." },
detectOutputFormat(ctx.settings.output),
);
return;
}
const result = await initializeDirectoryProject({
projectRoot: ctx.flags.project ?? ".",
provider: ctx.flags.provider ?? "bailian",
});
emitResult(result, detectOutputFormat(ctx.settings.output));
},
});
export const managedAgentProjectValidate = defineCommand({
description: { "en-US": "Validate a directory Agent project", "zh-CN": "校验目录式 Agent 项目" },
auth: "none",
usageArgs: "[--project <directory>]",
flags: PROJECT_FLAG,
exampleArgs: ["", "--project ./my-agent"],
async run(ctx) {
const result = await validateDirectoryProject(ctx.flags.project ?? ".");
const format = detectOutputFormat(ctx.settings.output);
if (format === JSON_FORMAT) emitResult(safeInspection(result), format);
else {
for (const diagnostic of [...result.diagnostics, ...result.warnings]) {
emitBare(`${diagnostic.severity}: ${diagnostic.code}: ${diagnostic.message}`);
}
if (!result.diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
emitBare(`Project is valid (${result.project_revision.slice(0, 12)}).`);
}
}
if (result.diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
throw new BailianError("Directory project validation failed.", ExitCode.GENERAL);
}
},
});
export const managedAgentProjectBuild = defineCommand({
description: {
"en-US": "Organize directory source and generate the immutable Publish Build",
"zh-CN": "整理目录源文件并生成不可变的发布 Build",
},
auth: "none",
usageArgs: "[--project <directory>] [--yes]",
flags: {
...PROJECT_FLAG,
yes: {
type: "switch",
description: { "en-US": "Write the previewed Build", "zh-CN": "写入已预览的 Build" },
},
},
exampleArgs: ["--dry-run", "--yes", "--project ./my-agent --yes"],
async run(ctx) {
const root = ctx.flags.project ?? ".";
const preview = await previewProjectBuild(root);
const format = detectOutputFormat(ctx.settings.output);
if (ctx.settings.dryRun) {
emitResult(safeInspection(preview), format);
return;
}
if (!preview.can_build)
throw new BailianError("Directory project is invalid and cannot be built.", ExitCode.GENERAL);
if (!ctx.flags.yes) {
throw new BailianError(
"Build requires confirmation before it organizes shared skills and writes generated YAML.",
ExitCode.USAGE,
"Preview with --dry-run, then rerun with --yes.",
);
}
const built = await commitProjectBuild({
projectRoot: root,
baseRevision: preview.project_revision,
});
emitResult(
{ manifest: built.manifest, organization_moves: preview.organization_moves },
format,
);
},
});
export const managedAgentProjectPublish = defineCommand({
description: {
"en-US": "Publish the current directory-project Build and record a version",
"zh-CN": "发布当前目录项目 Build 并记录版本",
},
auth: "apiKey",
usageArgs:
"[--project <directory>] [--provider <name>] [--yes] [--no-refresh] [--concurrency <n>]",
flags: {
...PROJECT_FLAG,
provider: {
type: "string",
valueHint: "<name>",
description: { "en-US": "Target provider", "zh-CN": "目标 Provider" },
},
yes: {
type: "switch",
description: { "en-US": "Confirm remote Publish", "zh-CN": "确认执行远端发布" },
},
noRefresh: {
type: "switch",
description: {
"en-US": "Skip remote refresh before planning",
"zh-CN": "规划前跳过远端刷新",
},
},
concurrency: {
type: "number",
valueHint: "<n>",
description: {
"en-US": "Maximum parallel resource operations",
"zh-CN": "最大并行资源操作数",
},
},
},
exampleArgs: ["--yes", "--project ./my-agent --yes", "--provider bailian --yes"],
notes: CREDENTIALS_NOTE,
async run(ctx) {
installSdkTransport(ctx);
const root = ctx.flags.project ?? ".";
const resolveBuild = (buildPath: string) => resolveAgentProjectConfig(ctx, buildPath);
const planned = await withAgentErrors(() =>
withStdoutProtected(() =>
planProjectPublish(root, {
provider: ctx.flags.provider,
refresh: !ctx.flags.noRefresh,
quiet: true,
onFeedback: renderAgentFeedback,
resolveBuild,
}),
),
);
const actions = planned.planned.plan.actions.filter((action) => action.action !== "no-op");
if (ctx.settings.dryRun) {
emitResult(
{
project_revision: planned.project_revision,
build_manifest: planned.build_manifest,
plan: planned.planned.plan,
},
detectOutputFormat(ctx.settings.output),
);
return;
}
for (const action of actions) {
const marker = action.action === "create" ? "+" : action.action === "update" ? "~" : "-";
emitBare(`${marker} ${formatResourceLabel(action.address)}`);
}
if (!ctx.flags.yes) {
throw new BailianError(
`Refusing to Publish ${actions.length} remote change(s) without confirmation.`,
ExitCode.USAGE,
"Review with project publish --dry-run, then rerun with --yes.",
);
}
const result = await withAgentErrors(() =>
withStdoutProtected(() =>
executeProjectPublish({
projectRoot: planned.project_root,
expectedProjectRevision: planned.project_revision,
expectedYamlHash: planned.build_manifest.yaml_hash,
provider: ctx.flags.provider,
refresh: !ctx.flags.noRefresh,
concurrency: ctx.flags.concurrency,
policy: "force",
onFeedback: renderAgentFeedback,
resolveBuild,
}),
),
);
emitResult(result, detectOutputFormat(ctx.settings.output));
},
});
export const managedAgentProjectWorkbench = defineCommand({
description: {
"en-US": "Launch the directory project Workbench",
"zh-CN": "启动目录项目 Workbench",
},
auth: "apiKey",
usageArgs: "[--project <directory>] [--port <n>] [--no-open]",
flags: {
...PROJECT_FLAG,
port: {
type: "number",
valueHint: "<n>",
description: { "en-US": "Local port (default: 4848)", "zh-CN": "本地端口(默认:4848)" },
},
noOpen: {
type: "switch",
description: { "en-US": "Do not open a browser", "zh-CN": "不自动打开浏览器" },
},
},
exampleArgs: ["", "--project ./my-agent --no-open"],
notes: CREDENTIALS_NOTE,
async run(ctx) {
const root = ctx.flags.project ?? ".";
if (ctx.settings.dryRun) {
emitResult(
{ would_launch: "workbench", project_root: root, port: ctx.flags.port ?? 4848 },
detectOutputFormat(ctx.settings.output),
);
return;
}
await launchManagedAgentPlayground({
project: root,
port: ctx.flags.port ?? 4848,
open: !ctx.flags.noOpen,
surface: "workbench",
client: ctx.client,
settings: ctx.settings,
});
},
});
export const managedAgentProjectVersionEnable = versionToggleCommand(true);
export const managedAgentProjectVersionDisable = versionToggleCommand(false);
function versionToggleCommand(enabled: boolean) {
return defineCommand({
description: enabled
? { "en-US": "Enable directory project versions", "zh-CN": "启用目录项目版本管理" }
: { "en-US": "Disable directory project versions", "zh-CN": "关闭目录项目版本管理" },
auth: "none",
usageArgs: "[--project <directory>]",
flags: PROJECT_FLAG,
exampleArgs: ["", "--project ./my-agent"],
async run(ctx) {
const service = createDirectoryWorkspaceVersionService(ctx.flags.project ?? ".");
if (ctx.settings.dryRun) {
emitResult(
{ would_set_enabled: enabled, status: await service.status() },
detectOutputFormat(ctx.settings.output),
);
return;
}
const result = enabled
? await service.enable("Enable project versions")
: await service.disable();
emitResult(result, detectOutputFormat(ctx.settings.output));
},
});
}
export const managedAgentProjectVersionStatus = defineCommand({
description: {
"en-US": "Show directory project version status",
"zh-CN": "显示目录项目版本状态",
},
auth: "none",
usageArgs: "[--project <directory>]",
flags: PROJECT_FLAG,
exampleArgs: ["", "--project ./my-agent --output json"],
async run(ctx) {
emitResult(
await createDirectoryWorkspaceVersionService(ctx.flags.project ?? ".").status(),
detectOutputFormat(ctx.settings.output),
);
},
});
export const managedAgentProjectVersionList = defineCommand({
description: { "en-US": "List directory project versions", "zh-CN": "列出目录项目版本" },
auth: "none",
usageArgs: "[--project <directory>] [--limit <n>] [--cursor <cursor>]",
flags: {
...PROJECT_FLAG,
limit: {
type: "number",
valueHint: "<n>",
description: { "en-US": "Maximum versions to return", "zh-CN": "最多返回的版本数" },
},
cursor: {
type: "string",
valueHint: "<cursor>",
description: { "en-US": "Pagination cursor", "zh-CN": "分页游标" },
},
},
exampleArgs: ["", "--limit 20 --output json"],
async run(ctx) {
emitResult(
await createDirectoryWorkspaceVersionService(ctx.flags.project ?? ".").listVersions({
limit: ctx.flags.limit,
cursor: ctx.flags.cursor,
}),
detectOutputFormat(ctx.settings.output),
);
},
});
const VERSION_ID_FLAG = {
versionId: {
type: "string",
valueHint: "<full-version>",
required: true,
description: { "en-US": "Full project version ID", "zh-CN": "完整的项目版本 ID" },
},
} satisfies FlagsDef;
export const managedAgentProjectVersionPreview = defineCommand({
description: { "en-US": "Preview a directory project version", "zh-CN": "预览目录项目历史版本" },
auth: "none",
usageArgs: "--version-id <full-version> [--project <directory>]",
flags: { ...PROJECT_FLAG, ...VERSION_ID_FLAG },
exampleArgs: ["--version-id <full-version>"],
async run(ctx) {
emitResult(
await createDirectoryWorkspaceVersionService(ctx.flags.project ?? ".").previewVersion(
ctx.flags.versionId,
),
detectOutputFormat(ctx.settings.output),
);
},
});
export const managedAgentProjectVersionRestore = defineCommand({
description: {
"en-US": "Restore a version to the project working directory",
"zh-CN": "将历史版本恢复到项目工作目录",
},
auth: "none",
usageArgs: "--version-id <full-version> [--project <directory>] [--yes]",
flags: {
...PROJECT_FLAG,
...VERSION_ID_FLAG,
yes: {
type: "switch",
description: {
"en-US": "Restore without interactive confirmation",
"zh-CN": "无需交互确认直接恢复",
},
},
},
exampleArgs: ["--version-id <full-version>", "--version-id <full-version> --yes"],
async run(ctx) {
const service = createDirectoryWorkspaceVersionService(ctx.flags.project ?? ".");
const preview = await service.previewVersion(ctx.flags.versionId);
if (!preview.can_restore)
throw new BailianError(
preview.blockers[0] ?? preview.diagnostics[0]?.message ?? "Version cannot be restored.",
ExitCode.GENERAL,
);
if (ctx.settings.dryRun) {
emitResult(
{ would_restore: ctx.flags.versionId, preview },
detectOutputFormat(ctx.settings.output),
);
return;
}
await confirmDangerousAction(
"Restore the full directory source? Version history and remote State will not move.",
ctx.flags.yes,
);
const restored = await service.restoreVersion(ctx.flags.versionId, {
headVersion: preview.base_head_version,
projectRevision: preview.base_project_revision,
});
emitResult(restored, detectOutputFormat(ctx.settings.output));
},
});
function safeInspection(result: {
project_root: string;
project_revision: string;
source_manifest_hash: string;
yaml_hash: string;
diagnostics: unknown[];
warnings: unknown[];
organization_moves: unknown[];
canonical_yaml: string;
before_yaml?: string;
can_build?: boolean;
}) {
return {
project_root: result.project_root,
project_revision: result.project_revision,
source_manifest_hash: result.source_manifest_hash,
yaml_hash: result.yaml_hash,
diagnostics: result.diagnostics,
warnings: result.warnings,
organization_moves: result.organization_moves,
before_yaml: "before_yaml" in result ? result.before_yaml : undefined,
after_yaml: result.canonical_yaml,
can_build: "can_build" in result ? result.can_build : undefined,
};
}
@@ -1,362 +0,0 @@
import {
BailianError,
defineCommand,
detectOutputFormat,
ExitCode,
type FlagsDef,
} from "bailian-cli-core";
import { confirmDangerousAction, emitBare, emitResult } from "bailian-cli-runtime";
import chalk from "chalk";
import {
disableProjectVersioning,
enableProjectVersioning,
getProjectVersionStatus,
type ProjectVersion,
type ProjectVersionPreview,
type ProjectVersionStatus,
listProjectVersions,
previewProjectVersion,
restoreProjectVersion,
} from "@openagentpack/project-versions";
const FILE_FLAG = {
file: {
type: "string",
valueHint: "<path>",
description: {
"en-US": "Config file path (default: agents.yaml)",
"zh-CN": "配置文件路径(默认:agents.yaml)",
},
},
} satisfies FlagsDef;
const VERSION_FLAG = {
versionId: {
type: "string",
valueHint: "<full-version>",
required: true,
description: {
"en-US": "Full local version ID",
"zh-CN": "完整的本地版本 ID",
},
},
} satisfies FlagsDef;
export const managedAgentVersionEnable = defineCommand({
description: {
"en-US": "Enable Apply-time local snapshots for agents.yaml",
"zh-CN": "为 agents.yaml 启用 Apply 后自动本地快照",
},
auth: "none",
usageArgs: "[--file <path>]",
flags: FILE_FLAG,
exampleArgs: ["", "--file agents.yaml"],
async run(ctx) {
const file = ctx.flags.file ?? "agents.yaml";
const format = detectOutputFormat(ctx.settings.output);
if (ctx.settings.dryRun) {
emitResult({ would_enable: file, versioning: await getProjectVersionStatus(file) }, format);
return;
}
const result = await enableProjectVersioning(file, "Enable Bailian CLI versioning");
if (format === "json") {
emitResult(result, format);
return;
}
if (result.version) {
emitBare(
`Created baseline version ${result.version.short_version} ${result.version.message}`,
);
} else {
emitBare("Current agents.yaml is already versioned; no snapshot was created.");
}
emitBare("Automatic versioning is enabled for this agents.yaml.");
renderStatus(result.versioning);
},
});
export const managedAgentVersionDisable = defineCommand({
description: {
"en-US": "Disable Apply-time local snapshots without removing history",
"zh-CN": "关闭 Apply 后自动本地快照,但保留历史",
},
auth: "none",
usageArgs: "[--file <path>]",
flags: FILE_FLAG,
exampleArgs: ["", "--file agents.yaml"],
async run(ctx) {
const file = ctx.flags.file ?? "agents.yaml";
const format = detectOutputFormat(ctx.settings.output);
if (ctx.settings.dryRun) {
emitResult({ would_disable: file, versioning: await getProjectVersionStatus(file) }, format);
return;
}
const status = await disableProjectVersioning(file);
if (format === "json") {
emitResult(status, format);
return;
}
emitBare("Automatic versioning is disabled for this agents.yaml.");
renderStatus(status);
},
});
export const managedAgentVersionStatus = defineCommand({
description: {
"en-US": "Show local snapshot versioning status for agents.yaml",
"zh-CN": "显示 agents.yaml 的本地快照版本管理状态",
},
auth: "none",
usageArgs: "[--file <path>]",
flags: FILE_FLAG,
exampleArgs: ["", "--file agents.yaml --output json"],
async run(ctx) {
const status = await getProjectVersionStatus(ctx.flags.file ?? "agents.yaml");
const format = detectOutputFormat(ctx.settings.output);
if (format === "json") emitResult(status, format);
else renderStatus(status);
},
});
const LIST_FLAGS = {
...FILE_FLAG,
limit: {
type: "number",
valueHint: "<n>",
description: {
"en-US": "Maximum versions to return (default: 50, max: 100)",
"zh-CN": "最多返回的版本数(默认:50,最大:100)",
},
},
cursor: {
type: "string",
valueHint: "<cursor>",
description: {
"en-US": "Pagination cursor returned by the previous page",
"zh-CN": "上一页返回的分页游标",
},
},
} satisfies FlagsDef;
export const managedAgentVersionList = defineCommand({
description: {
"en-US": "List local snapshots of agents.yaml",
"zh-CN": "列出 agents.yaml 的本地快照",
},
auth: "none",
usageArgs: "[--file <path>] [--limit <n>] [--cursor <cursor>]",
flags: LIST_FLAGS,
exampleArgs: ["", "--limit 20 --output json"],
async run(ctx) {
const page = await listProjectVersions(ctx.flags.file ?? "agents.yaml", {
limit: ctx.flags.limit,
cursor: ctx.flags.cursor,
});
const format = detectOutputFormat(ctx.settings.output);
if (format === "json") {
emitResult(page, format);
return;
}
if (page.versions.length === 0) {
emitBare("No local versions of agents.yaml exist.");
return;
}
for (const version of page.versions) emitBare(formatVersion(version));
if (page.next_cursor) emitBare(chalk.dim(`Next cursor: ${page.next_cursor}`));
},
});
const PREVIEW_FLAGS = {
...FILE_FLAG,
...VERSION_FLAG,
} satisfies FlagsDef;
export const managedAgentVersionPreview = defineCommand({
description: {
"en-US": "Preview a historical agents.yaml version",
"zh-CN": "预览 agents.yaml 的历史版本",
},
auth: "none",
usageArgs: "--version-id <full-version> [--file <path>]",
flags: PREVIEW_FLAGS,
exampleArgs: ["--version-id <full-version>", "--version-id <full-version> --output json"],
async run(ctx) {
const preview = await previewProjectVersion(
ctx.flags.file ?? "agents.yaml",
ctx.flags.versionId,
);
const format = detectOutputFormat(ctx.settings.output);
if (format === "json") emitResult(preview, format);
else renderPreview(preview);
},
});
const RESTORE_FLAGS = {
...PREVIEW_FLAGS,
yes: {
type: "switch",
description: {
"en-US": "Restore without an interactive confirmation",
"zh-CN": "无需交互确认直接恢复",
},
},
} satisfies FlagsDef;
export const managedAgentVersionRestore = defineCommand({
description: {
"en-US": "Restore a historical agents.yaml version to the working tree",
"zh-CN": "将 agents.yaml 历史版本恢复到工作区",
},
auth: "none",
usageArgs: "--version-id <full-version> [--file <path>] [--yes]",
flags: RESTORE_FLAGS,
exampleArgs: ["--version-id <full-version>", "--version-id <full-version> --yes --output json"],
async run(ctx) {
const file = ctx.flags.file ?? "agents.yaml";
const preview = await previewProjectVersion(file, ctx.flags.versionId);
const format = detectOutputFormat(ctx.settings.output);
if (format !== "json") renderPreview(preview);
if (!preview.can_restore) {
throw new BailianError(
preview.diagnostics.find((diagnostic) => diagnostic.severity === "error")?.message ??
preview.blockers[0] ??
"This version cannot be restored.",
ExitCode.GENERAL,
);
}
if (ctx.settings.dryRun) {
emitResult({ would_restore: ctx.flags.versionId, preview }, format);
return;
}
await confirmDangerousAction(
"Restore this version to the agents.yaml working tree? Version history and agents.state.json will not change.",
ctx.flags.yes,
);
const restored = await restoreProjectVersion(file, ctx.flags.versionId, {
headVersion: preview.base_head_version,
sourceRevision: preview.base_source_revision,
});
if (format === "json") {
emitResult({ restored: ctx.flags.versionId, preview: restored }, format);
} else {
emitBare(
`Restored ${ctx.flags.versionId.slice(0, 12)} to the working tree. Version history was not changed.`,
);
}
},
});
function renderStatus(status: ProjectVersionStatus): void {
emitBare(`Automatic versioning: ${status.enabled ? "enabled" : "disabled"}`);
emitBare(`Version store: ${status.initialized ? status.store_root : "not initialized"}`);
emitBare(`Config path: ${status.config_path}`);
emitBare(`Current version: ${status.head_version ?? "none"}`);
emitBare(
`agents.yaml: ${status.source_status}${status.source_versioned ? ", versioned" : ", unversioned"}`,
);
const blockers = [...new Set([...status.write_blockers, ...status.restore_blockers])];
for (const blocker of blockers) emitBare(chalk.yellow(`Blocker: ${blocker}`));
}
function formatVersion(version: ProjectVersion): string {
return `${chalk.yellow(version.short_version)} ${version.created_at} ${version.message} ${chalk.dim(`(${version.created_by})`)}`;
}
function renderPreview(preview: ProjectVersionPreview): void {
emitBare(chalk.bold(`Version ${preview.version_id}`));
emitBare(chalk.red("--- working tree"));
emitBare(chalk.green(`+++ ${preview.version_id}`));
for (const line of buildLineDiff(preview.before_yaml, preview.after_yaml)) {
if (line.kind === "deletion") emitBare(chalk.red(`-${line.text}`));
else if (line.kind === "addition") emitBare(chalk.green(`+${line.text}`));
else emitBare(chalk.dim(` ${line.text}`));
}
for (const diagnostic of preview.diagnostics) {
const color =
diagnostic.severity === "error"
? chalk.red
: diagnostic.severity === "warning"
? chalk.yellow
: chalk.dim;
emitBare(color(`${diagnostic.severity}: ${diagnostic.code}: ${diagnostic.message}`));
}
for (const blocker of preview.blockers) emitBare(chalk.yellow(`blocker: ${blocker}`));
emitBare(`Can restore: ${preview.can_restore ? "yes" : "no"}`);
}
type DiffLine = { kind: "context" | "addition" | "deletion"; text: string };
function buildLineDiff(beforeSource: string, afterSource: string): DiffLine[] {
const beforeLines = yamlLines(beforeSource);
const afterLines = yamlLines(afterSource);
const maximumDistance = beforeLines.length + afterLines.length;
const frontier = new Map<number, number>([[1, 0]]);
const traces: Array<Map<number, number>> = [];
for (let editDistance = 0; editDistance <= maximumDistance; editDistance += 1) {
traces.push(new Map(frontier));
for (let diagonal = -editDistance; diagonal <= editDistance; diagonal += 2) {
const deletionStart = frontier.get(diagonal - 1) ?? Number.NEGATIVE_INFINITY;
const additionStart = frontier.get(diagonal + 1) ?? Number.NEGATIVE_INFINITY;
const startsWithAddition =
diagonal === -editDistance || (diagonal !== editDistance && deletionStart < additionStart);
let beforeIndex = startsWithAddition ? (frontier.get(diagonal + 1) ?? 0) : deletionStart + 1;
let afterIndex = beforeIndex - diagonal;
while (
beforeIndex < beforeLines.length &&
afterIndex < afterLines.length &&
beforeLines[beforeIndex] === afterLines[afterIndex]
) {
beforeIndex += 1;
afterIndex += 1;
}
frontier.set(diagonal, beforeIndex);
if (beforeIndex >= beforeLines.length && afterIndex >= afterLines.length) {
return backtrackDiff(beforeLines, afterLines, traces, editDistance);
}
}
}
return [];
}
function backtrackDiff(
beforeLines: string[],
afterLines: string[],
traces: Array<Map<number, number>>,
finalDistance: number,
): DiffLine[] {
let beforeIndex = beforeLines.length;
let afterIndex = afterLines.length;
const reversedLines: DiffLine[] = [];
for (let editDistance = finalDistance; editDistance >= 0; editDistance -= 1) {
const frontier = traces[editDistance]!;
const diagonal = beforeIndex - afterIndex;
const deletionStart = frontier.get(diagonal - 1) ?? Number.NEGATIVE_INFINITY;
const additionStart = frontier.get(diagonal + 1) ?? Number.NEGATIVE_INFINITY;
const cameFromAddition =
diagonal === -editDistance || (diagonal !== editDistance && deletionStart < additionStart);
const previousDiagonal = cameFromAddition ? diagonal + 1 : diagonal - 1;
const previousBeforeIndex = frontier.get(previousDiagonal) ?? 0;
const previousAfterIndex = previousBeforeIndex - previousDiagonal;
while (beforeIndex > previousBeforeIndex && afterIndex > previousAfterIndex) {
reversedLines.push({ kind: "context", text: beforeLines[beforeIndex - 1]! });
beforeIndex -= 1;
afterIndex -= 1;
}
if (editDistance === 0) break;
if (beforeIndex === previousBeforeIndex) {
reversedLines.push({ kind: "addition", text: afterLines[afterIndex - 1]! });
afterIndex -= 1;
} else {
reversedLines.push({ kind: "deletion", text: beforeLines[beforeIndex - 1]! });
beforeIndex -= 1;
}
}
return reversedLines.reverse();
}
function yamlLines(source: string): string[] {
const lines = source.split("\n");
if (lines[lines.length - 1] === "") lines.pop();
return lines;
}
@@ -3,7 +3,7 @@ import { emitResult } from "bailian-cli-runtime";
import { CREDENTIALS_NOTE } from "./_engine/config-loader.ts";
import { launchManagedAgentPlayground } from "./_engine/playground-launcher.ts";
const WORKBENCH_FLAGS = {
const PLAYGROUND_BASE_FLAGS = {
file: {
type: "string",
valueHint: "<path>",
@@ -30,7 +30,7 @@ const WORKBENCH_FLAGS = {
} satisfies FlagsDef;
const PLAYGROUND_FLAGS = {
...WORKBENCH_FLAGS,
...PLAYGROUND_BASE_FLAGS,
agent: {
type: "string",
valueHint: "<id>",
@@ -41,52 +41,16 @@ const PLAYGROUND_FLAGS = {
},
} satisfies FlagsDef;
const WORKBENCH_NOTES = [
const PLAYGROUND_NOTES = [
...CREDENTIALS_NOTE,
{
"en-US":
"Workbench requires Node.js 22+ and starts the shared @openagentpack/playground package locally. Local versions use the shared .openagentpack/versions project store and do not require Git.",
"Session Preview requires Node.js 22+ and keeps using an agents.yaml source. Directory Workbench is available under managed-agent project workbench.",
"zh-CN":
"Workbench 需要 Node.js 22+,并在本地启动共享的 @openagentpack/playground 包;本地版本使用共享的 .openagentpack/versions 项目版本存储,不依赖 Git。",
"会话预览需要 Node.js 22+,并继续使用 agents.yaml;目录 Workbench 位于 managed-agent project workbench。",
},
];
export const managedAgentWorkbench = defineCommand({
description: {
"en-US": "Launch the agents.yaml project Workbench",
"zh-CN": "启动 agents.yaml 项目 Workbench",
},
auth: "apiKey",
usageArgs: "[--file <path>] [--port <n>] [--no-open]",
flags: WORKBENCH_FLAGS,
exampleArgs: ["", "--file agents.yaml --no-open", "--port 4949"],
notes: WORKBENCH_NOTES,
async run(ctx) {
const file = ctx.flags.file ?? "agents.yaml";
const port = ctx.flags.port ?? 4848;
if (ctx.settings.dryRun) {
emitResult(
{
would_launch: "workbench",
config_file: file,
port,
open_browser: !ctx.flags.noOpen,
},
detectOutputFormat(ctx.settings.output),
);
return;
}
await launchManagedAgentPlayground({
file,
port,
open: !ctx.flags.noOpen,
surface: "workbench",
client: ctx.client,
settings: ctx.settings,
});
},
});
export const managedAgentPlayground = defineCommand({
description: {
"en-US": "Launch a Session Preview for an agents.yaml Agent",
@@ -96,7 +60,7 @@ export const managedAgentPlayground = defineCommand({
usageArgs: "[--file <path>] [--agent <id>] [--port <n>] [--no-open]",
flags: PLAYGROUND_FLAGS,
exampleArgs: ["", "--agent assistant", "--file agents.yaml --no-open"],
notes: WORKBENCH_NOTES,
notes: PLAYGROUND_NOTES,
async run(ctx) {
const file = ctx.flags.file ?? "agents.yaml";
const port = ctx.flags.port ?? 4848;
+13 -11
View File
@@ -136,18 +136,20 @@ export { default as managedAgentValidate } from "./commands/managed-agent/valida
export { default as managedAgentPlan } from "./commands/managed-agent/plan.ts";
export { default as managedAgentApply } from "./commands/managed-agent/apply.ts";
export { default as managedAgentDestroy } from "./commands/managed-agent/destroy.ts";
export { managedAgentPlayground } from "./commands/managed-agent/workbench.ts";
export {
managedAgentPlayground,
managedAgentWorkbench,
} from "./commands/managed-agent/workbench.ts";
export {
managedAgentVersionDisable,
managedAgentVersionEnable,
managedAgentVersionList,
managedAgentVersionPreview,
managedAgentVersionRestore,
managedAgentVersionStatus,
} from "./commands/managed-agent/version.ts";
managedAgentProjectBuild,
managedAgentProjectInit,
managedAgentProjectPublish,
managedAgentProjectValidate,
managedAgentProjectVersionDisable,
managedAgentProjectVersionEnable,
managedAgentProjectVersionList,
managedAgentProjectVersionPreview,
managedAgentProjectVersionRestore,
managedAgentProjectVersionStatus,
managedAgentProjectWorkbench,
} from "./commands/managed-agent/project.ts";
export { default as managedAgentStateList } from "./commands/managed-agent/state-list.ts";
export { default as managedAgentStateShow } from "./commands/managed-agent/state-show.ts";
export { default as managedAgentStateRm } from "./commands/managed-agent/state-rm.ts";
@@ -1,5 +1,7 @@
import { mkdtemp, readFile, rm, stat } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, test } from "vite-plus/test";
import { afterEach, describe, expect, test } from "vite-plus/test";
import { e2eFixturesDir, parseStdoutJson, runCommandE2e } from "./helpers.ts";
import { MANAGED_AGENT_ROUTES } from "./topic-routes.ts";
@@ -15,6 +17,13 @@ const DEPLOYMENT_SAFETY_DIAGNOSTIC_CODES = [
"bailian.deployment.file.mount_path.required",
"bailian.deployment.file.mount_path.duplicate",
];
const projectDirectories: string[] = [];
afterEach(async () => {
for (const directory of projectDirectories.splice(0)) {
await rm(directory, { recursive: true, force: true });
}
});
/**
* managed-agent:help / 缺参不依赖密钥;所有 mutation 命令的 --dry-run
@@ -143,19 +152,83 @@ describe("e2e: managed-agent", () => {
expect(stderr).not.toContain("--git");
});
test("managed-agent version 暴露共享版本管理子命令", async () => {
test("managed-agent project 暴露目录项目与共享版本管理子命令", async () => {
const { stderr, exitCode } = await runCommandE2e(MANAGED_AGENT_ROUTES, [
"managed-agent",
"version",
"project",
"--help",
]);
expect(exitCode, stderr).toBe(0);
expect(stderr).toMatch(/enable|disable|status|list|preview|restore/i);
expect(stderr).toMatch(/init|validate|build|publish|workbench|version/i);
});
test("managed-agent version preview 缺少 --version-id 时退出为用法错误 (2)", async () => {
test("managed-agent project 完成 init、validate、build 与 version status 本地闭环", async () => {
const projectRoot = await mkdtemp(join(tmpdir(), "bailian-managed-agent-project-"));
projectDirectories.push(projectRoot);
const initialized = await runCommandE2e(MANAGED_AGENT_ROUTES, [
"managed-agent",
"project",
"init",
"--project",
projectRoot,
"--provider",
"bailian",
"--output",
"json",
]);
expect(initialized.exitCode, initialized.stderr).toBe(0);
expect(
parseStdoutJson<{ baseline_version?: string }>(initialized.stdout).baseline_version,
).toMatch(/^[a-f0-9]{64}$/);
const validated = await runCommandE2e(MANAGED_AGENT_ROUTES, [
"managed-agent",
"project",
"validate",
"--project",
projectRoot,
"--output",
"json",
]);
expect(validated.exitCode, validated.stderr).toBe(0);
expect(
parseStdoutJson<{ diagnostics?: Array<{ severity?: string }> }>(validated.stdout).diagnostics,
).not.toContainEqual(expect.objectContaining({ severity: "error" }));
const built = await runCommandE2e(MANAGED_AGENT_ROUTES, [
"managed-agent",
"project",
"build",
"--project",
projectRoot,
"--yes",
"--output",
"json",
]);
expect(built.exitCode, built.stderr).toBe(0);
expect(await readFile(join(projectRoot, ".openagentpack/build/agents.yaml"), "utf8")).toContain(
"assistant",
);
const status = await runCommandE2e(MANAGED_AGENT_ROUTES, [
"managed-agent",
"project",
"version",
"status",
"--project",
projectRoot,
"--output",
"json",
]);
expect(status.exitCode, status.stderr).toBe(0);
expect(parseStdoutJson<{ enabled?: boolean }>(status.stdout).enabled).toBe(true);
expect(await stat(join(projectRoot, ".openagentpack/state.json")).catch(() => null)).toBeNull();
});
test("managed-agent project version preview 缺少 --version-id 时退出为用法错误 (2)", async () => {
const { stderr, exitCode } = await runCommandE2e(MANAGED_AGENT_ROUTES, [
"managed-agent",
"project",
"version",
"preview",
"--quiet",
@@ -250,11 +323,14 @@ describe("e2e: managed-agent(--dry-run 短路,不联网不写盘)", () =>
expect(data.provider).toBe("bailian");
});
test("workbench --dry-run 仅输出启动计划", async () => {
test("project workbench --dry-run 仅输出目录项目启动计划", async () => {
const { stdout, stderr, exitCode } = await runCommandE2e(MANAGED_AGENT_ROUTES, [
"managed-agent",
"project",
"workbench",
"--dry-run",
"--project",
"./agent-project",
"--no-open",
"--output",
"json",
@@ -262,10 +338,12 @@ describe("e2e: managed-agent(--dry-run 短路,不联网不写盘)", () =>
expect(exitCode, stderr).toBe(0);
const data = parseStdoutJson<{
would_launch?: string;
open_browser?: boolean;
project_root?: string;
port?: number;
}>(stdout);
expect(data.would_launch).toBe("workbench");
expect(data.open_browser).toBe(false);
expect(data.project_root).toBe("./agent-project");
expect(data.port).toBe(4848);
});
test("apply --dry-run 仅输出计划", async () => {
+11 -7
View File
@@ -186,14 +186,18 @@ export const MANAGED_AGENT_ROUTES: E2eRouteExports = {
"managed-agent plan": "managedAgentPlan",
"managed-agent apply": "managedAgentApply",
"managed-agent destroy": "managedAgentDestroy",
"managed-agent workbench": "managedAgentWorkbench",
"managed-agent playground": "managedAgentPlayground",
"managed-agent version enable": "managedAgentVersionEnable",
"managed-agent version disable": "managedAgentVersionDisable",
"managed-agent version status": "managedAgentVersionStatus",
"managed-agent version list": "managedAgentVersionList",
"managed-agent version preview": "managedAgentVersionPreview",
"managed-agent version restore": "managedAgentVersionRestore",
"managed-agent project init": "managedAgentProjectInit",
"managed-agent project validate": "managedAgentProjectValidate",
"managed-agent project build": "managedAgentProjectBuild",
"managed-agent project publish": "managedAgentProjectPublish",
"managed-agent project workbench": "managedAgentProjectWorkbench",
"managed-agent project version enable": "managedAgentProjectVersionEnable",
"managed-agent project version disable": "managedAgentProjectVersionDisable",
"managed-agent project version status": "managedAgentProjectVersionStatus",
"managed-agent project version list": "managedAgentProjectVersionList",
"managed-agent project version preview": "managedAgentProjectVersionPreview",
"managed-agent project version restore": "managedAgentProjectVersionRestore",
"managed-agent state list": "managedAgentStateList",
"managed-agent state rm": "managedAgentStateRm",
"managed-agent state import": "managedAgentStateImport",
+16 -13
View File
@@ -37,21 +37,24 @@ description: >-
5. Destroy bl managed-agent destroy --yes # only after user confirmation
```
## Workbench and local versions
## Directory projects, Workbench, and local versions
| Intent | Command |
| ---------------------------------------- | ---------------------------------------------- |
| Launch project resource editing | `bl managed-agent workbench` |
| Launch one Agent Session Preview | `bl managed-agent playground --agent <id>` |
| Enable/disable shared automatic versions | `bl managed-agent version enable` / `disable` |
| Inspect local version state and history | `bl managed-agent version status` / `list` |
| Preview or restore a historical YAML | `bl managed-agent version preview` / `restore` |
| Intent | Command |
| --------------------------------------- | ------------------------------------------------------ |
| Create or convert a directory project | `bl managed-agent project init` |
| Validate and Build directory source | `bl managed-agent project validate` / `build` |
| Publish the current immutable Build | `bl managed-agent project publish --yes` |
| Launch project resource editing | `bl managed-agent project workbench` |
| Launch one Agent Session Preview | `bl managed-agent playground --agent <id>` |
| Enable/disable project versions | `bl managed-agent project version enable` / `disable` |
| Inspect local version state and history | `bl managed-agent project version status` / `list` |
| Preview or restore project source | `bl managed-agent project version preview` / `restore` |
- Bailian CLI and Workbench use the same `.openagentpack/versions` store and enable switch for the same `agents.yaml`. Git is not required.
- `store.json` contains only the switch and head metadata. Immutable linked entries live under `entries/`, while complete YAML is stored as content-addressed blobs under `blobs/`. Neither `agents.state.json` nor referenced files are versioned.
- When enabled, a fully successful Apply creates a local snapshot only when `agents.yaml` changed. Failed, partial, cancelled, and `--refresh-only` Apply runs do not create one.
- `version restore` writes the historical YAML to the working tree. It does not move version history, restore `agents.state.json`, create a new snapshot, or Apply remote changes.
- Workbench can edit local drafts while Apply is running, but saving/version mutations are blocked until Apply completes. External file edits are detected through revision checks.
- Bailian CLI and Workbench use the same `.openagentpack/versions/project` store and enable switch. Git is not required.
- Build is local-only. Publish never runs Build implicitly and consumes only a current `.openagentpack/build/agents.yaml` plus manifest.
- A successful Publish versions the canonical YAML and the complete project source tree, including Skill scripts/assets and binary files. Remote State is never versioned or restored.
- `project version restore` restores source files to the working directory, invalidates Build, and does not move version history or remote State.
- `managed-agent playground` remains the standalone `agents.yaml` Session Preview path; directory Workbench is only under `managed-agent project workbench`.
## Deployment as IaC
+34 -30
View File
@@ -9,39 +9,43 @@ Use this index for the skill-scoped quick index and global flags.
## Quick index
| Command | Authentication | Description | Detail |
| ---------------------------------- | -------------- | ------------------------------------------------------------- | ------------------------------------ |
| `bl managed-agent apply` | API Key | Apply planned changes to create/update/delete agent resources | [managed-agent.md](managed-agent.md) |
| `bl managed-agent destroy` | API Key | Destroy all managed agent resources tracked in state | [managed-agent.md](managed-agent.md) |
| `bl managed-agent init` | No Auth | Create an agents.yaml template | [managed-agent.md](managed-agent.md) |
| `bl managed-agent plan` | API Key | Show what changes would be applied to agent infrastructure | [managed-agent.md](managed-agent.md) |
| `bl managed-agent playground` | API Key | Launch a Session Preview for an agents.yaml Agent | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session create` | API Key | Create a new session for an agent | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session delete` | API Key | Delete a session | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session events` | API Key | List event history for a session | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session get` | API Key | Get details of a session | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session list` | API Key | List sessions from the provider | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session run` | API Key | Create a session, send a message, and stream the response | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session send` | API Key | Send a message to an existing session and stream the response | [managed-agent.md](managed-agent.md) |
| `bl managed-agent skill-list` | API Key | List skills from the provider's skill catalog | [managed-agent.md](managed-agent.md) |
| `bl managed-agent state import` | API Key | Import an existing remote resource into agents state | [managed-agent.md](managed-agent.md) |
| `bl managed-agent state list` | No Auth | List resources tracked in agents state | [managed-agent.md](managed-agent.md) |
| `bl managed-agent state rm` | No Auth | Remove a resource from state without destroying it remotely | [managed-agent.md](managed-agent.md) |
| `bl managed-agent state show` | No Auth | Show details of a resource in agents state | [managed-agent.md](managed-agent.md) |
| `bl managed-agent validate` | No Auth | Validate an agents.yaml configuration (offline) | [managed-agent.md](managed-agent.md) |
| `bl managed-agent version disable` | No Auth | Disable Apply-time local snapshots without removing history | [managed-agent.md](managed-agent.md) |
| `bl managed-agent version enable` | No Auth | Enable Apply-time local snapshots for agents.yaml | [managed-agent.md](managed-agent.md) |
| `bl managed-agent version list` | No Auth | List local snapshots of agents.yaml | [managed-agent.md](managed-agent.md) |
| `bl managed-agent version preview` | No Auth | Preview a historical agents.yaml version | [managed-agent.md](managed-agent.md) |
| `bl managed-agent version restore` | No Auth | Restore a historical agents.yaml version to the working tree | [managed-agent.md](managed-agent.md) |
| `bl managed-agent version status` | No Auth | Show local snapshot versioning status for agents.yaml | [managed-agent.md](managed-agent.md) |
| `bl managed-agent workbench` | API Key | Launch the agents.yaml project Workbench | [managed-agent.md](managed-agent.md) |
| Command | Authentication | Description | Detail |
| ------------------------------------------ | -------------- | ------------------------------------------------------------------ | ------------------------------------ |
| `bl managed-agent apply` | API Key | Apply planned changes to create/update/delete agent resources | [managed-agent.md](managed-agent.md) |
| `bl managed-agent destroy` | API Key | Destroy all managed agent resources tracked in state | [managed-agent.md](managed-agent.md) |
| `bl managed-agent init` | No Auth | Create an agents.yaml template | [managed-agent.md](managed-agent.md) |
| `bl managed-agent plan` | API Key | Show what changes would be applied to agent infrastructure | [managed-agent.md](managed-agent.md) |
| `bl managed-agent playground` | API Key | Launch a Session Preview for an agents.yaml Agent | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project build` | No Auth | Organize directory source and generate the immutable Publish Build | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project init` | No Auth | Create a directory project or convert the local agents.yaml | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project publish` | API Key | Publish the current directory-project Build and record a version | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project validate` | No Auth | Validate a directory Agent project | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project version disable` | No Auth | Disable directory project versions | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project version enable` | No Auth | Enable directory project versions | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project version list` | No Auth | List directory project versions | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project version preview` | No Auth | Preview a directory project version | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project version restore` | No Auth | Restore a version to the project working directory | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project version status` | No Auth | Show directory project version status | [managed-agent.md](managed-agent.md) |
| `bl managed-agent project workbench` | API Key | Launch the directory project Workbench | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session create` | API Key | Create a new session for an agent | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session delete` | API Key | Delete a session | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session events` | API Key | List event history for a session | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session get` | API Key | Get details of a session | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session list` | API Key | List sessions from the provider | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session run` | API Key | Create a session, send a message, and stream the response | [managed-agent.md](managed-agent.md) |
| `bl managed-agent session send` | API Key | Send a message to an existing session and stream the response | [managed-agent.md](managed-agent.md) |
| `bl managed-agent skill-list` | API Key | List skills from the provider's skill catalog | [managed-agent.md](managed-agent.md) |
| `bl managed-agent state import` | API Key | Import an existing remote resource into agents state | [managed-agent.md](managed-agent.md) |
| `bl managed-agent state list` | No Auth | List resources tracked in agents state | [managed-agent.md](managed-agent.md) |
| `bl managed-agent state rm` | No Auth | Remove a resource from state without destroying it remotely | [managed-agent.md](managed-agent.md) |
| `bl managed-agent state show` | No Auth | Show details of a resource in agents state | [managed-agent.md](managed-agent.md) |
| `bl managed-agent validate` | No Auth | Validate an agents.yaml configuration (offline) | [managed-agent.md](managed-agent.md) |
## By group
| Group | Commands | Reference |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| `managed-agent` | `apply`, `destroy`, `init`, `plan`, `playground`, `session create`, `session delete`, `session events`, `session get`, `session list`, `session run`, `session send`, `skill-list`, `state import`, `state list`, `state rm`, `state show`, `validate`, `version disable`, `version enable`, `version list`, `version preview`, `version restore`, `version status`, `workbench` | [managed-agent.md](managed-agent.md) |
| Group | Commands | Reference |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| `managed-agent` | `apply`, `destroy`, `init`, `plan`, `playground`, `project build`, `project init`, `project publish`, `project validate`, `project version disable`, `project version enable`, `project version list`, `project version preview`, `project version restore`, `project version status`, `project workbench`, `session create`, `session delete`, `session events`, `session get`, `session list`, `session run`, `session send`, `skill-list`, `state import`, `state list`, `state rm`, `state show`, `validate` | [managed-agent.md](managed-agent.md) |
## Global flags
@@ -7,33 +7,37 @@ Index: [index.md](index.md)
## Commands in this group
| Command | Authentication | Description |
| ---------------------------------- | -------------- | ------------------------------------------------------------- |
| `bl managed-agent apply` | API Key | Apply planned changes to create/update/delete agent resources |
| `bl managed-agent destroy` | API Key | Destroy all managed agent resources tracked in state |
| `bl managed-agent init` | No Auth | Create an agents.yaml template |
| `bl managed-agent plan` | API Key | Show what changes would be applied to agent infrastructure |
| `bl managed-agent playground` | API Key | Launch a Session Preview for an agents.yaml Agent |
| `bl managed-agent session create` | API Key | Create a new session for an agent |
| `bl managed-agent session delete` | API Key | Delete a session |
| `bl managed-agent session events` | API Key | List event history for a session |
| `bl managed-agent session get` | API Key | Get details of a session |
| `bl managed-agent session list` | API Key | List sessions from the provider |
| `bl managed-agent session run` | API Key | Create a session, send a message, and stream the response |
| `bl managed-agent session send` | API Key | Send a message to an existing session and stream the response |
| `bl managed-agent skill-list` | API Key | List skills from the provider's skill catalog |
| `bl managed-agent state import` | API Key | Import an existing remote resource into agents state |
| `bl managed-agent state list` | No Auth | List resources tracked in agents state |
| `bl managed-agent state rm` | No Auth | Remove a resource from state without destroying it remotely |
| `bl managed-agent state show` | No Auth | Show details of a resource in agents state |
| `bl managed-agent validate` | No Auth | Validate an agents.yaml configuration (offline) |
| `bl managed-agent version disable` | No Auth | Disable Apply-time local snapshots without removing history |
| `bl managed-agent version enable` | No Auth | Enable Apply-time local snapshots for agents.yaml |
| `bl managed-agent version list` | No Auth | List local snapshots of agents.yaml |
| `bl managed-agent version preview` | No Auth | Preview a historical agents.yaml version |
| `bl managed-agent version restore` | No Auth | Restore a historical agents.yaml version to the working tree |
| `bl managed-agent version status` | No Auth | Show local snapshot versioning status for agents.yaml |
| `bl managed-agent workbench` | API Key | Launch the agents.yaml project Workbench |
| Command | Authentication | Description |
| ------------------------------------------ | -------------- | ------------------------------------------------------------------ |
| `bl managed-agent apply` | API Key | Apply planned changes to create/update/delete agent resources |
| `bl managed-agent destroy` | API Key | Destroy all managed agent resources tracked in state |
| `bl managed-agent init` | No Auth | Create an agents.yaml template |
| `bl managed-agent plan` | API Key | Show what changes would be applied to agent infrastructure |
| `bl managed-agent playground` | API Key | Launch a Session Preview for an agents.yaml Agent |
| `bl managed-agent project build` | No Auth | Organize directory source and generate the immutable Publish Build |
| `bl managed-agent project init` | No Auth | Create a directory project or convert the local agents.yaml |
| `bl managed-agent project publish` | API Key | Publish the current directory-project Build and record a version |
| `bl managed-agent project validate` | No Auth | Validate a directory Agent project |
| `bl managed-agent project version disable` | No Auth | Disable directory project versions |
| `bl managed-agent project version enable` | No Auth | Enable directory project versions |
| `bl managed-agent project version list` | No Auth | List directory project versions |
| `bl managed-agent project version preview` | No Auth | Preview a directory project version |
| `bl managed-agent project version restore` | No Auth | Restore a version to the project working directory |
| `bl managed-agent project version status` | No Auth | Show directory project version status |
| `bl managed-agent project workbench` | API Key | Launch the directory project Workbench |
| `bl managed-agent session create` | API Key | Create a new session for an agent |
| `bl managed-agent session delete` | API Key | Delete a session |
| `bl managed-agent session events` | API Key | List event history for a session |
| `bl managed-agent session get` | API Key | Get details of a session |
| `bl managed-agent session list` | API Key | List sessions from the provider |
| `bl managed-agent session run` | API Key | Create a session, send a message, and stream the response |
| `bl managed-agent session send` | API Key | Send a message to an existing session and stream the response |
| `bl managed-agent skill-list` | API Key | List skills from the provider's skill catalog |
| `bl managed-agent state import` | API Key | Import an existing remote resource into agents state |
| `bl managed-agent state list` | No Auth | List resources tracked in agents state |
| `bl managed-agent state rm` | No Auth | Remove a resource from state without destroying it remotely |
| `bl managed-agent state show` | No Auth | Show details of a resource in agents state |
| `bl managed-agent validate` | No Auth | Validate an agents.yaml configuration (offline) |
## Command details
@@ -204,7 +208,7 @@ bl managed-agent plan --no-refresh
- Bailian credentials come from bl's auth chain: --api-key > DASHSCOPE_API_KEY > `bl auth login` (active config profile).
- Other providers read the env vars referenced in agents.yaml (e.g. ${ANTHROPIC_API_KEY}), including .env and ~/.agents/config.json.
- Resolved credentials are injected into the SDK in-memory and cleared from the environment; they never persist in process env.
- Workbench requires Node.js 22+ and starts the shared @openagentpack/playground package locally. Local versions use the shared .openagentpack/versions project store and do not require Git.
- Session Preview requires Node.js 22+ and keeps using an agents.yaml source. Directory Workbench is available under managed-agent project workbench.
#### Examples
@@ -220,6 +224,318 @@ bl managed-agent playground --agent assistant
bl managed-agent playground --file agents.yaml --no-open
```
### `bl managed-agent project build`
| Field | Value |
| ------------------ | ------------------------------------------------------------------ |
| **Name** | `managed-agent project build` |
| **Description** | Organize directory source and generate the immutable Publish Build |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project build [--project <directory>] [--yes]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
| `--yes` | switch | no | Write the previewed Build |
#### Examples
```bash
bl managed-agent project build --dry-run
```
```bash
bl managed-agent project build --yes
```
```bash
bl managed-agent project build --project ./my-agent --yes
```
### `bl managed-agent project init`
| Field | Value |
| ------------------ | ---------------------------------------------------------------------------- |
| **Name** | `managed-agent project init` |
| **Description** | Create a directory project or convert the local agents.yaml |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project init [--project <directory>] [--provider bailian]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
| `--provider <name>` | string | no | Provider for a new project |
#### Examples
```bash
bl managed-agent project init
```
```bash
bl managed-agent project init --project ./my-agent
```
```bash
bl managed-agent project init --provider bailian
```
### `bl managed-agent project publish`
| Field | Value |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `managed-agent project publish` |
| **Description** | Publish the current directory-project Build and record a version |
| **Authentication** | API Key |
| **Usage** | `bl managed-agent project publish [--project <directory>] [--provider <name>] [--yes] [--no-refresh] [--concurrency <n>]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
| `--provider <name>` | string | no | Target provider |
| `--yes` | switch | no | Confirm remote Publish |
| `--no-refresh` | switch | no | Skip remote refresh before planning |
| `--concurrency <n>` | number | no | Maximum parallel resource operations |
| `--api-key <key>` | string | no | API key |
| `--base-url <url>` | string | no | API base URL |
#### Notes
- Bailian credentials come from bl's auth chain: --api-key > DASHSCOPE_API_KEY > `bl auth login` (active config profile).
- Other providers read the env vars referenced in agents.yaml (e.g. ${ANTHROPIC_API_KEY}), including .env and ~/.agents/config.json.
- Resolved credentials are injected into the SDK in-memory and cleared from the environment; they never persist in process env.
#### Examples
```bash
bl managed-agent project publish --yes
```
```bash
bl managed-agent project publish --project ./my-agent --yes
```
```bash
bl managed-agent project publish --provider bailian --yes
```
### `bl managed-agent project validate`
| Field | Value |
| ------------------ | ----------------------------------------------------------- |
| **Name** | `managed-agent project validate` |
| **Description** | Validate a directory Agent project |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project validate [--project <directory>]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
#### Examples
```bash
bl managed-agent project validate
```
```bash
bl managed-agent project validate --project ./my-agent
```
### `bl managed-agent project version disable`
| Field | Value |
| ------------------ | ------------------------------------------------------------------ |
| **Name** | `managed-agent project version disable` |
| **Description** | Disable directory project versions |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project version disable [--project <directory>]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
#### Examples
```bash
bl managed-agent project version disable
```
```bash
bl managed-agent project version disable --project ./my-agent
```
### `bl managed-agent project version enable`
| Field | Value |
| ------------------ | ----------------------------------------------------------------- |
| **Name** | `managed-agent project version enable` |
| **Description** | Enable directory project versions |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project version enable [--project <directory>]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
#### Examples
```bash
bl managed-agent project version enable
```
```bash
bl managed-agent project version enable --project ./my-agent
```
### `bl managed-agent project version list`
| Field | Value |
| ------------------ | ------------------------------------------------------------------------------------------------- |
| **Name** | `managed-agent project version list` |
| **Description** | List directory project versions |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project version list [--project <directory>] [--limit <n>] [--cursor <cursor>]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
| `--limit <n>` | number | no | Maximum versions to return |
| `--cursor <cursor>` | string | no | Pagination cursor |
#### Examples
```bash
bl managed-agent project version list
```
```bash
bl managed-agent project version list --limit 20 --output json
```
### `bl managed-agent project version preview`
| Field | Value |
| ------------------ | ---------------------------------------------------------------------------------------------- |
| **Name** | `managed-agent project version preview` |
| **Description** | Preview a directory project version |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project version preview --version-id <full-version> [--project <directory>]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
| `--version-id <full-version>` | string | yes | Full project version ID |
#### Examples
```bash
bl managed-agent project version preview --version-id <full-version>
```
### `bl managed-agent project version restore`
| Field | Value |
| ------------------ | ------------------------------------------------------------------------------------------------------ |
| **Name** | `managed-agent project version restore` |
| **Description** | Restore a version to the project working directory |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project version restore --version-id <full-version> [--project <directory>] [--yes]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
| `--version-id <full-version>` | string | yes | Full project version ID |
| `--yes` | switch | no | Restore without interactive confirmation |
#### Examples
```bash
bl managed-agent project version restore --version-id <full-version>
```
```bash
bl managed-agent project version restore --version-id <full-version> --yes
```
### `bl managed-agent project version status`
| Field | Value |
| ------------------ | ----------------------------------------------------------------- |
| **Name** | `managed-agent project version status` |
| **Description** | Show directory project version status |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent project version status [--project <directory>]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
#### Examples
```bash
bl managed-agent project version status
```
```bash
bl managed-agent project version status --project ./my-agent --output json
```
### `bl managed-agent project workbench`
| Field | Value |
| ------------------ | ------------------------------------------------------------------------------------- |
| **Name** | `managed-agent project workbench` |
| **Description** | Launch the directory project Workbench |
| **Authentication** | API Key |
| **Usage** | `bl managed-agent project workbench [--project <directory>] [--port <n>] [--no-open]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------- | ------ | -------- | --------------------------------------------------- |
| `--project <directory>` | string | no | Directory project root (default: current directory) |
| `--port <n>` | number | no | Local port (default: 4848) |
| `--no-open` | switch | no | Do not open a browser |
| `--api-key <key>` | string | no | API key |
| `--base-url <url>` | string | no | API base URL |
#### Notes
- Bailian credentials come from bl's auth chain: --api-key > DASHSCOPE_API_KEY > `bl auth login` (active config profile).
- Other providers read the env vars referenced in agents.yaml (e.g. ${ANTHROPIC_API_KEY}), including .env and ~/.agents/config.json.
- Resolved credentials are injected into the SDK in-memory and cleared from the environment; they never persist in process env.
#### Examples
```bash
bl managed-agent project workbench
```
```bash
bl managed-agent project workbench --project ./my-agent --no-open
```
### `bl managed-agent session create`
| Field | Value |
@@ -664,198 +980,3 @@ bl managed-agent validate
```bash
bl managed-agent validate --file agents.yaml
```
### `bl managed-agent version disable`
| Field | Value |
| ------------------ | ----------------------------------------------------------- |
| **Name** | `managed-agent version disable` |
| **Description** | Disable Apply-time local snapshots without removing history |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent version disable [--file <path>]` |
#### Flags
| Flag | Type | Required | Description |
| --------------- | ------ | -------- | --------------------------------------- |
| `--file <path>` | string | no | Config file path (default: agents.yaml) |
#### Examples
```bash
bl managed-agent version disable
```
```bash
bl managed-agent version disable --file agents.yaml
```
### `bl managed-agent version enable`
| Field | Value |
| ------------------ | ------------------------------------------------- |
| **Name** | `managed-agent version enable` |
| **Description** | Enable Apply-time local snapshots for agents.yaml |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent version enable [--file <path>]` |
#### Flags
| Flag | Type | Required | Description |
| --------------- | ------ | -------- | --------------------------------------- |
| `--file <path>` | string | no | Config file path (default: agents.yaml) |
#### Examples
```bash
bl managed-agent version enable
```
```bash
bl managed-agent version enable --file agents.yaml
```
### `bl managed-agent version list`
| Field | Value |
| ------------------ | --------------------------------------------------------------------------------- |
| **Name** | `managed-agent version list` |
| **Description** | List local snapshots of agents.yaml |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent version list [--file <path>] [--limit <n>] [--cursor <cursor>]` |
#### Flags
| Flag | Type | Required | Description |
| ------------------- | ------ | -------- | -------------------------------------------------- |
| `--file <path>` | string | no | Config file path (default: agents.yaml) |
| `--limit <n>` | number | no | Maximum versions to return (default: 50, max: 100) |
| `--cursor <cursor>` | string | no | Pagination cursor returned by the previous page |
#### Examples
```bash
bl managed-agent version list
```
```bash
bl managed-agent version list --limit 20 --output json
```
### `bl managed-agent version preview`
| Field | Value |
| ------------------ | ------------------------------------------------------------------------------ |
| **Name** | `managed-agent version preview` |
| **Description** | Preview a historical agents.yaml version |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent version preview --version-id <full-version> [--file <path>]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------------- | ------ | -------- | --------------------------------------- |
| `--file <path>` | string | no | Config file path (default: agents.yaml) |
| `--version-id <full-version>` | string | yes | Full local version ID |
#### Examples
```bash
bl managed-agent version preview --version-id <full-version>
```
```bash
bl managed-agent version preview --version-id <full-version> --output json
```
### `bl managed-agent version restore`
| Field | Value |
| ------------------ | -------------------------------------------------------------------------------------- |
| **Name** | `managed-agent version restore` |
| **Description** | Restore a historical agents.yaml version to the working tree |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent version restore --version-id <full-version> [--file <path>] [--yes]` |
#### Flags
| Flag | Type | Required | Description |
| ----------------------------- | ------ | -------- | ------------------------------------------- |
| `--file <path>` | string | no | Config file path (default: agents.yaml) |
| `--version-id <full-version>` | string | yes | Full local version ID |
| `--yes` | switch | no | Restore without an interactive confirmation |
#### Examples
```bash
bl managed-agent version restore --version-id <full-version>
```
```bash
bl managed-agent version restore --version-id <full-version> --yes --output json
```
### `bl managed-agent version status`
| Field | Value |
| ------------------ | ----------------------------------------------------- |
| **Name** | `managed-agent version status` |
| **Description** | Show local snapshot versioning status for agents.yaml |
| **Authentication** | No Auth |
| **Usage** | `bl managed-agent version status [--file <path>]` |
#### Flags
| Flag | Type | Required | Description |
| --------------- | ------ | -------- | --------------------------------------- |
| `--file <path>` | string | no | Config file path (default: agents.yaml) |
#### Examples
```bash
bl managed-agent version status
```
```bash
bl managed-agent version status --file agents.yaml --output json
```
### `bl managed-agent workbench`
| Field | Value |
| ------------------ | --------------------------------------------------------------------- |
| **Name** | `managed-agent workbench` |
| **Description** | Launch the agents.yaml project Workbench |
| **Authentication** | API Key |
| **Usage** | `bl managed-agent workbench [--file <path>] [--port <n>] [--no-open]` |
#### Flags
| Flag | Type | Required | Description |
| ------------------ | ------ | -------- | --------------------------------------- |
| `--file <path>` | string | no | Config file path (default: agents.yaml) |
| `--port <n>` | number | no | Local port (default: 4848) |
| `--no-open` | switch | no | Do not open a browser automatically |
| `--api-key <key>` | string | no | API key |
| `--base-url <url>` | string | no | API base URL |
#### Notes
- Bailian credentials come from bl's auth chain: --api-key > DASHSCOPE_API_KEY > `bl auth login` (active config profile).
- Other providers read the env vars referenced in agents.yaml (e.g. ${ANTHROPIC_API_KEY}), including .env and ~/.agents/config.json.
- Resolved credentials are injected into the SDK in-memory and cleared from the environment; they never persist in process env.
- Workbench requires Node.js 22+ and starts the shared @openagentpack/playground package locally. Local versions use the shared .openagentpack/versions project store and do not require Git.
#### Examples
```bash
bl managed-agent workbench
```
```bash
bl managed-agent workbench --file agents.yaml --no-open
```
```bash
bl managed-agent workbench --port 4949
```