
1. 项目概述CLI-Anything 不是又一个命令行工具而是一套“让任何能力长出命令行接口”的方法论我第一次在 GitHub 上看到 CLI-Anything 这个名字时下意识以为是某个新出的 Python CLI 框架——类似 Click 或 Typer 的竞品。但花了一下午读完它的 README 和核心源码后我立刻把本地所有正在用的 CLI 工具都暂停了。它根本不是“另一个 CLI 框架”而是一套反向工程思维下的 CLI 接口生成范式你不用从零写 argparse、不纠结子命令嵌套层级、不反复调试 help 文本格式而是把已有的功能模块哪怕只是几行 Python 函数、一个 HTTP API 封装、一段 Shell 脚本逻辑甚至 Obsidian 插件里的一个数据处理函数当作“原子能力”CLI-Anything 会自动为它生成符合 POSIX 标准、支持 Tab 补全、带完整 --help 输出、可 pip install 的独立命令行程序。这背后直击的是开发者日常最真实的痛点我们写了大量实用脚本——比如每天拉取 Jira 状态生成日报、把 Excel 表格转成 Markdown 表格、批量重命名照片按拍摄时间戳、用正则清洗日志文件……这些脚本往往散落在个人 bin 目录、IDE 的 Run Configuration 里或者干脆藏在某个项目的 scripts/ 子目录中。它们功能明确、逻辑清晰但缺乏统一入口、无法被其他工具链调用、不能被非技术同事使用、更谈不上版本管理和跨环境部署。CLI-Anything 就是来解决这个“最后一公里”问题的它不关心你底层用的是 requests 还是 httpx是 pandas 还是 polars是 subprocess.run 还是 asyncio.create_subprocess_exec它只关心“你这段逻辑的输入是什么输出是什么有哪些可配置参数用户希望怎么调用它”——然后一键生成一个真正意义上的 Unix 风格 CLI 工具。关键词里反复出现的 “agent-native” 并非营销话术。它意味着 CLI-Anything 生成的命令天然适配当前 Agent 工作流你可以把它直接注册进 Claude 的 Tool Calling 列表或作为 MCPModel Control Protocol服务端的一个 endpoint甚至嵌入到 VS Code 的 Task Runner 中。它不强制你改写业务逻辑而是让你的已有代码“即插即用”地接入智能体生态。而那些热词里高频出现的 “codex cli”、“claude cli”、“obsidian cli 安装包”恰恰印证了这个需求的普遍性——大家不是不想用 CLI而是被 CLI 的开发门槛卡住了。CLI-Anything 把“写 CLI”这件事从“需要理解 shell 解析、信号处理、进程管理”的系统级工程降维成“描述清楚你的函数签名和用途”的产品设计任务。它适合三类人一是写脚本但懒得封装的工程师二是想快速验证想法的数据分析师三是需要把内部工具开放给非技术用户的团队负责人。你不需要精通 Python 元编程但得知道自己的函数要接收什么参数、返回什么结果——这就够了。2. 核心设计思路拆解为什么是“Anything”而不是“Another CLI Framework”2.1 本质差异从“构建 CLI”到“暴露能力”传统 CLI 框架如 Click、Typer、Argparse的核心工作流是你先定义命令结构 → 再填充业务逻辑 → 最后打包发布。这是一个自上而下的、以 CLI 形态为起点的设计过程。而 CLI-Anything 的工作流是你先有业务逻辑任意形态→ CLI-Anything 分析其接口 → 自动生成 CLI 包装层 → 最后发布为标准 Python 包。这是一个自下而上的、以能力本身为起点的暴露过程。这个差异看似微小实则决定了整个工具链的适用边界。举个具体例子假设你有一个现成的 Python 函数用于从本地 SQLite 数据库中查询某张表的统计摘要def get_table_summary(db_path: str, table_name: str, top_n: int 10) - dict: import sqlite3 conn sqlite3.connect(db_path) cursor conn.cursor() cursor.execute(fSELECT COUNT(*) FROM {table_name}) total cursor.fetchone()[0] cursor.execute(fSELECT * FROM {table_name} LIMIT {top_n}) sample cursor.fetchall() conn.close() return {total_rows: total, sample_data: sample}用 Click 实现 CLI你需要手动写import click click.command() click.option(--db-path, requiredTrue, helpPath to SQLite database) click.option(--table-name, requiredTrue, helpName of the table to query) click.option(--top-n, default10, typeint, helpNumber of rows to sample) def cli_get_table_summary(db_path, table_name, top_n): result get_table_summary(db_path, table_name, top_n) print(json.dumps(result, indent2))再加click.group()嵌套、click.argument、错误处理、类型转换……一套下来业务逻辑代码占比可能不到 30%。而 CLI-Anything 只需一个 YAML 配置文件cli-config.yamlname: db-summary description: Get summary statistics and sample data from a SQLite table function: my_module:get_table_summary arguments: - name: db_path type: str required: true help: Path to SQLite database file - name: table_name type: str required: true help: Name of the table to query - name: top_n type: int default: 10 help: Number of rows to include in sample output_format: json然后执行cli-anything build --config cli-config.yaml它会自动生成一个完整的db-summary命令支持db-summary --help、db-summary --db-path data.db --table-name users --top-n 5并自动处理参数类型校验、缺失值提示、JSON 格式化输出。你完全不用碰 Click 或 Typer 的任何 API。这就是“Anything”的底气——它不绑定任何框架不侵入你的代码只做一件事把函数签名映射为 CLI 接口规范。2.2 架构分层三层抽象隔离关注点CLI-Anything 的内部架构非常清晰分为三个严格隔离的层次能力层Capability Layer这是你的原始代码。它可以是一个.py文件里的函数一个已安装 Python 包里的模块一个通过subprocess调用的外部二进制程序如ffmpeg、jq甚至是一个 RESTful API 的 URLCLI-Anything 支持将 HTTP 请求模板化为 CLI 命令。这一层完全不受 CLI-Anything 约束你用什么语言、什么风格写都行只要能被 Python 调用或描述清楚输入输出即可。契约层Contract Layer这是 CLI-Anything 的核心价值所在由 YAML/JSON 配置文件定义。它不包含任何业务逻辑只声明三件事能力定位function: my_package.module:my_func或command: /usr/bin/ffmpeg或api: https://api.example.com/v1/process输入契约每个参数的名称、类型str/int/bool/list/dict、是否必需、默认值、帮助文本、约束条件如min1,max100,pattern: ^[a-z]$输出契约期望的输出格式json/text/table/raw、是否需要结构化解析如对 JSON 响应提取特定字段、错误码映射规则。接口层Interface LayerCLI-Anything 根据契约层的描述动态生成一个符合 PEP 517 标准的 Python 包。这个包里包含一个__main__.py作为命令入口点一个setup.py或pyproject.toml定义包元数据和console_scripts入口可选一个cli-anything专用的cli.py负责加载契约、解析参数、调用能力、格式化输出。这种分层带来的最大好处是可维护性与可测试性。你可以独立测试能力层单元测试你的get_table_summary函数独立验证契约层用cli-anything validate --config config.yaml检查 YAML 语法和逻辑一致性而接口层完全是生成的、无需人工维护的胶水代码。当你的业务逻辑升级时只需更新能力层和可能调整契约层接口层一键重建即可。这彻底避免了传统方式中“改一行业务逻辑要同步修改七八处 CLI 参数解析和 help 文本”的脆弱耦合。2.3 为什么选择 Python 作为宿主语言网络热词里 “python” 出现频率极高这不是偶然。CLI-Anything 选择 Python 作为唯一宿主语言是经过深思熟虑的工程权衡而非简单跟风生态广度决定覆盖能力Python 拥有最庞大的“能力仓库”。从pandas处理表格、requests调用 API、Pillow处理图像到scapy网络抓包、sqlalchemy操作数据库再到transformers调用大模型——几乎所有你能想到的数据处理、系统管理、AI 应用场景都有成熟的 Python 库支撑。CLI-Anything 作为“能力暴露器”必须站在巨人的肩膀上。如果它用 Rust 或 Go虽然性能更好但会瞬间失去 90% 的潜在能力来源变成一个只能包装自己写的二进制程序的工具。动态性匹配“Anything”哲学CLI-Anything 的核心是“动态分析函数签名”。Python 的inspect模块可以轻松获取任意可调用对象的参数名、类型注解、默认值、文档字符串。这种运行时反射能力是静态语言难以优雅实现的。例如它能自动从def process_file(path: Path, encoding: str utf-8) - list[str]:中提取出path类型Path需转换为str、encoding类型str默认utf-8并生成对应的 CLI 选项--path和--encoding。这种“零配置推断”极大降低了使用门槛。部署简易性降低落地阻力一个 CLI-Anything 生成的命令最终就是一个标准的pip install包。用户不需要安装额外的运行时如 Node.js 的nvm、Go 的go env也不需要担心不同平台的二进制兼容性node_modules\opencode\cli\bin\opencode.exe 与你运行的 windows 版本不兼容这类报错在 Python 生态里几乎绝迹。pip install my-cli-tool之后my-cli-tool --help就能立刻工作。这对于推广到非专业用户如产品经理、运营、设计师至关重要。他们不需要懂什么是venv什么是PATH只需要一个命令就能解决问题。提示CLI-Anything 本身并不强制要求你的能力层也用 Python。它支持通过command类型调用任意系统命令或通过api类型调用 HTTP 服务。但它的“最佳体验路径”即零配置、强类型、自动补全是为 Python 能力层深度优化的。如果你的能力是 Java 写的CLI-Anything 会建议你先用subprocess封装一个 Python 接口这比直接用 Java 写 CLI 更符合它的设计哲学。3. 核心细节解析与实操要点从零开始构建你的第一个 CLI3.1 环境准备与基础安装CLI-Anything 的安装极其简单因为它本身就是一个标准的 Python 包。你不需要下载二进制文件也不需要配置复杂的环境变量。前提是你的系统上已经安装了 Python推荐 3.8和 pip。如果你还不确定打开终端执行python3 --version # 如果输出类似 Python 3.11.8说明已安装 # 如果提示 command not found请先去 python.org 下载安装最新版 Python确认 Python 可用后执行pip install cli-anything这条命令会从 PyPI 安装 CLI-Anything 的核心工具。安装完成后验证是否成功cli-anything --version # 应该输出类似 cli-anything 0.8.2 cli-anything --help # 查看所有可用的子命令这里有个关键细节CLI-Anything 的安装不依赖于你项目中使用的 Python 版本。它被设计为一个全局可用的开发工具Developer Tool就像pip、black、mypy一样。你可以在任何 Python 项目之外使用它来生成 CLI。这意味着你不需要在每个要包装的项目里都pip install cli-anything只需要在你的开发机上装一次即可。这也是它区别于某些“项目内 CLI 框架”的重要特征——它服务于你的整个工作流而非单个项目。注意不要试图用conda install cli-anything。目前 CLI-Anything 主要维护在 PyPI 上conda-forge 通道尚未同步。如果你习惯用 conda可以先激活你的目标环境再用pip install cli-anything它会正确安装到当前 conda 环境中。3.2 创建你的第一个能力一个极简的 Python 函数为了演示我们创建一个最简单的“能力”一个计算两个数字之和的函数。新建一个文件math_utils.py# math_utils.py def add(a: float, b: float) - float: Add two numbers. Args: a: The first number. b: The second number. Returns: The sum of a and b. return a b这个函数非常普通但它包含了 CLI-Anything 所需的所有信息函数名add将成为 CLI 命令的默认名称。参数a和b都有类型注解floatCLI-Anything 会据此生成--a和--b选项并进行数值校验。文档字符串docstring其中的Args和Returns部分会被自动提取作为 CLI 的--help输出内容。现在这个函数就是你的“能力”。它独立存在不依赖 CLI-Anything你可以像往常一样在 Python 脚本里from math_utils import add来使用它。CLI-Anything 只是“发现”并“包装”它。3.3 编写契约文件YAML 配置详解CLI-Anything 的灵魂在于契约文件。我们为add函数创建一个add-cli.yaml# add-cli.yaml name: calc-add # 生成的 CLI 命令名将覆盖函数名 add description: Calculate the sum of two numbers function: math_utils:add # 模块名:函数名路径相对于当前工作目录 arguments: - name: a type: float required: true help: The first number to add - name: b type: float required: true help: The second number to add output_format: text # 输出格式text 表示直接打印返回值这个 YAML 文件的每一项都值得深究name: 这是最终生成的命令名。calc-add比add更具描述性避免了与内置函数名冲突。你可以随意命名它与函数名无关。description: 这段文字会出现在calc-add --help的第一行是用户对这个命令的“第一印象”。function: 这是关键定位符。math_utils:add表示在当前目录或 Python path下查找math_utils.py文件并从中导入add函数。如果math_utils.py在子目录src/下这里就写src.math_utils:add。CLI-Anything 会像 Python 解释器一样解析这个路径。arguments: 这是一个列表定义了 CLI 的所有输入参数。每个参数对象包含name: 必须与函数参数名完全一致大小写敏感。type: 指定参数类型。CLI-Anything 支持str,int,float,bool,list,dict。对于boolCLI-Anything 会自动将其转换为“开关式”选项如--verbose无需传值。required:true表示该参数是必需的用户不提供会报错false或省略则表示可选。help: 这段文字会出现在calc-add --help的参数说明部分是用户理解如何使用的关键。实操心得我最初写契约文件时总想把所有参数都设为required: true结果发现这反而降低了 CLI 的易用性。比如一个处理文件的函数--input是必需的但--output可以有默认值如stdout--format可以有默认值如json。在arguments列中为可选参数显式指定default字段能让用户少敲很多字。例如给b参数加一个默认值default: 0.0那么calc-add --a 5就等价于calc-add --a 5 --b 0。3.4 生成与安装 CLI一步到位一切就绪后执行生成命令cli-anything build --config add-cli.yamlCLI-Anything 会开始工作读取add-cli.yaml。根据function字段动态导入math_utils:add函数。分析函数签名与 YAML 中的arguments进行比对和校验。生成一个名为dist/的目录里面包含一个标准的 Python wheel 包.whl文件例如calc_add-0.1.0-py3-none-any.whl。生成完成后你就可以像安装任何 Python 包一样安装它pip install dist/calc_add-0.1.0-py3-none-any.whl安装成功后你的新命令calc-add就正式进入了系统的命令行环境。现在你可以随时使用它# 查看帮助 calc-add --help # 正常使用 calc-add --a 3.14 --b 2.71 # 因为 a 和 b 都是 required不提供会报错 calc-add --a 10 # Error: Missing required argument: b提示cli-anything build命令还支持--output-dir参数可以指定生成的 wheel 包放在哪里。默认是dist/这是 Python 打包的标准约定方便后续上传到私有 PyPI 仓库。4. 实操过程与核心环节实现进阶功能与真实场景复现4.1 处理复杂参数列表、字典与文件路径现实中的 CLI 往往需要处理更复杂的输入。CLI-Anything 对此有完善的原生支持。我们扩展math_utils.py添加一个计算多个数字平均值的函数# math_utils.py (追加) def average(numbers: list[float]) - float: Calculate the average of a list of numbers. Args: numbers: A list of numbers. Returns: The arithmetic mean. if not numbers: raise ValueError(Cannot calculate average of empty list) return sum(numbers) / len(numbers)对应的契约文件average-cli.yamlname: calc-average description: Calculate the average of a list of numbers function: math_utils:average arguments: - name: numbers type: list required: true help: List of numbers to average. Use space-separated values. # CLI-Anything 会自动将 1 2 3 4 解析为 [1.0, 2.0, 3.0, 4.0] output_format: text注意type: list这一行。CLI-Anything 会自动将命令行中空格分隔的多个值如calc-average --numbers 1 2 3 4组装成一个 Pythonlist并尝试根据numbers参数的类型注解这里是list[float]进行元素类型转换。这比手动用argparse的nargs和typefloat组合要直观得多。再来看一个更常见的场景处理文件。我们添加一个函数读取一个文本文件并统计行数# math_utils.py (追加) def count_lines(file_path: str) - int: Count the number of lines in a text file. Args: file_path: Path to the input file. Returns: The number of lines. with open(file_path, r, encodingutf-8) as f: return len(f.readlines())契约文件count-lines-cli.yamlname: file-lines description: Count the number of lines in a text file function: math_utils:count_lines arguments: - name: file_path type: str required: true help: Path to the input text file # CLI-Anything 会自动检查文件是否存在如果 type 是 str 且参数名含 path 或 file output_format: textCLI-Anything 有一个贴心的“启发式检查”机制。当你定义一个type: str的参数且其name包含path、file、dir、folder等关键词时它会在解析参数后自动调用os.path.exists()检查该路径是否存在。如果不存在会给出清晰的错误提示而不是让open()抛出一个晦涩的FileNotFoundError。这极大地提升了 CLI 的用户体验。4.2 输出格式化从 raw 到 table满足不同需求output_format是契约文件中一个强大的开关。我们之前一直用text它只是简单地print()函数的返回值。但 CLI-Anything 还支持更多格式json: 将返回值必须是可 JSON 序列化的对象格式化为缩进良好的 JSON 字符串。这对于脚本间管道传输pipe或被其他程序解析非常有用。raw: 直接输出返回值的str()表示不做任何格式化。适用于返回值本身就是字符串且你希望保持其原始格式如多行文本、ANSI 颜色码。table: 这是为list[dict]类型返回值量身定制的。它会将一个字典列表渲染成一个对齐美观的 ASCII 表格。我们来演示table格式。创建一个新函数list_users模拟从数据库查询用户列表# math_utils.py (追加) def list_users() - list[dict]: Simulate listing users from a database. Returns: A list of user dictionaries with id, name, and email. return [ {id: 1, name: Alice Johnson, email: aliceexample.com}, {id: 2, name: Bob Smith, email: bobexample.com}, {id: 3, name: Charlie Brown, email: charlieexample.com}, ]契约文件users-cli.yamlname: list-users description: List all users in the system function: math_utils:list_users arguments: [] output_format: table # CLI-Anything 会自动识别返回值是 list[dict]并用第一项的 keys 作为表头生成并安装后运行list-users你会看到一个整齐的表格------------------------------------------ | id | name | email | ------------------------------------------ | 1 | Alice Johnson | aliceexample.com | | 2 | Bob Smith | bobexample.com | | 3 | Charlie Brown | charlieexample.com | ------------------------------------------实操心得table格式是 CLI-Anything 最惊艳的功能之一。我曾用它包装了一个内部的 Kubernetes 资源查询脚本原本返回的是一个巨大的嵌套字典用json格式输出运维同事抱怨“眼睛看花了”。改成table后他们立刻就能在终端里一眼看清NAME,READY,STATUS,RESTARTS这些关键列。这证明了 CLI-Anything 的价值不仅在于“能用”更在于“好用”。4.3 处理外部命令与 HTTP API打破 Python 边界CLI-Anything 的“Anything”还体现在它能包装非 Python 的能力。我们来看两个例子。包装外部命令ffmpeg 假设你经常需要用ffmpeg转换视频格式但记不住复杂的参数。你可以用 CLI-Anything 创建一个简化版的video-convert命令。创建ffmpeg-cli.yamlname: video-convert description: Convert video files using ffmpeg command: ffmpeg # 直接调用系统命令 arguments: - name: input type: str required: true help: Input video file path - name: output type: str required: true help: Output video file path - name: preset type: str default: fast help: Encoding preset (e.g., fast, medium, slow) environment: # 可选设置子进程的环境变量 FFMPEG_LOG_LEVEL: quiet # CLI-Anything 会将 --input /in.mp4 --output /out.mp4 --preset slow # 转换成 ffmpeg -i /in.mp4 -preset slow /out.mp4CLI-Anything 会智能地将 CLI 参数映射为外部命令的参数。它遵循一个简单的规则--arg_name映射为-arg_name单字符或--arg_name多字符并自动处理-i这样的输入标志。你不需要写任何胶水代码。包装 HTTP APIGitHub Repos API 我们创建一个github-repos命令用来列出某个用户的公开仓库。创建github-cli.yamlname: github-repos description: List public repositories for a GitHub user api: https://api.github.com/users/{user}/repos # URL 模板{user} 是占位符 arguments: - name: user type: str required: true help: GitHub username - name: per_page type: int default: 30 help: Number of repositories per page (max 100) - name: page type: int default: 1 help: Page number of results headers: # 可选设置 HTTP 请求头 Accept: application/vnd.github.v3json User-Agent: CLI-Anything/0.1 output_format: table # CLI-Anything 会自动将 --user octocat --per_page 10 替换为 # GET https://api.github.com/users/octocat/repos?per_page10page1生成并安装后运行github-repos --user torvalds你就能看到 Linus 的所有公开仓库以表格形式呈现。注意对于 API 调用CLI-Anything 会自动处理 HTTP 状态码。如果 API 返回 4xx 或 5xx 错误它会捕获响应体并以Error: ...的格式输出而不是让整个命令静默失败。这对于调试和用户反馈至关重要。5. 常见问题与排查技巧实录踩过的坑与独家避坑指南5.1 典型问题速查表问题现象可能原因排查与解决方法Unable to locate the codex cli binary or required runtime components. Check...这是另一个工具Codex CLI的报错与 CLI-Anything 无关。网络热词中混杂了大量无关信息。立即忽略。CLI-Anything 的错误信息格式完全不同通常以CLI-Anything Error:开头。遇到此报错请确认你执行的是cli-anything命令而非codex。ModuleNotFoundError: No module named xxxCLI-Anything 在解析function时找不到指定的 Python 模块。1. 检查function字段的路径是否正确package.module:function。2. 确认该模块所在的目录在 Python 的sys.path中。最简单的方法是将模块文件放在 CLI-Anything 命令执行的当前工作目录下。3. 如果模块在子目录确保子目录中有__init__.py文件即使是空的使其成为 Python 包。Error: Missing required argument: xxx命令行中遗漏了 YAML 中标记为required: true的参数。查看xxx --help输出确认参数名拼写是否正确CLI-Anything 默认将_转换为-所以file_path参数在命令行中是--file-path。如果参数名含下划线CLI-Anything 会自动将其转换为连字符这是标准做法无需在 YAML 中手动写--file-path。生成的 CLI 命令执行后无输出或输出格式混乱output_format设置不当或函数返回值类型与预期不符。1. 检查函数的return语句确保返回值类型与output_format匹配如table要求返回list[dict]。2. 临时将output_format改为raw查看原始返回值确认其结构。Tab补全不工作CLI-Anything 生成的命令默认支持 Bash/Zsh 的complete补全但需要手动启用。在你的 shell 配置文件如~/.bashrc或~/.zshrc中添加eval $(register-python-argcomplete calc-add)将calc-add替换为你的命令名然后执行source ~/.bashrc。5.2 我踩过的几个深坑与解决方案坑一类型注解的“陷阱”我曾经写过一个函数def process_data(data: str) - dict:本意是接收一个 JSON 字符串。但在契约文件中我把data的type写成了str。结果 CLI-Anything 把用户输入的--data {key: value}当作一个普通的字符串没有做任何 JSON 解析。函数收到的还是字符串导致后续json.loads()报错。解决方案CLI-Anything 提供了type: json这个特殊类型。当你在 YAML 中将参数type设为json时它会自动尝试用json.loads()解析输入的字符串并将解析后的 Python 对象dict/list传递给函数。所以正确的契约应该是- name: data type: json # 关键不是 str required: true help: JSON string to process坑二Windows 下的路径分隔符问题在 Windows 上我用function: src.utils:my_func但src目录下没有__init__.py。CLI-Anything 在 Windows 上有时会因为路径分隔符\vs/的处理问题无法正确导入模块报ModuleNotFoundError。解决方案最可靠的方法是永远在包的根目录下放置一个空的__init__.py文件。即使你的模块是单个.py文件也把它放在一个有__init__.py的目录里。这样无论在 Linux、macOS 还是 Windows 上src.utils都能被 Python 解释器稳定识别为一个包。坑三--help输出的文档字符串不完整我发现my-command --help只显示了函数的第一行 docstring而Args和Returns部分没有出现。解决方案CLI-Anything 默认只提取 docstring 的第一行summary line。要让Args和Returns也出现在--help中你需要在契约文件中显式开启detailed_help: truename: my-command description: ... function: ... detailed_help: true # 添加这一行 arguments: ...开启后--help会显示完整的 docstring包括所有Args、Returns、Raises等部分这对复杂命令的用户来说是救命稻草。5.3 性能与安全边界提醒CLI-Anything 是一个开发期工具它的核心价值在于提升开发效率和 CLI 的可维护性而非运行时性能。因此在使用时需要有清晰的边界意识不要用它包装计算密集型任务CLI-Anything 的启动本身有 Python 解释器加载、YAML 解析、参数校验等开销。对于一个毫秒级完成的函数CLI-Anything 的启动开销可能占到 90%。它最适合包装 I/O 密集型任务文件读写、网络请求、数据库查询这些任务本身的耗时远大于 CLI 启动开销。警惕“能力”中的安全风险CLI-Anything 会忠实地执行你定义的function或command。如果你的函数里有os.system(user_input)或subprocess.run(..., shellTrue)并且user_input来自 CLI 参数那这就是一个经典的命令注入漏洞。CLI-Anything 不会、也不能替你做安全审计。**它暴露的是你的能力安全责任永远