For AI agents: the complete documentation index is available at https://scriptedalchemy.github.io/agent-bundle/zh/llms.txt, the full documentation bundle is available at https://scriptedalchemy.github.io/agent-bundle/zh/llms-full.txt, and this page is available as Markdown at https://scriptedalchemy.github.io/agent-bundle/zh/examples/audiobook-curator.md.
跳至主要内容
  • 简体中文
  • 有声书策展器

    这不是对某一个表面的演示,而是一个完整的插件:一个真实的媒体管理应用,由 React Server Component 路由 模块、请求上下文、持久状态、MCP 路由与 CLI 路由组装而成。一次构建产出一个生成的 stdio MCP 服务器、 一个可安装的 CLI、一个 Skill,以及原生的 Claude Code 与 Codex 插件产物。它是框架自有包构建的参考 消费者。

    • 在仓库根目录运行: pnpm example:audiobook
    • 包名: @agent-bundle-example/audiobook-curator
    • 公开依赖: agent-bundle(workspace:*)、@agent-bundle/runtime(workspace:*)、 @modelcontextprotocol/server、react、zod
    • Target: claude、codex,且 marketplace: true
    • 需要: Node.js 22.19 或更高版本,以及 PATH 上的 ffprobe 与 ffmpeg
    • 源码: examples/audiobook-curator

    可选功能会调用为其提供证据的外部工具:Audiobook Forge、位于所选 Python 环境中的 Audiolocate,以及带 指定模型的 whisper-cli。跳过它们只会失去那些功能,而不影响构建。这个示例没有钩子。

    它证明什么

    • 路由树就是应用。 agent-bundle.config.ts 声明标识、Node 运行时与两个 target。其余由文件约定 发现:src/mcp/curator/ 下的 16 个工具路由、1 个目录资源与 1 个策展提示词。这里没有路由注册表, 没有手写的 src/mcp/curator.ts,没有逐操作的服务器选择器,也没有 routes 设置。每个工具都使用 defineTool,把元数据、schema 与处理器放在同一个定义中。
    • 一个操作,一条命令。 每个工具都有一个同目录的 <tool>.cli.ts 投影模块, search_audible.cli.ts 把工具拼写为 audible-search、--duration,以及可逗号分隔或重复的 --regions;prepare_audiobook.cli.ts 把 outputRoot 拼写为 --output; convert_audiobook.cli.ts 则通过 --input 保留完整的嵌套转换契约,因此编译后的图恰好有 16 条 CLI 命令,每条都带着工具自己的身份(tool:curator/<tool>)。没有 src/cli/ 目录,也没有 audiobook-curator curator <tool> --input 这样的孪生命令:投影就是命令。每个投影都声明 confirm: false,因为这些先计划再执行的命令用 --apply 而不是 --yes 把关变更。
    • 表现层是共享的,不是复制的。 src/components/ 是一份报告组件库,每个工具模块只渲染一次并服务 两种表面:MCP 文本内容与管道输出的 CLI Markdown 是同一份文档,因此一个工具和它的命令不可能漂移成 两套表现层。
    • Markdown 块就是 JSX。 组件库中的 DataList、FileList 原语以及重复分析中的已测量文件表格,都通过 运行时的 MarkdownContent 组件编写 Markdown,<ul>/<li>、<strong> 和一个 GFM <table>,而不是手工拼接字符串,因此转义归渲染器 负责,管道输出的 CLI Markdown 与 MCP 文本内容出自同一份输出。
    • 请求上下文是观察出来的,不是假定的。 约定式的 src/providers/library.ts 在每个请求中探测 ffmpeg -version 与 ffprobe -version,并连同探测时间一起发布工具可用性。目录资源通过 await agent() 读取它,并渲染实时上下文或一个显式的不可用状态。
    • 持久状态有被挂载的身份。 src/state.ts 挂载工作区级持久状态 audiobook-curator/shelf 与三个 事件。如果状态未挂载,只读的 review_curation_shelf 工具,命令行上是 shelf,会返回一个空的 结构化书架和一条显式的不可用提示,而不是失败。
    • Suspense 变成 MCP 进度。 audit_library 把它的异步分析放到 React Suspense 之后,回退内容是一个 Agent.Progress 节点,而这个回退本身就是全部的进度表面:生成的投影器会把它作为 notifications/progress 发送给传入了 progress token 的客户端,再用完成后的分析替换它,而最终的结构化收据不变。没有任何 progress.report() 调用重复这条消息。
    • 包构建归框架所有。 配置没有声明 bin,也没有声明 scripts。投影出的命令编译为 dist/bin/audiobook-curator.mjs 以服务 package.json 的 bin,而 dist/index.js 加声明文件服务 exports。见 CLI 与库包入口。
    • package.json 是唯一的版本来源。 解析出的版本会流入项目上下文、 产物清单、inspect 输出、dev 状态,以及这个插件导入的 agent-bundle/meta 常量。

    每条命令都渲染其工具的文档

    每条命令运行的就是其工具的组件。交互式终端会就地绘制流式的 Agent.Progress 回退;管道输出则是一份 最终的 Markdown 文档,与 MCP 客户端作为文本内容收到的是同一份标题与报告。--json 选择机器输出, 并输出一个经结果 schema 校验的 JSON 值加一个换行:这是最终的规范 Agent.Result 值,绝不是 Markdown 表现,也绝不是中间的 Suspense 回退,并且与工具调用的 structuredContent 逐字节一致。把字段投影为 flag 的命令仍提供可选的 --report 与 --receipt;convert 则把可选的 receipt 放在 JSON conversion 对象中。传入了的命令在成功时仍会写出收据文件。这相对于已移除的 src/cli/ 树是一处行为变化:那里每条接受报告或收据路径的命令(十六条中的十三条,包括 inventory --report 与 convert --receipt)都把它设为必填;现在这些命令不带该路径也能运行且不写报告或收据文件,而退出码、 --apply 把关与错误输出在两种情况下都不变。inspect、prepare 与 shelf 从来不接受这个参数。

    在工作区中开发

    pnpm --filter @agent-bundle-example/audiobook-curator build
    pnpm --filter @agent-bundle-example/audiobook-curator test
    pnpm --filter @agent-bundle-example/audiobook-curator test:routes
    pnpm --filter @agent-bundle-example/audiobook-curator typecheck

    包内的 pnpm check 会运行 validate、build、typecheck 与两个测试池。一次 agent-bundle build --output artifact 产出全部内容:位于 artifact/ 的一个复合插件根目录,承载 Claude 与 Codex 两个投影,各宿主的清单位于自己的点目录中,共用同一份 Skill、打包后的 CLI 脚本与被生命周期 包装的 MCP 服务器,以及 dist/ 下的 npm 包。

    从仓库根目录启动 pnpm example:audiobook,即可进入可视化开发循环:

    1. 展开 Application → MCP → curator → Tools 并选中 search_audible。
    2. 在生成的输入编辑器中输入诸如 Dune 这样的标题,然后选择 Run。
    3. 首先检视 Rendered:它展示该路由生产 RSC 执行得到的真实 Agent Document。结构化数据、原始文档、 MCP/CLI 投影与 Trace 仍作为次要标签可用。
    4. 打开 Trace,查看归入此次运行的调用开始与完成条目,然后使用 Open route 返回这份已记录结果。
    5. 编辑 src/mcp/curator/tools/search_audible.tsx 或它所渲染的某个组件。重建到达 Idle 之后, 重新运行已保存的输入,并检视更新后的渲染结果。

    该路由可直接寻址 /routes/mcp/curator/tool/search_audible;追加 ?invocation=<id> 即可重新打开本次会话中一条已记录的 结果。

    想在不打包 tarball 的情况下试用构建好的 CLI,可以从任意已在 PATH 上的可写目录链接构建产物中的 bin:

    cd examples/audiobook-curator
    ln -s "$(pwd)/dist/bin/audiobook-curator.mjs" ~/.local/bin/audiobook-curator
    audiobook-curator --help

    在 stdio 上运行服务器

    cd examples/audiobook-curator
    pnpm exec agent-bundle mcp run --server curator --target claude

    该命令会从 Claude target 的 MCP 清单解析出生成的入口,并先构建一份临时产物;传入 --artifact artifact 可改为复用 pnpm build 的输出。关闭 stdin 以 0 退出,Ctrl-C 以 130 退出, 每个服务器的状态持久化在 .agent-bundle/mcp-run/claude/curator 下。

    安全边界

    源文件不可变,规划阶段绝不改动媒体。转换会发布到独立的目标位置;元数据与章节替换必须显式 apply, 先写入同目录的暂存文件,校验暂存结果,然后原子重命名。JSON 收据拒绝音频后缀,也拒绝与媒体或证据输入 发生冲突。网络响应体、进程输出、目录遍历与并发都是有界的,网络工作使用有界重试加调用方的取消信号, 而不是隐藏的超时。本地媒体进程没有挂钟期限;调用方取消与有界的 stdout、stderr 依旧强制生效。

    整理 Skill 指示代理只执行请求范围内的操作:单纯盘点或审计不需要转换或版本匹配。需要修改时,先准备 准确的计划和证据,再请求缺少的批准;只有在输入未变时才复用已有批准。每次修改工具调用仍必须传入 apply: true,同时保留源文件不可变和人工审核版本选择的边界。