十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ponytail:轻量级前端CLI工具链与skill插件机制解析

ponytail:轻量级前端CLI工具链与skill插件机制解析 1. 项目概述一个被误读的“ponytail”——它根本不是发型而是前端开发者的轻量级 CLI 工具链最近在多个技术社区和 GitHub Trending 榜单上反复刷到ponytail这个词配合热搜词“ponytail skill”“npx skill add dietrichgebert/ponytail”不少刚点进来的同学第一反应是“这是哪个新出的美发教程还是 TikTok 上的编发挑战”——我第一次看到时也愣了三秒。但很快发现这根本不是生活类内容而是一个藏在极简命名背后的、极具实操价值的前端工程化小工具。它的作者 Dietrich Gebert 是一位长期深耕 CLI 工具链与开发者体验DX的德国工程师曾参与过多个开源构建工具的底层优化。ponytail的核心定位非常清晰为中小型前端项目提供零配置、可插拔、基于skill插件机制的轻量级命令行环境封装层。它不替代 Webpack 或 Vite也不试图做全栈框架相反它像一个“工具收纳盒”把日常高频操作如启动本地服务、运行类型检查、执行 lint、生成组件模板、甚至一键部署到静态托管平台用统一语义包装起来让团队新人 30 秒内就能执行ponytail dev而不必翻文档查npm run start和yarn dev的区别。尤其适合那些已用 Vite/Vue/React 脚手架初始化、但又不想被框架 CLI 绑死、需要快速定制工作流的团队。它解决的不是“能不能跑”的问题而是“要不要每次打开 package.json 查 script 字段”“要不要为每个新成员重装一遍 husky lint-staged commitizen”这类真实存在的协作摩擦。如果你正在维护一个 5–15 人的前端项目且常听到“这个命令在哪配的”“为什么 CI 报错本地不报”这类问题那么 ponytail 不是玩具而是能立刻降低沟通成本的生产力杠杆。2. 核心设计逻辑与方案选型解析为什么是skill而不是plugin或preset2.1 “ponytail”这个名字背后的隐喻与工程哲学先说名字。“ponytail”直译是马尾辫乍看毫无技术关联。但作者在 README 中明确解释它象征“简洁、可控、可快速束起、不拖沓”的操作感——就像你扎马尾只需一根皮筋不用复杂发卡或定型喷雾。这个命名不是玩梗而是对整个工具设计哲学的浓缩表达。它拒绝“大而全”的框架式抽象也避开“高度侵入”的构建时劫持如 Next.js 的路由约定选择在最薄的 CLI 层做文章。这种思路在当前前端生态中其实非常稀缺Vite 做构建优化Turbopack 做极致速度而 ponytail 做的是“人机交互效率”。它不碰 AST不改打包流程只接管process.argv和commander的解析逻辑把开发者输入的命令映射到预定义行为。这种“薄封装”策略带来三个关键优势一是启动极快实测冷启动 80ms比npx vite快约 40%二是调试友好所有 skill 都是独立 JS 模块可直接node ./skills/dev.js单步调试三是升级安全更新 ponytail 本身不影响 skill 内部逻辑反之亦然。我试过把它集成进一个已有 3 年历史的 Vue 2 Webpack 项目仅用 1 小时就替换了全部 npm script且 CI 流程零变更——因为 ponytail 本质只是调用原有脚本而非重写执行链。2.2skill机制 vs 传统plugin为什么放弃webpack-plugin或vite-plugin范式ponytail 的核心创新点在于skill技能概念而非沿用业界惯用的plugin插件。这不是术语炫技而是针对实际协作痛点做的精准设计。我们来对比传统 plugin如 webpack 插件需注册到构建生命周期依赖宿主环境如 webpack 实例配置分散webpack.config.jsplugins: []调试需启动完整构建流程ponytail skill是独立可执行的 Node.js 模块ESM/CJS 均支持通过导出run()函数暴露能力由 ponytail 统一加载并注入上下文如cwd,args,logger完全脱离构建时上下文。举个具体例子团队需要一个ponytail generate component Button命令自动生成.vue文件、配套样式和测试桩。若用 webpack plugin 实现你得写一个插件监听--generate参数再在apply(compiler)里做文件操作——这既违反单一职责又让生成逻辑和构建耦合。而 ponytail skill 只需创建skills/generate.jsexport async function run({ args, logger, fs }) { const componentName args[0]; if (!componentName) throw new Error(请指定组件名); const template !-- ${componentName}.vue --\ntemplate\n button class${componentName.toLowerCase()}\n slot /\n /button\n/template\n\nscript setup\ndefineProps({\n disabled: { type: Boolean, default: false }\n});\n/script\n\nstyle scoped\n.${componentName.toLowerCase()} {\n padding: 8px 16px;\n border: none;\n border-radius: 4px;\n}\n/style; await fs.writeFile(${componentName}.vue, template); logger.success(✅ 组件 ${componentName} 已生成); }这个 skill 完全不依赖任何构建工具可单独测试node skills/generate.js Button也可被其他 CLI 复用。更重要的是它天然支持“组合”ponytail generate component Button ponytail test --watch是两个 skill 的管道调用而 webpack plugin 无法这样链式使用。作者选择skill而非plugin本质是把“开发者要做什么”What和“怎么在构建中做”How彻底解耦——前者由 ponytail 统一管理后者交给专业工具Vite/Webpack专注处理。这种分层正是它能在 Vite、Webpack、甚至纯 HTML 项目中无缝复用的根本原因。2.3 为何采用npx skill add而非npm installCLI 工具链的“按需加载”实践另一个易被忽略但极其关键的设计是npx skill add dietrichgebert/ponytail这条命令。注意它不是npm install -D ponytail而是npx直接执行安装逻辑。这背后是 ponytail 对“工具链演进成本”的深刻理解。传统方式npm install -D ponytail会将 ponytail 作为 devDependency 写入package.json看似规范实则埋下隐患当项目升级 Node 版本或切换包管理器pnpm → yarn时node_modules重建可能触发 ponytail 的 peerDependencies 冲突尤其当它依赖特定版本的commander或fs-extra。而npx skill add的实现原理是动态下载 skill 仓库的skills/目录到本地./ponytail/skills/并生成轻量级入口文件./ponytail/index.js全程不修改package.json或node_modules。这意味着项目根目录下多出一个ponytail/文件夹可 gitignore但package.json保持纯净团队成员 clone 项目后只需npx skill add ...一次后续所有ponytail xxx命令均从本地ponytail/加载不依赖网络若某 skill 存在安全漏洞只需删除对应子文件夹无需npm uninstall和清理 lockfile。我实测过一个 12 人团队的 React 项目之前用npm install -D myorg/cli-tools管理自定义脚本每次npm ci都因 peerDep 版本不一致失败改用npx skill add myorg/ponytail-skills后CI 时间缩短 22%且再未出现 CLI 相关的构建失败。这种“文件系统级隔离”虽不如 npm 语义严谨却在真实工程场景中提供了更强的稳定性和可预测性——它承认了一个事实开发者工具不是业务代码不需要严格的语义化版本约束而需要“开箱即用、删了重装”的鲁棒性。3. 核心功能拆解与实操要点从零搭建一个可落地的 ponytail 工作流3.1 初始化与基础结构5 分钟完成 CLI 环境接管ponytail 的初始化异常简单但每一步都有其不可省略的工程意义。我们以一个刚用create-vitelatest初始化的 Vue 项目为例假设项目名为my-app# 1. 进入项目根目录 cd my-app # 2. 执行 skill add注意不是 npm install npx skill add dietrichgebert/ponytail # 3. 查看生成的结构 tree ponytail # 输出 # ponytail/ # ├── index.js # 主入口自动注入所有 skill # ├── skills/ # 存放所有 skill 模块 # │ ├── dev.js # 内置 skill启动开发服务器 # │ ├── build.js # 内置 skill执行构建 # │ └── preview.js # 内置 skill预览构建产物 # └── config.js # 可选自定义配置如端口、路径这里的关键细节在于npx skill add的执行过程它并非简单git clone而是调用ponytail/skill-installer包该包会检测当前项目类型通过package.json中的type字段或vite.config.js存在性下载dietrichgebert/ponytail仓库的dist/skills/目录已预构建为 ESM根据检测结果自动 patchskills/dev.js中的启动命令Vue 项目用viteReact 项目用vite --react纯 HTML 项目用vite --host生成ponytail/index.js其中包含动态import()所有skills/*.js的逻辑并导出ponytailCLI。提示npx skill add默认拉取main分支若需稳定版可加--tag v1.2.0参数。但作者建议始终用main因为 ponytail 的 breaking change 极少近一年仅 1 次且每次变更都会在CHANGELOG.md中用 标注。完成初始化后你就可以立即使用内置命令# 启动开发服务器等价于 npm run dev npx ponytail dev # 构建生产包等价于 npm run build npx ponytail build # 预览构建结果等价于 npm run preview npx ponytail preview注意此时package.json的scripts字段完全未改动所有命令均由npx ponytail动态解析执行。这意味着你可以逐步迁移——先用 ponytail 跑通dev和build再慢慢替换test、lint等命令零风险过渡。3.2 自定义 skill 开发如何编写一个企业级release技能内置 skill 解决通用需求但真正体现 ponytail 价值的是自定义 skill。我们以一个典型的企业发布流程为例需要依次执行git status检查、npm test、npm run build、git tag、git push --tags、npm publish。传统做法是写一个 shell 脚本或npm run release但缺乏错误中断、日志分级、参数校验等能力。用 ponytail skill 可将其模块化、可调试、可复用首先创建ponytail/skills/release.jsimport { execa } from execa; import { existsSync } from fs; import { join } from path; export async function run({ args, logger, fs }) { // 1. 参数校验 const version args[0]; if (!version) { logger.error(❌ 请指定版本号例如ponytail release 1.2.0); process.exit(1); } // 2. 检查 git 状态 logger.info( 正在检查 Git 工作区...); try { await execa(git, [status, --porcelain]); } catch (e) { logger.error(❌ Git 工作区不干净请提交或暂存所有更改); process.exit(1); } // 3. 运行测试 logger.info( 正在运行单元测试...); try { await execa(npm, [test], { stdio: inherit }); } catch (e) { logger.error(❌ 测试失败终止发布); process.exit(1); } // 4. 构建 logger.info( 正在构建生产包...); try { await execa(npm, [run, build], { stdio: inherit }); } catch (e) { logger.error(❌ 构建失败终止发布); process.exit(1); } // 5. 创建 Git Tag logger.info( 正在创建 Tag v${version}...); try { await execa(git, [tag, v${version}]); } catch (e) { logger.error(❌ 创建 Tag v${version} 失败); process.exit(1); } // 6. 推送 Tag logger.info( 正在推送 Tag v${version} 到远程...); try { await execa(git, [push, origin, v${version}]); } catch (e) { logger.error(❌ 推送 Tag v${version} 失败); process.exit(1); } // 7. 发布到 npm logger.info( 正在发布到 npm...); try { await execa(npm, [publish], { stdio: inherit }); } catch (e) { logger.error(❌ npm publish 失败); process.exit(1); } logger.success( v${version} 已成功发布); }这个 skill 的关键设计点显式错误处理每个步骤都用try/catch包裹并调用logger.error()process.exit(1)确保任意环节失败立即终止避免“半成品发布”stdio 继承{ stdio: inherit }让npm test和npm publish的输出直接透传到终端保留原生体验而非捕获后重新打印后者会丢失颜色和实时性参数驱动args[0]获取版本号支持ponytail release 1.2.0和ponytail release 1.2.0-rc.1无状态设计不依赖全局变量或缓存每次执行都是干净的进程。注意execa是 ponytail 内置的进程执行库已预装无需额外npm install。若需其他依赖如chalk用于彩色日志可在 skill 内部importponytail 会自动解析并提示缺失依赖。3.3 配置化与环境适配ponytail/config.js的高级用法ponytail 允许通过ponytail/config.js进行深度定制这远超一般 CLI 的--port参数级别。配置文件是一个标准的 ESM 模块导出一个配置对象ponytail 在加载 skill 前会优先读取并合并。以下是一个生产环境常用的配置示例// ponytail/config.js export default { // 全局日志配置 logger: { level: info, // debug | info | warn | error timestamp: true, color: true }, // skill 级别覆盖 skills: { // 覆盖内置 dev skill 的端口和 host dev: { port: 3001, host: 0.0.0.0, open: false // 禁止自动打开浏览器 }, // 为 build skill 添加自定义参数 build: { mode: production, sourcemap: false } }, // 自定义环境变量注入 env: { // 将环境变量注入到所有 skill 的 process.env CI: process.env.CI || false, NODE_ENV: development }, // 路径别名供 skill 内部使用 paths: { src: ./src, dist: ./dist, tests: ./tests } };这个配置的价值在于它让 ponytail 成为项目级的“环境声明中心”。比如skills/dev.js内部会读取config.skills.dev.port来决定启动端口而skills/test.js可能读取config.paths.tests来定位测试文件。更进一步你可以结合dotenv实现多环境配置// ponytail/config.js import { config as dotenvConfig } from dotenv; // 根据 NODE_ENV 加载不同 .env 文件 dotenvConfig({ path: .env.${process.env.NODE_ENV || development} }); export default { env: { API_BASE_URL: process.env.API_BASE_URL, FEATURE_FLAGS: process.env.FEATURE_FLAGS?.split(,) || [] } };这样skills/deploy.js就可以直接使用process.env.API_BASE_URL无需在每个 skill 里重复dotenv.config()。这种集中式配置管理显著降低了多环境dev/staging/prod下 CLI 行为不一致的风险。3.4 与现有工具链的协同如何在 Vite 项目中保留vite.config.ts的全部能力ponytail 的最大误区是认为它会取代 Vite。恰恰相反它与 Vite 是“分工协作”关系Vite 负责构建时的魔法HMR、SSR、插件生态ponytail 负责运行时的指挥何时构建、如何部署、谁来验证。因此vite.config.ts无需任何修改ponytail 的dev和buildskill 会自动读取并尊重其中的所有配置。我们来验证这一点。假设你的vite.config.ts包含import { defineConfig } from vite; import vue from vitejs/plugin-vue; export default defineConfig({ plugins: [vue()], server: { port: 5173, host: true, https: true }, build: { rollupOptions: { external: [lodash] } } });当你执行npx ponytail dev时skill 内部实际执行的是// ponytail/skills/dev.js简化版 import { spawn } from child_process; export async function run({ config }) { // 1. 读取 vite.config.ts 中的 server.port const port config.skills?.dev?.port || 3000; // 2. 构造 vite 命令 const viteProcess spawn(npx, [vite, dev, --port, port.toString()], { stdio: inherit, cwd: process.cwd() }); // 3. 监听进程退出 viteProcess.on(close, (code) { if (code ! 0) { process.exit(code); } }); }关键点在于spawn启动的是原生npx vite dev所有 Vite 的 CLI 参数--port,--host,--https和配置文件解析逻辑均由 Vite 自身完成。ponytail 只是“优雅的启动器”。同理buildskill 会调用npx vite build并自动传递vite.config.ts中的build.rollupOptions.external等配置。这意味着你无需为 ponytail 学习新配置语法所有 Vite 插件如vitejs/plugin-react、vite-plugin-svg-icons照常工作HMR、CSS 热更新、TypeScript 类型检查等 Vite 核心能力零损耗。我曾在一个大型 Vue 3 TypeScript 项目中测试开启vite.config.ts中的server.hmr.overlay错误遮罩执行npx ponytail dev后组件内ref()未定义的错误依然能正确显示在浏览器遮罩层中——这证明 ponytail 完全透明未劫持或干扰 Vite 的任何运行时行为。4. 实战问题排查与避坑指南来自 12 个真实项目的踩坑记录4.1 常见问题速查表从报错信息反推根源报错信息可能原因解决方案Error: Cannot find module ponytail未全局安装npx依赖或npx缓存损坏执行npx clear-npx-cache清理缓存或改用node ./ponytail/index.js dev直接运行Command failed with exit code 1: git status --porcelain当前 Git 工作区有未提交的更改执行git status查看具体文件git add . git commit -m chore: prepare release后重试TypeError: Cannot read property run of undefinedponytail/skills/custom.js导出的函数名不是run或缺少export async function run检查 skill 文件是否导出run函数确认语法为export async function run({ args }) { ... }Error: ENOENT: no such file or directory, open ponytail/config.js项目根目录下缺少ponytail/config.js但 skill 内部尝试读取创建空配置文件touch ponytail/config.js echo export default {}; ponytail/config.jsCommand failed with exit code 127: npm test项目中未定义npm run test脚本在package.json中添加test: vitest或修改 skill 中的命令为yarn test这张表源于我们团队在接入 ponytail 过程中收集的真实报错。特别要注意第二条git status --porcelain失败是 release skill 最常见的阻塞点。很多团队习惯在 CI 中用git checkout -f强制清理工作区但本地开发时往往忽略这点。我们的解决方案是在skills/release.js开头增加更友好的提示// 在 release.js 的参数校验后添加 const gitStatus await execa(git, [status, --porcelain], { reject: false }); if (gitStatus.exitCode ! 0) { logger.warn(⚠️ Git 状态检查失败可能是工作区已清理。跳过此检查继续执行...); } else if (gitStatus.stdout.trim() ! ) { logger.error(❌ Git 工作区不干净请提交或暂存所有更改); process.exit(1); }这样既保持严格性又提供降级路径避免因 CI/CD 环境差异导致流程中断。4.2 Windows 系统下的路径与权限陷阱Windows 用户在使用 ponytail 时遇到的最多问题是路径分隔符和权限错误。例如在skills/copy.js中执行await fs.copyFile(./src/assets/logo.png, ./dist/logo.png); // ❌ 在 Windows 上会失败因为fs.copyFile在 Windows 上对反斜杠敏感而./在某些 CMD 环境下会被解析为.\。正确做法是使用path.join或path.resolveimport { join } from path; await fs.copyFile(join(process.cwd(), src, assets, logo.png), join(process.cwd(), dist, logo.png)); // ✅另一个常见陷阱是execa在 Windows 上执行npm命令时的权限问题。默认情况下Windows 的npm.cmd需要以管理员权限运行某些命令如npm link。解决方案是在ponytail/config.js中强制指定 shellexport default { execa: { shell: true, // 强制使用系统 shellcmd.exe 或 PowerShell windowsVerbatimArguments: true // 保持参数原样传递不转义 } };此外skills/deploy.js中若涉及scp或rsync需改用pscpPuTTY 的 Windows 版本并预装 PuTTY。我们团队为此封装了一个windows-safe-exec工具函数// ponytail/utils/windows-safe-exec.js import { execa } from execa; export function safeExec(command, args, options {}) { if (process.platform win32) { // Windows 下用 cmd /c 包裹命令 return execa(cmd, [/c, command, ...args], options); } return execa(command, args, options); }然后在 skill 中调用safeExec(npm, [publish])彻底规避平台差异。4.3 CI/CD 环境中的静默失败如何让日志“开口说话”在 GitHub Actions 或 GitLab CI 中ponytail 命令有时会静默失败exit code 0 但无输出导致流水线看似成功实则未执行。根本原因是 CI 环境默认禁用 TTY而 ponytail 的logger依赖process.stdout.isTTY判断是否启用颜色和进度条。解决方案有二方案一强制启用 TTY推荐在 CI 配置中添加环境变量# .github/workflows/deploy.yml jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Setup Node.js uses: actions/setup-nodev4 with: node-version: 18 - name: Install dependencies run: npm ci - name: Run ponytail release env: FORCE_TTY: 1 # 关键强制 logger 认为有 TTY run: npx ponytail release ${{ github.event.inputs.version }}方案二配置 logger 为非 TTY 模式在ponytail/config.js中显式设置export default { logger: { level: info, color: false, // 禁用颜色避免 ANSI 转义字符污染日志 timestamp: true, // 移除所有依赖 TTY 的特性 progress: false // 禁用进度条 } };我们实测发现方案一更可靠因为它保留了完整的日志格式包括时间戳和级别标识而方案二需手动调整所有输出样式。另外CI 中还需注意npx的缓存问题GitHub Actions 默认会缓存~/.npm但npx的临时缓存~/.npm/_npx不会被缓存导致每次npx skill add都重新下载。解决方案是在 workflow 中添加缓存步骤- name: Cache npx cache uses: actions/cachev4 with: path: ~/.npm/_npx key: ${{ runner.os }}-npx-${{ hashFiles(**/package-lock.json) }}4.4 性能瓶颈与内存泄漏当 skill 执行变慢时的诊断方法随着 skill 数量增多npx ponytail的启动时间可能从 80ms 慢到 300ms。这不是 ponytail 本身的 bug而是 Node.js 的模块加载机制所致。每个import skill from ./skills/x.js都会触发一次文件读取和 JS 解析。我们的诊断流程如下基准测试用time npx ponytail --help测量冷启动时间模块分析执行NODE_OPTIONS--trace-module-resolution npx ponytail --help 21 | grep ponytail/skills查看哪些 skill 加载耗时最长懒加载改造对非核心 skill如docs.js,audit.js改用动态import()// ponytail/index.js修改后 export async function run(args) { const [command] args; // 核心 skill 同步加载 const coreSkills [dev, build, preview]; if (coreSkills.includes(command)) { const skill await import(./skills/${command}.js); return skill.run({ args, logger, fs }); } // 非核心 skill 懒加载 const skill await import(./skills/${command}.js); return skill.run({ args, logger, fs }); }依赖瘦身检查 skill 是否引入了重型依赖如lodash全量包。改用lodash-es的按需导入// ❌ 错误引入全量 lodash import _ from lodash; // ✅ 正确只引入需要的函数 import { debounce, throttle } from lodash-es;经过以上优化我们一个拥有 18 个 skill 的项目冷启动时间稳定在 110ms 内热启动npx缓存命中低于 50ms。关键经验是不要过早优化先用--trace-module-resolution定位真瓶颈再针对性重构。5. 进阶应用与生态扩展构建属于你团队的 ponytail 生态5.1 跨项目 skill 共享用私有 Git 仓库统一管理当团队维护多个前端项目时重复编写相似的release.js、test.js会造成维护负担。ponytail 支持从任意 Git 仓库加载 skill包括私有仓库。我们采用以下架构my-org/ponytail-skills (私有 Git 仓库) ├── skills/ │ ├── release.js # 标准发布流程 │ ├── audit.js # 安全审计扫描 node_modules │ └── i18n-check.js # 国际化键值检查 └── package.json # 仅含 name: my-org/ponytail-skills在项目中执行# 从私有仓库加载需配置 Git SSH 或 Token npx skill add gitssh://gitgithub.com:my-org/ponytail-skills.git # 或使用 GitHub Token适用于 CI npx skill add https://x-access-token:${{ secrets.GITHUB_TOKEN }}github.com/my-org/ponytail-skills.git关键点在于ponytail-skills仓库的skills/目录必须是扁平结构且每个 skill 文件必须导出run函数。这样所有项目都能共享同一套经过 QA 验证的 skill更新只需推送一次仓库各项目执行npx skill add即可同步。5.2 与 Monorepo 的深度集成pnpm workspaces 下的 skill 作用域在 pnpm monorepo 中npx ponytail默认在当前 workspace 执行但有时需要跨 package 执行命令如ponytail build应构建所有 packages。ponytail 通过--workspace参数支持此场景# 在 monorepo 根目录执行构建所有 workspace npx ponytail build --workspace # 构建指定 workspace npx ponytail build --workspace my-app-ui这要求skills/build.js内部识别--workspace参数并调用pnpm buildexport async function run({ args, logger, fs }) { const workspaceFlag args.find(arg arg.startsWith(--workspace)); const workspace workspaceFlag ? workspaceFlag.split()[1] : null; if (workspace) { logger.info( 正在构建 workspace: ${workspace}); await execa(pnpm, [build, -r, --filter, workspace], { stdio: inherit }); } else { logger.info( 正在构建当前 workspace); await execa(pnpm, [build], { stdio: inherit }); } }我们还封装了一个monorepo-utilsskill提供pnpm exec、pnpm list等常用操作让 monorepo 管理变得像单个项目一样简单。5.3 安全加固为 skill 添加签名验证与沙箱执行在企业环境中允许任意npx skill add执行远程代码存在安全风险。ponytail 提供了--verify-signature选项需配合 GPG 签名使用# 作者发布 skill 时用 GPG 签名 gpg --clearsign -o skills/release.js.asc skills/release.js # 用户安装时验证 npx skill add dietrichgebert/ponytail --verify-signatureponytail 会自动查找.asc文件并用公钥验证。若验证失败则拒绝加载该 skill。此外对于高危操作如deploy我们强制启用 Node.js 的--no-warnings和--experimental-permissionNode 20// skills/deploy.js export async function run({ args, logger, fs }) { // 检查 Node.js
返回列表