资讯动态

Composio CLI 架构深度解析:基于 Effect 生态与 Bun 的命令行工程实践

发布时间:2026/9/12 16:39:06 来源:尧图企业网站定制
Composio CLI 架构深度解析基于 Effect 生态与 Bun 的命令行工程实践【免费下载链接】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 CLIcomposio/cli是 Composio 平台面向开发者的官方命令行工具用于登录认证、管理 toolkits/tools/triggers、生成类型桩代码以及运行 agent 工作流。本文以仓库中 ts/packages/cli/CLAUDE.md 为骨架结合源码深入剖析其基于Effect.ts 生态与Bun构建的服务化架构、命令体系、输出契约与工程规范帮助读者理解这一现代 CLI 的设计思路并掌握其关键配置、命令与扩展方式。CLI 概览与仓库结构composio/cli位于 ts/packages/cli发布产物为composio可执行文件package.json中bin指向./bin/composio.mjs。其核心特征运行时基于Bun开发时通过bun run src/bin.ts启动构建二进制时使用bun run ./scripts/build-binary.ts见 package.json。依赖注入采用 Effect 生态的 Layer 机制实现服务化架构控制流使用Effect.gen生成器语法错误处理使用结构化类型。CLI 框架使用effect/unstable/cli的Command.make()/Command.runWith()构建命令树与解析参数。TypeScript 版本固定该包将typescript依赖固定在 TypeScript 6catalog:ts6因为src/generation/typescript/*依赖 JS compiler API而 TS7tsgo不再提供该 API。此固定仅影响import ts from typescript的解析typecheck 脚本调用的tsc二进制仍来自 workspace 根TS7。从源码目录结构看CLI 源码按职责清晰分层src/bin.ts与src/cli-main.ts入口与顶层 Layer 组装src/commands/全部顶层命令与子命令组*.cmd.tssrc/services/Effect 服务认证、仓库、终端 UI、二进制升级等src/effects/可复用的 Effect 计算src/models/Effect Schema 数据模型src/generation/composio generate {ts,py}代码生成管线src/effect-errors/错误捕获、source-map 栈追踪与格式化输出入口与启动流程bin.ts → cli-main.tsbin.ts轻量引导层src/bin.ts 是唯一直接读取process.argv的地方此后所有消费者都接收规范化后的 argv。引导层做三件事剥离内部--telemetry-debug标志stripTelemetryDebugFlag。识别后台 worker 调用analytics 事件分发若为后台 worker则仅提供最小 Layer 集合并通过BunRuntime.runMain运行。否则动态导入cli-main.ts并调用runCli由后者组装完整的 Effect Layer 栈。cli-main.tsLayer 组装与错误契约src/cli-main.ts 是运行器的核心。它组合了完整的 Layer 栈layers变量约 25 个 Layer关键成员包括CliConfigLiveCliConfig.layer(ComposioCliConfig)仅启用GlobalFlag.Help内建标志详见下文配置小节。ComposioUserContextLive从~/.composio/读取用户认证状态。ComposioSessionRepositoryLiveOAuth2 会话管理。ComposioToolkitsRepositoryCachedLive带文件缓存的 toolkits/tools API 客户端。UpgradeBinaryLive从 GitHub Releases 自更新二进制。BunFileSystem.layer、BunPath.layer、BunServices.layer、FetchHttpClient.layerBun 运行时集成Effect v4 中BunContext已不存在BunServices.layer是聚合替代。Help 渲染与退出码契约Command.runWith会自行渲染帮助文本与解析/校验错误输出到正确的流随后以CliError.ShowHelp重新失败。该错误携带两个 Runtime 标记[Runtime.errorReported] false抑制runMain的自动错误日志与[Runtime.errorExitCode]裸--help为 0伴随解析错误为 1。因此cli-main.ts的 sandbox 兜底处理器对ShowHelp采用Effect.failCause原样转发绝不自行打印避免输出重复自定义teardown通过Runtime.getErrorExitCode从压缩后的失败中读取退出码。错误捕获真实命令执行失败经由自定义的effect-errors/模块捕获source-map 栈追踪、Effect span 时间线、格式化输出见 src/effect-errors。命令体系Command.make() 与命令树所有命令使用effect/unstable/cli的Command.make()模式。顶层命令文件以.cmd.ts结尾嵌套命令组位于各自子目录中以group.cmd.ts作为入口。根命令树在 src/commands/index.ts 中通过Command.withSubcommands组装。顶层命令一览组 / 命令用途version显示 CLI 版本支持--check检查更新whoami显示当前登录用户信息管道输出时向 stdout 写原始 API key见输出约定login浏览器跳转或直接 user/API key 登录--no-browser、--no-wait、--key、--user-api-key、--orglogout清除已存储的 API keysignup创建 Composio 账号upgrade从 GitHub Releases 自更新二进制init在当前目录初始化 Composio 项目install配置 shell 集成PATH 与补全generate {ts,py}生成类型桩无子命令时自动检测项目语言agent管理 AI agent 预设toolkits列出 / 查看 / 版本化 toolkitstools列出 / 查看 /execute工具triggers列出 / 管理 trigger 类型auth-configs管理 auth-config 资源ac_*connected-accounts管理已连接账号ca_*connectionsconnected-account 流程的别名 / 辅助命令orgs管理组织projects管理项目local-tools管理本地 toolkits通过composio/cli-local-toolslogs查看工具执行日志logs-cmd/config读写 CLI 配置listen监听事件实验特性proxy代理已认证的 API 请求run运行保存的脚本 / 预设dev仅开发者使用的工具artifacts管理生成的产物参数声明与 Feature Flag命名选项使用Flag.string()、Flag.boolean()、Flag.integer()、Flag.choice()、Flag.directory()均来自effect/unstable/cli位置参数使用Argument.string()/Argument.variadic()。二者共享.withDefault/.withDescription/.withAlias/.optional组合子。Feature flags 定义在 src/commands/feature-tags.ts 与 src/experimental-features.ts。argv 预处理与特殊路由runWithConfig在把 argv 交给解析器前做了一系列规范化见 src/commands/index.tsnormalizeVersionFlagcomposio --version/composio -v被重写为version命令使三者输出字节级一致裸 semver经ui.output()。这是GlobalFlag.Version未启用的原因——避免composio subcommand --version落入 v4 的name vversion横幅。splitRunPassthroughArgscomposio run需要把形如--flag value的 token 原样转发给用户脚本。由于 v4 的 CLI lexer 将每个-前缀 token 视为选项候选且--分隔只作用于第一层解析该函数将 passthrough tail 从 argv 中分离经RunPassthroughArgsservice 以 out-of-band 方式提供给runhandler。normalizeHiddenDebugFlags剥离--perf-debug、--tool-debug、--acp-only等隐藏调试标志以CliDebugFlags作为命令输入而非进程级状态。帮助路由isRootHelp/matchSubcommandHelp匹配根帮助与子命令帮助走自定义的printRootHelp/printSubcommandHelp见root-help.ts--help/-h被列入EXPLICIT_STDOUT_FLAGS显式请求帮助时框架渲染走 stdout其余场景框架渲染被重定向到 stderr见下文输出约定。服务层src/services/服务是Context.Service类导出NameShape类型与显式static readonly DefaultLayerLayer.effect/Layer.sync依赖通过Layer.provide注入。测试时用Service.of({ ... })构建替身没有生成的访问器或构造函数。核心服务一览服务用途ComposioUserContext认证状态——读写~/.composio/user-config.json合并环境变量ComposioSessionRepository创建 OAuth2 会话轮询直到linked状态ComposioToolkitsRepositoryAPI 客户端——拉取 toolkits、tools、trigger 类型校验版本ComposioToolkitsRepositoryCached基于基础仓库的装饰器带文件缓存与优雅降级NodeOsOS 抽象homedir、platform、archJsPackageManagerDetector检测 npm/pnpm/yarn/bun用于生成安装指引UpgradeBinary从 GitHub Releases 拉取最新版本下载并替换二进制OS 凭据存储使用兄弟包composio/cli-keyringmacOS Keychain / Linux Secret Service。用户上下文与凭据存储细节从 src/services/user-context.ts 的源码看API key 的存储遵循安全优先级环境变量优先COMPOSIO_USER_API_KEY经APP_CONFIG[USER_API_KEY]读取优先于一切磁盘存储。OS keyringkeyring 服务标识为com.composio.cli/default。CLI 配置中的security字段决定后端auto与json使用传统明文路径user_data.jsonkeychain-subprocess使用子进程后端默认keychain使用实验性 FFI 路径需要 Developer ID 签名的二进制以避免系统弹窗。明文回退当 keyring 不可用如无头 Linux / 容器 / CIAPI key 会以明文写入user_data.jsonCLI 始终偏好“继续工作 明文回退”而非崩溃。读取时若 keyring 命中会自动清理磁盘上的陈旧明文并迁移Migrating legacy api_key from user_data.json to the OS keyring。所有写盘操作经atomicWritePrivateFileString原子写入并确保私有文件权限ensurePrivateFileMode。缓存仓库与客户端同步ComposioToolkitsRepositoryCached是ComposioToolkitsRepository的 Layer 包装见 src/services/composio-clients-cached.ts。修改composio-clients.ts时必须同步检查缓存版本方法的新增、删除、签名变更与新导出的错误类型必须保持同步。每类方法需决策“缓存还是直通”——校验类方法通常直通拉取类方法通常缓存。缓存文件位于~/.composio/缓存目录toolkits.json、tools.json、tools-as-enums.json、trigger-types.json文件名定义于 src/constants.ts 的CACHE_FILENAMES。配置体系CLI 框架配置ComposioCliConfigsrc/cli-config.ts 定义了唯一的CliConfig定制export const ComposioCliConfig { builtIns: [GlobalFlag.Help], } satisfies PartialCliConfig.CliConfig.Service;要点Effect v4 的CliConfig.Service形状缩减为单一字段builtIns——Command.runWith在命令树每一层接受的内建全局标志列表。Composio 只保留--help/-h其余内建--version、--wizard、--completions、--log-level全部剔除。GlobalFlag.Version刻意缺席composio --version/-v被normalizeVersionFlag重写为version命令见上文保证三种拼写输出一致。v3 的autoCorrectLimit与isCaseSensitive在 v4 中没有对应配置v4 解析器无条件计算 “Did you mean?” 建议internal/auto-suggest.ts无禁用开关且不做任何大小写折叠精确匹配。这两点 Composio 都乐于接受因此不再复刻。Composio 不提供自定义CliOutput.Formatter——帮助渲染使用 v4 的CliOutput.defaultFormatter()。常量与环境变量前缀src/constants.ts 定义了APP_ENV_CONFIG_KEY_PREFIX COMPOSIO_用户环境变量前缀。DEBUG_OVERRIDE_ENV_CONFIG_KEY_PREFIX DEBUG_OVERRIDE_调试覆盖前缀。USER_CONFIG_FILE_NAME用户配置文件名user-config.json位于~/.composio/。CLI_CONFIG_FILE_NAME config.jsonCLI 通用配置。项目级文件project.json、.env每目录 CLI 配置覆盖、.composio/每目录 Composio 配置目录。版本来源发布构建将__COMPOSIO_CLI_RELEASE_VERSION__替换为精确的 GitHub release 版本私有包版本0.0.0-development仅是源码/开发回退绝不驱动二进制发布选择见 package.json 与IS_RELEASE_BUILD。环境相关 effectssrc/effects/app-config.ts 读取全部COMPOSIO_*环境变量src/effects/toolkit-version-overrides.ts 解析COMPOSIO_TOOLKIT_VERSION_NAMEver形式的覆盖供代码生成时指定非 latest 的 toolkit 版本。输出约定可组合的 CLI 输出stdout 只放数据遵循 Unix 惯例——人类可读装饰与机器可读数据分离stdout——只放数据ui.output()。可被管道 /$(...)/ file捕获。stderr——放全部装饰Clack spinner、日志、note、intro/outro。终端可见管道中不可见。三个流是相互独立的契约每个能力只依赖真正服务于它的流刻意不存在聚合的 “interactive” 标志见 src/services/terminal-ui.ts 的TerminalCapabilitiesPromptingcanPromptstdin.isTTY stderr.isTTY。stdin 必须能接收输入、stderr 必须能显示 Clack 提示。stdout 无关紧要管道化数据绝不能改变提示或认证行为——composio login | tee与有人值守登录行为一致。机器输出!stdout.isTTY。ui.output(data)仅在 stdout 被重定向管道、子 shell、文件或调用方传{ force: true }时写入。重定向 stdin 或 stderr 绝不能使数据泄漏到可见的 stdout 终端。DecorationcanDecoratestderr.isTTY。spinner、日志、note 只需要 stderr因此 stdin 或 stdout 被重定向时仍正常渲染。规则清单除output()外的所有TerminalUI方法经 Clack 的{ output: process.stderr }写 stderr且仅在 stderr 为 TTYcanDecorate时渲染。ui.output(data)仅在 stdout 被管道化或显式force时写 stdout。没有其他流参与该决策。提示ui.confirm、ui.select仅在canPrompt时运行否则不阻塞地回退到默认值confirm 默认trueselect 返回首个选项。管道化的 stdout 保持干净composio whoami | pbcopy只把 key 放进剪贴板——装饰仍在终端经 stderr 渲染仅当 stderr 本身被捕获时才被抑制。数据命令whoami、version、login、generate 等同时调用装饰stderr与ui.output()stdout。动作命令logout、upgrade不产生 stdout 数据——输出纯装饰。绝不把数据写 stderr 或把装饰写 stdout也绝不让程序行为认证路径、命令流程依赖 stdout 的 TTY 状态。新增命令时的判断标准“这个命令产生脚本应捕获的值吗”——是 →ui.output(value)ui.log.*/ui.note()否 → 仅装饰。此外cli-main.ts对显式请求的帮助--help/-h走 stdout其余场景把框架自身的帮助/错误渲染经 Console 服务重定向到 stderrlog覆写为error从而守住 “stdout 只放数据” 的契约。以version命令为例src/commands/version.cmd.ts普通模式同时调用ui.log.info(version)stderr 装饰与ui.output(version)stdout 数据--check模式输出结构化 JSON{current, latestStable, updateAvailable, checkStatus, lastChecked}到 stdout。Effect.ts 模式与规范生成器语法全仓库统一使用生成器语法Effect.gen(function* () { const service yield* ServiceName; // 解析依赖 const result yield* someEffect; // 等待计算 yield* Effect.log(message); return result; });关键模式Effect.all([...], { concurrency: unbounded })并行执行Layer.provide()组合依赖Effect.mapError()/Effect.catchTag()处理类型化错误Effect.scoped做资源清理。表驱动测试独立有限选择的全组合推荐用 Effect Array do 记法构建类型化笛卡尔积而非枚举每种情况或嵌套循环const cases pipe( Arr.Do, Arr.bind(firstAxis, () choices), Arr.bind(secondAxis, () choices) );每个Arr.bind为生成的用例增加一个独立轴。Effect 安全与迁移接缝绝不直接分支于 Effect 值内部的 tag 字段。使用所属模块的公开 refinement/matcherOption、Result、Exit、Cause、CliError、Match.valueTags做穷尽联合匹配或Predicate.isTagged做单个收窄守卫。不要把普通Error包进Effect.fail用于预期失败。为失败赋予有意义的Data.TaggedError类型带结构化字段与保留的 cause再用catchTag/catchTags恢复。Effect.die/Effect.dieMessage只留给不可能的不变量。将unknown、JSON、持久化状态、API 载荷视为信任边界。用effect/Schema解码或用Predicate收窄as断言不是校验手写结构守卫x in obj/typeof链不能替代 schema。effect/Schema是 CLI 的 schema 工具——不要在 CLI 中引入 zodzod 是 SDK 包与 docs 的约定。不要窥探effect/unstable/cli的私有内部parser 状态、HelpDoc字符串形状、CliError建议机制。Command.runWith自行渲染帮助与解析/校验错误命令树自省必须停留在公开的Command.Any表面name、alias、subcommands。CliError.InvalidValue接受结构化的{ option, value, expected, kind }字段而非自由文本消息——需要自定义校验消息的命令抛本地Data.TaggedError如 src/commands/login.cmd.ts 的LoginOptionError交给effect-errors美化打印而非手写CliError。优先Effect.mapError、Effect.matchEffect与类型化恢复而非把不同失败压平为单一消息错误的Effect.catch块v4 中catchAll的新名称。Effect 边界策略平台访问一律走服务node:path、node:fs、node:os、node:child_process、process.env、try/catch在src/中被 oxlint 禁止。合规替代需求使用路径运算join/resolve/dirname/…effect/Path的Path服务const path yield* Path.Path文件系统 I/Oeffect/FileSystem的FileSystem服务const fs yield* FileSystem.FileSystemhomedir / tmpdir / platform / archNodeOs服务src/services/node-os.ts唯一的node:os边界子进程effect/unstable/process的ChildProcess/ChildProcessSpawner比 CLI 存活更久的子进程经 src/services/detached-process.ts环境变量读取effect/Config同步易失败操作JSON.parse、new URL、JSON.stringifyResult.tryData.TaggedErrorJSON 记录经parseJsonRecordsrc/utils/parse-json.ts按子路径导入平台模块import * as FileSystem from effect/FileSystem、import * as BunFileSystem from effect/platform-bun/BunFileSystem绝不从effect/platform-bun包桶导入oxlint 在src/中拒绝包桶导入。转换优先级(1) 在现有 Effect 代码内 yield 服务(2) 当调用方由 Effect 托管时把普通 helper 转换为 Effect注意 v4 中Result不是Effect不能直接 yield须在Effect.gen内用Effect.fromResult(...)提升(3) 把已解析的服务实例如Path.Path、FileSystem.FileSystem作为普通参数传入无法成为 Effect 的同步回调或 promise 管线见tool-permissions.ts、generation/typescript/virtual-compiler-host.ts(4) 自我提供 Layer 的模块在栈中加入BunPath.layer/BunFileSystem.layer/NodeOs.Default。允许绕过服务的唯一代码位于声明的运行时边界bin.ts引导、子进程伴生运行时run-helpers-runtime.ts、run-subagent-*打包为在用户派生进程中运行的.mjs、导入时 UI 设置ui/colors.ts、ui/redact.ts、环境变量写入与全环境枚举effect/Config无法表达、以及父子composio run进程间的 spawn 时环境握手。每个此类边界都带内联// eslint-disable-next-line rule -- reason注释并登记在lint-boundaries.json。强制执行pnpm run validate:boundaries属于pnpm testCI 阻塞在src/中的任何 eslint-disable 缺失于 manifest、缺少-- reason、或使用文件级形式时失败。不得新增 disable——应穿透服务。若代码确实无法在 Effect 运行时内运行那是新边界用pnpm run validate:boundaries -- --update重新生成 manifest 并在 PR 中说明边界理由。代码生成管线composio generate {ts,py}composio generate的核心流程src/generationFetch——拉取 toolkits、tools、trigger 类型可用--toolkits过滤。Index——按 toolkit 前缀分组为ToolkitIndex见 src/generation/create-toolkit-index.ts。工具与 trigger 类型按其 slug 前缀归属对应 toolkit版本覆盖versionMap来自COMPOSIO_TOOLKIT_VERSION_NAME环境变量仅对非 latest 版本生效。Generate——用composio/ts-builders的 AST builder 构建 TS/Python 源码TypeScript 路径见 src/generation/typescript/generate.ts支持emitSingleFile单文件与多文件两种输出index 汇总文件为index.ts。Transpile——可选地把 TS 转译为 ESM JS供composio/core/generated使用。--type-tools包含完整类型定义withTypes: true路径工具以带 slug 的完整Tool对象而非仅枚举名出现。TS 生成依赖 JS compiler APIvirtual-compiler-host.ts这正是 TypeScript 依赖被固定在 TS6 的原因。数据模型Effect Schemasrc/models 定义 Effect Schema 模型配JSONTransformSchema()生成的fromJSON/toJSONhelperToolkit、Tool、TriggerType、UserData、Session。这些模型同时服务于磁盘持久化如user_data.json的 schema 解码与 API 载荷的解码体现“把持久化状态与 API 载荷视为信任边界、用 schema 解码”的规范。其他工程实践客户端缓存同步修改src/services/composio-clients.ts时须在同一变更中检查composio-clients-cached.ts见上文“缓存仓库与客户端同步”。CLI Demo 录制VHS面向用户的 CLI 命令在改动文档化工作流、引入新可见命令面或需要发布说明 demo 覆盖时应附带 VHS 录制SVG asciicast。流程在recordings/recordings.yaml添加条目字段name、command、description、sleepAfterEnter、长输出用height: dynamic。运行bun scripts/record.ts——需要COMPOSIO_API_KEY且vhs在PATH上。输出落在recordings/{tapes,svgs,ascii}/group/name.{tape,svg,ascii}。发布工作流推送next分支并触碰 CLI 路径会自动发布滚动 beta。常规 stable 路径通过promote-stableworkflow action 把已测试的 beta 提升为 stable。composio/cli与composio/cli-local-tools被 Changesets 忽略永远不要为这两个包添加 changeset否则会卡住 TypeScript SDK 发布 action。面向人的 CLI 变更直接写入CHANGELOG.md。package.json使用私有开发 sentinel0.0.0-development绝不是二进制发布权威。有意的 minor/major 发布应派发build-beta并带可选版本输入验证该 beta 后正常 promote。关键工作流文件.github/workflows/build-cli-binaries.yml二进制构建与发布、.github/workflows/cli.test-installation.yml发布后安装冒烟测试、.github/scripts/cli-release/resolve-release-target.shbeta/stable 目标解析。关键依赖速览effect固定4.0.0-rc.112effect/cli与effect/platform不再是独立包已折叠进effect的 barrel 与effect/unstable/{cli,http,process}、effect/platform-bun、effect/vitest同款精确 pin、clack/prompts终端 UI默认写 stderr、picocolors、composio/clientComposio API、composio/core类型、composio/ts-buildersAST 生成、composio/cli-keyringOS 凭据存储、composio/cli-local-tools本地 toolkit 定义、composio/json-schema-to-effect-schema、semver、open、extract-zip完整清单见 ts/packages/cli/package.json。此外仓库将 Effect 依赖源码以只读子模块固定在ts/vendor/effect/effect4.0.0-rc.112发布 commit其中packages/effect/src/unstable/cli/、unstable/http/、unstable/process/与packages/platform/bun/src/是查阅 v4 API 行为的第一手参考ts/vendor/effect/migration/提供官方 v3→v4 迁移指南。这使 CLI 的框架行为如Command.runWith的渲染契约可在仓库内直接溯源验证。结语composio/cli展示了将 Effect 生态的服务化架构、类型化错误与结构化并发应用到 CLI 工程的完整范式stdout/stderr独立契约保证脚本可组合性Layer 依赖注入保证可测试性schema 解码守住信任边界边界策略把平台访问收拢到受控服务。无论你是要扩展该 CLI 的命令面、把项目迁移到 Effect v4还是设计自己的现代 CLI这份架构都可以作为直接参照——建议从 ts/packages/cli/src/bin.ts 与 ts/packages/cli/src/cli-main.ts 开始阅读结合 ts/packages/cli/CLAUDE.md 与仓库根 AGENTS.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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价