Composio CLI `composio run` 端到端测试深度解析:退出码转发与运行日志持久性验证

发布时间:2026/9/12 9:30:18

Composio CLI `composio run` 端到端测试深度解析:退出码转发与运行日志持久性验证 Composio CLIcomposio run端到端测试深度解析退出码转发与运行日志持久性验证【免费下载链接】composioComposio powers 1000 toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composiocomposio run是 Composio CLI 中用于执行内联 TypeScript/JavaScript 代码或脚本文件、并在其中注入execute、search、proxy、experimental_subAgent等工具助手helpers的核心命令。本文以仓库中该命令的端到端测试套件 ts/e2e-tests/cli/run/README.md 为骨架结合其实现源码 run.cmd.ts 与单元测试 run.cmd.test.ts系统讲解为什么composio run需要专门的 e2e 测试、它验证哪些关键行为、底层退出码与日志文件的机制原理以及如何在本仓库中实际运行这套测试。为什么composio run需要端到端测试一个单元测试无法覆盖的退出码盲区composio run的职责是把用户脚本作为子进程拉起并把子进程的退出状态原样转发给调用者。这个转发路径是进程级process-level的命令处理器handler只是设置process.exitCode然后返回一个成功的 Effect真正的退出动作发生在 CLI 的 teardown 阶段——teardown 把该退出码交给runMain而runMain仅在退出码非零时才强制退出进程。单元测试运行在进程内in-process只能观察到process.exitCode这个变量被设置成了什么却永远无法确认这个值是否真的到达了操作系统层。这意味着存在一个真实的回归风险一次 Effect 升级或 teardown 逻辑的改动可能让所有失败的脚本都变成 exit 0而整套单元测试依然全部通过——没有任何一个 in-process 断言能捕获这种故障。e2e 测试则是直接针对真实编译后的 CLI 二进制执行composio run process.exit(7)然后用wait/$?级别的断言去检查进程的真实退出码。这是唯一能在失败脚本被静默当成成功这一回归出现时发出警报的防线。运行日志同样面临进程结束后存活问题composio run会在 stderr 上打印一行RUN_LOG_FILEpath向调用者宣告本次运行日志文件的路径。这条路径只有在文件比打印它的进程活得更久时才有意义。历史上这里就回归过一次当时运行日志存放在一个作用域临时目录scoped temp directory里目录随进程结束被清理日志文件随之消失RUN_LOG_FILE路径形同虚设。这个文件在进程退出后是否仍然存在的属性同样无法在进程内被检查必须靠 e2e 测试在 CLI 进程退出之后再去探测文件系统。测试套件总览整个测试套件位于 ts/e2e-tests/cli/run/e2e.test.ts对应的清单文档 README.md 给出了完整的测试矩阵测试描述Exit forwarding退出码转发composio run process.exit(7)以退出码 7 结束Successful run成功运行内联脚本以 0 退出且其 stdout 能到达调用者Missing script缺少脚本不带代码也不带--file时非零退出并给出明确提示Run log durability日志持久性进程退出后宣告的RUN_LOG_FILE路径仍然存在运行前置要求Requirements无。该套件不需要任何环境变量也不需要网络访问——它不依赖 API Key、不调用远端服务纯粹验证 CLI 本地的进程行为。隔离工具Isolation ToolDocker并且 CLI 必须是从当前 monorepo 源码构建的版本。端到端测试基础设施e2e-tests/utils这套测试构建在仓库共享的 e2e 基础设施之上位于 ts/e2e-tests/_utils/README.md。核心是e2e()入口函数它从调用方位置自动推断工作目录与套件名称使用bun:test作为测试框架并在隔离的 Docker 容器中执行命令。本套件用到的关键 APIrunCmd(command: string): PromiseE2ETestResult在 Docker 容器中运行任意命令返回{ exitCode, stdout, stderr }sanitizeOutput()去除 ANSI 转义码、统一换行符并裁剪空白使输出断言稳定可比TIMEOUTS.FIXTURE120 秒用于beforeAll钩子中执行真实 CLI 命令的超时上限versions: { cli: [current] }声明测试当前版本的 CLIcurrent解析为ts/packages/cli/package.json中的版本号也可通过COMPOSIO_E2E_CLI_VERSION环境变量覆盖。套件的 package.json 依赖e2e-tests/utilsworkspace 内部包并声明了test:e2e:cli脚本bun test e2e.test.ts。四项测试的代码级详解测试主体在beforeAll中一次性执行四个命令并缓存结果均在TIMEOUTS.FIXTURE超时保护下随后用describe/it分组断言。1. 失败脚本的退出码转发failingScriptResult await runCmd(composio run process.exit(7)); it(forwards the script exit status to the caller, () { expect(failingScriptResult.exitCode).toBe(7); });这是整个套件最关键的一个断言脚本主动以7退出CLI 进程本身也必须以7退出。如果前面提到的teardown 改动导致失败脚本变成 exit 0的回归发生这条用例会立刻红灯。2. 成功脚本退出码与 stdout 转发const STDOUT_MARKER composio-run-e2e-stdout-marker; successfulScriptResult await runCmd(composio run console.log(${STDOUT_MARKER})); it(exits successfully, () { expect(successfulScriptResult.exitCode).toBe(0); }); it(forwards script stdout to the caller, () { expect(sanitizeOutput(successfulScriptResult.stdout)).toContain(STDOUT_MARKER); });成功路径除了验证退出码为 0还验证了子进程的 stdout 被原样透传——调用者能收到脚本打印的内容这是composio run作为脚本运行器的基本契约。3. 缺少脚本时的失败提示missingScriptResult await runCmd(composio run); it(exits non-zero, () { expect(missingScriptResult.exitCode).not.toBe(0); }); it(explains what is missing on stderr, () { expect(sanitizeOutput(missingScriptResult.stderr)).toContain( Provide inline code or use --file to run a script file. ); }); it(writes no data to stdout, () { expect(sanitizeOutput(missingScriptResult.stdout)).toBe(); });裸执行composio run既不提供内联代码也不提供--file时CLI 必须非零退出、在 stderr 上说明缺什么、并且不向 stdout 写任何数据。对应到源码这条错误信息正是MissingRunSourceError携带的MISSING_RUN_SOURCE_MESSAGE见 run.cmd.tsProvide inline code or use --file to run a script file. composio run console.log(1) composio run --file ./script.ts源码注释明确说明这是普通的用法错误usage mistake而不是内部不变量被破坏因此实现为带一行消息的类型化失败Data.TaggedError让调用者看到的是修复指引而非堆栈。并且这个检查发生在任何准备工作之前handler 的第一件事就是检查Option.isNone(file) !args[0]见 run.cmd.ts所以裸composio run既不会创建 run-artifacts 目录也不会宣告一个永远不会被使用的日志文件。4. RUN_LOG_FILE 路径的持久性探针这一组测试用一个复合 shell 命令实现进程外探测先运行一次成功的脚本把 CLI 自身的 stderr 重定向到run-stderr.txt文件避免其混入输出然后在 CLI 进程退出后解析出RUN_LOG_FILE宣告的路径再检查该文件是否存在const runLogProbeCommand [ composio run console.log(run-log-probe) 2 run-stderr.txt, run_status$?, run_log_path$(grep ^RUN_LOG_FILE run-stderr.txt | head -n 1 | cut -d -f2-), echo RUN_STATUS$run_status, if [ -n $run_log_path ]; then echo RUN_LOG_ANNOUNCEDyes; else echo RUN_LOG_ANNOUNCEDno; fi, if [ -f $run_log_path ]; then echo RUN_LOG_EXISTSyes; else echo RUN_LOG_EXISTSno; fi, ].join(; );探针结果以KEYvalue形式输出到 stdout随后在测试侧断言it(is announced, () { expect(runLogResult.exitCode).toBe(0); expect(sanitizeOutput(runLogResult.stdout)).toContain(RUN_STATUS0); expect(sanitizeOutput(runLogResult.stdout)).toContain(RUN_LOG_ANNOUNCEDyes); }); it(still exists after the CLI process exits, () { expect(sanitizeOutput(runLogResult.stdout)).toContain(RUN_LOG_EXISTSyes); });注意这里的时序关键点RUN_LOG_EXISTSyes的检查发生在composio run这个 CLI 进程已经退出之后由外层 shell 完成——这正是日志文件必须比打印它的进程活得更久这一契约的直接验证。也正是这一点让这个探针天然无法被放进单元测试。底层实现原理退出码与日志文件的生命周期退出码如何从子进程走到操作系统从 run.cmd.ts 的实现可以看到完整链路命令处理器通过ChildProcess.make拉起子进程process.execPath --preload preloadPath ...并await child.exitCode得到脚本退出码退出码被赋值给process.exitCode exitCodehandler 返回一个成功的 Effect让 Effect 运行时不做任何强制退出CLI teardown 读取process.exitCode并交给runMainrunMain只在非零时 force-exit。这个总是返回成功 Effect 依赖 teardown 转发退出码的设计正是 README 所述盲区的根源只要某次重构把 teardown 中的runMain行为改掉例如无论什么退出码都直接正常结束所有失败脚本都会静默变成 exit 0。e2e 测试用真实的$?值来做最后一道防线。顺带一提源码还处理了一个相关细节当用户按 Ctrl-C 中断时handler 把process.exitCode设为130即 128SIGINT 的惯例值防止 wrapper 脚本和set -e把一次被取消的运行误读为成功。RUN_LOG_FILE 为什么能活过进程RUN_LOG_FILE路径由createRunHelpersPreloadFile生成见 run.cmd.ts其中体现了两种临时目录的刻意区分preload 目录使用makeTempDirectoryScoped带前缀composio-run-创建作用域化运行结束时自动删除——globals.mjs预加载文件放在这里属于临时中间产物run 输出目录运行日志与较大的工具输出需要向调用者宣告并存活因此放在非作用域的独立临时目录makeTempDirectory前缀composio-run-artifacts-日志文件路径为runOutputDir/run.log。当检测到当前处于 consumer 项目时runOutputDir还会被替换为 CLI 会话工件目录resolveCliSessionArtifacts让日志落在项目会话的正式工件目录中。命令执行前的ui.error(\RUN_LOG_FILE${preload.runLogFilePath})见 run.cmd.ts就是把这行路径打到 stderr 上供外部工具或 e2e 探针捕获。这段代码的注释也直接呼应了 README 中记载的历史回归曾有一次日志被放进作用域临时目录导致RUN_LOG_FILE路径在进程结束后失效。配套单元测试的边界仓库中的单元测试 run.cmd.test.ts 通过替换ChildProcessSpawner为 stub 句柄STUB_CHILD_PID、挂起的exitCode来测试命令构造、信号转发、wrapInlineCodeForRun包装逻辑等 in-process 行为并断言MissingRunSourceError的错误消息对应缺失脚本场景。它与 e2e 测试形成互补单元测试验证处理器把 exitCode 设置对了e2e 测试验证这个 exitCode 真的到达了操作系统。二者缺一不可。如何运行这套测试在仓库根目录或ts/e2e-tests/cli/run目录执行pnpm test:e2e:cli该命令会执行bun test e2e.test.ts。运行前提本机安装Docker测试基础设施在隔离容器中运行命令见 ts/e2e-tests/_utils/README.mdCLI 镜像需从当前 monorepo 源码构建无需任何环境变量或网络访问套件完全离线可跑。如需调整被测 CLI 版本可通过COMPOSIO_E2E_CLI_VERSION环境变量覆盖默认current解析自ts/packages/cli/package.json。延伸阅读命令实现与全部 flag 定义ts/packages/cli/src/commands/run.cmd.ts含--file/-f、--dry-run、--debug、--logs-off、--skip-connection-check、--skip-tool-params-check、--skip-checks及注入的execute/search/proxy/experimental_subAgent/z等 helpers 说明单元测试进程内行为验证ts/packages/cli/test/src/commands/run.cmd.test.tse2e 基础设施与e2e()/runCmd/sanitizeOutput/TIMEOUTSAPIts/e2e-tests/_utils/README.md本套件清单文档ts/e2e-tests/cli/run/README.md【免费下载链接】composioComposio powers 1000 toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/12 10:20:25

七天征服Bootloader开发- 第0课(概述)

前言 在2个月前,Bootloader开发对我来说,犹如天花板一样的存在,高高在上,就像睥睨众生的撒旦在天上呼吸着稀薄的空气,可望而不可即,令基础软件开发的人们望而却步!但这2个月走来,从…

2026/9/12 10:20:25

MiniMax批量导出实战指南:浏览器插件与Python自动化方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 10:20:25

OpenCode源码解析:从Agent循环到Skills与LSP的完整实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 10:20:25

用Python打造交易策略执行路径可视化,防守日复盘+1.73%的秘诀

开盘前我盯着昨晚的外盘数据和今天的竞价量能,第一反应是:今天不适合进攻。结果收盘一看,账户定格在1.73%。这个数字在顺风局里不值一提,但在一个需要防守的交易日里,算是一笔“守出来”的收益。这轮操作里最有价值的其…

2026/9/12 10:20:24

YOLO野生动物检测系统:从模型选型到SpringBoot工程落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/12 10:15:24

C51单片机99秒秒表设计:定时器、动态扫描与Proteus仿真详解

简介:99秒马表设计是基于C51单片机的电子计时器项目,面向单片机初学者、课程设计及毕业设计学生,通过Proteus仿真实现0~99秒精确计时。资源共29个文件,压缩包84KB,包含Proteus仿真工程(DSN/DBK)…

2026/9/12 2:05:33

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/12 3:55:12

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/12 10:09:03

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码