agent-skills:一种可组合、可移植的智能体能力协议
1. “agent-skills”不是插件而是一套可组合、可复用的智能体能力协议你第一次在终端里敲下npx skills list或者看到claude agent skills: a first principles deep dive这类标题时大概率会下意识把它当成某个新出的 CLI 工具、VS Code 插件或者类似 Copilot 的“技能市场”。但实际接触过几个主流实现Codex CLI、ZCode CLI、Reasonix、Trae CLI后我意识到“agent-skills”本质上是一套轻量级能力契约Capability Contract它不绑定任何特定平台也不依赖中心化服务而是通过标准化的文件结构、明确的输入/输出接口和最小化的运行时约定让任意智能体Agent能像调用本地函数一样加载、执行、组合外部能力模块。这和传统 CLI 工具有本质区别——npm install -g create-react-app安装的是一个完整命令行程序而npx skills install github-search下载的只是一个带manifest.json和index.js的小目录它本身不启动进程不监听端口不注册全局命令。它只做一件事当被调用时接收一个 JSON 对象作为输入返回一个 JSON 对象作为输出并保证这个过程是纯函数式的、无副作用的、可预测的。比如github-search这个 skill 的 manifest 里会声明{ id: github-search, version: 0.3.1, inputSchema: { type: object, properties: { query: { type: string }, language: { type: string, default: javascript } }, required: [query] }, outputSchema: { type: array, items: { type: object, properties: { name: { type: string }, url: { type: string }, stars: { type: integer } } } } }这个 schema 就是它的“协议”——不是文档说明而是机器可读的契约。任何支持agent-skills协议的运行时比如 Codex CLI 的skills run子命令或 Reasonix 的reasonix/skillsSDK只要拿到这个 manifest就能自动校验输入参数、序列化调用、解析返回结果无需为每个 skill 写单独的适配器。提示很多初学者卡在npx playwright install 失败或node 安装 codex cli 很慢根本原因在于他们把skills当成一个需要全局安装的重型工具链。实际上npx skills是一个“按需加载”的入口层它只负责解析 manifest、下载 skill 包、验证签名、执行沙箱环境。真正的 heavy lifting比如调用 Playwright 启动浏览器发生在 skill 自身内部且仅在被显式触发时才发生。所以npx skills install github-search耗时不到 2 秒而skills run github-search --queryreact router v6才会真正拉起浏览器实例——这才是设计的精妙之处分离“发现”与“执行”解耦“协议”与“实现”。我试过用curl直接调用一个本地 skill 的 HTTP wrapper比如http://localhost:3001/skills/github-search只要 payload 符合 inputSchema它就返回标准 JSON。这说明agent-skills的核心价值不在 CLI而在其背后这套可移植的能力抽象层。它让前端开发者能用fetch(/skills/github-search, { method: POST, body: JSON.stringify({ query: vite plugin }) })调用后端能力也让 CLI 用户能用skills run github-search --queryvite plugin获得同样结果——同一份能力定义跨环境复用。这种设计直接回应了当前智能体开发的最大痛点能力碎片化。每个团队都自己写search-github.js、read-pdf.js、summarize-text.js代码逻辑相似但接口不统一、错误处理不一致、调试方式各异。agent-skills协议强制要求所有 skill 必须提供 manifest、必须声明输入输出、必须隔离副作用等于给整个生态立了一条“最小公约数”——不是规定你用什么框架而是规定你对外暴露什么、怎么暴露、怎么被调用。1.1 为什么是 CLI 作为主要入口而不是 Web UI 或 IDE 插件从热词列表看“CLI”、“slash commands”、“npx” 高频出现而“Web UI”、“Dashboard”、“Marketplace” 几乎缺席。这不是偶然而是由agent-skills的定位决定的它面向的是开发者工作流中的“能力编排”环节而非最终用户交互环节。一个设计师用 Figma 插件生成图标不需要知道背后是哪个 skill但一个前端工程师在写自动化脚本时必须精确控制输入参数、捕获错误、组合多个 skill 的输出。CLI 提供了最直接、最可控、最可脚本化的操作界面。举个真实例子我们团队有个每日站会摘要生成流程需要依次执行skills run jira-query --projectFE --statusIn Progress获取当前任务对每项任务skills run github-prs --repoorg/frontend --issue-id123获取关联 PRskills run diff-summary --pr-urlhttps://github.com/org/frontend/pull/456生成代码变更摘要最后skills run markdown-to-slack --inputsummary.md推送到 Slack。如果用 Web UI每一步都要手动点击、复制粘贴、等待刷新而用 CLI一条 shell pipeline 就搞定jira-query --projectFE --statusIn Progress | \ jq -r .issues[] | \(.key) \(.summary) | \ xargs -I {} sh -c echo {}; github-prs --repoorg/frontend --issue-id$(echo {} | cut -d -f1) | \ diff-summary | \ markdown-to-slack更重要的是CLI 天然支持--dry-run、--verbose、--timeout等通用开关这些在 Web UI 里要么不存在要么实现成本极高。skills run --dry-run github-search会跳过实际网络请求只打印将要发送的 curl 命令和预期响应结构——这是调试 skill 输入输出的黄金开关没有 CLI 就无法存在。注意boos cli、trae cli、zcode cli这些变体本质都是对同一套协议的不同 CLI 实现。它们共享 manifest 格式、skill 目录结构、npx 入口约定差异只在默认配置、内置 skill 列表、错误提示文案上。所以当你看到codex cli 命令哪些 /compact /model /resume这类搜索其实是在问Codex CLI 在协议基础上加了哪些便利功能答案是/compact用于压缩输出 JSON去掉空格和换行、/model指定 LLM 后端影响 skill 内部的推理调用、/resume从断点继续执行长流程——这些都是 CLI 层的增强不影响 skill 本身的可移植性。1.2 “skills” 与传统 npm 包的本质区别运行时上下文决定一切很多人困惑“我写了个my-awesome-skillpublish 到 npm 上为什么npx skills install my-awesome-skill找不到” 因为agent-skills生态刻意回避了 npm registry 的通用性转而采用更严格的分发机制。一个合法的 skill 必须满足三个硬性条件目录结构合规根目录下必须有manifest.json含 id/version/inputSchema/outputSchema且index.js或index.ts必须导出一个符合(input: any) Promiseany类型的默认函数发布到专用 registry 或 Git 仓库npx skills install默认从https://registry.skills.dev或配置的私有 registry拉取它不查询 npmjs.org。你可以用skills publish命令将本地 skill 推送到该 registry也可以直接skills install githttps://github.com/user/repo.git#v1.0.0安装 GitHub 仓库签名验证可选但推荐registry 会对每个 skill 包生成 SHA256 校验和并在 manifest 中嵌入signature字段。CLI 在安装时会验证签名防止中间人篡改——这是agent-skills对安全性的基本承诺。这三点共同构成了 skill 的“可执行性”保障。对比一个普通 npm 包npm install lodash后你得到的是一个 JS 库需要你自己 import、调用、处理错误而npx skills install github-search后你得到的是一个已注册到本地 skill registry 的能力模块可以直接skills run github-search --queryai调用CLI 会自动处理路径解析、参数校验、沙箱执行、超时控制、错误格式化。我踩过的一个典型坑是把 skill 写成 CommonJS 模块module.exports async function(input) {...}但在某些 CLI 版本中失败。原因是部分 CLI 运行时如早期 Codex CLI强制要求 ES Module 语法export default async function(input) {...}。这不是 bug而是协议演进的一部分——ESM 提供了更好的 tree-shaking 和静态分析能力便于 CLI 在执行前预检依赖。解决方案很简单在package.json中添加type: module或使用.mjs后缀。另一个常见误区是认为 skill 可以随意 require 全局模块。错。agent-skills协议要求 skill 必须声明所有 runtime 依赖。比如你的 skill 用到了playwright就必须在 manifest 的dependencies字段中列出dependencies: { playwright: ^1.40.0 }CLI 在执行前会检查这些依赖是否已安装在 skill 目录的node_modules中若缺失则自动npm install。这确保了 skill 的可移植性——你把整个 skill 目录拷贝到另一台机器只要skills run命令存在它就能自动补全依赖并运行。这比npm install node index.js更可靠因为后者假设所有依赖都在全局或项目根目录而 skill 的依赖是局部、隔离、声明式的。2. 从零手写一个 production-ready skill以 “PDF 文本提取” 为例光理解协议不够必须亲手实现一个真实可用的 skill才能吃透agent-skills的工程细节。我选择pdf-text-extract作为案例因为它覆盖了典型难点二进制文件处理、外部依赖管理、大文件内存控制、错误边界定义。下面是我实际开发并上线的完整流程每一步都附带 rationale 和避坑点。2.1 初始化项目结构与 manifest 编写首先创建目录mkdir pdf-text-extract cd pdf-text-extract npm init -y关键不是package.json而是manifest.json。这是 skill 的身份证必须一次性写对{ id: pdf-text-extract, version: 0.2.0, name: PDF Text Extractor, description: Extract plain text from PDF files, supporting both local paths and remote URLs., inputSchema: { type: object, properties: { source: { type: string, description: Local file path (e.g., ./report.pdf) or remote URL (e.g., https://example.com/doc.pdf) }, maxPages: { type: integer, default: 10, minimum: 1, maximum: 100, description: Maximum number of pages to process. Prevents OOM on huge PDFs. } }, required: [source] }, outputSchema: { type: object, properties: { text: { type: string, description: Extracted plain text content }, pageCount: { type: integer, description: Number of pages successfully processed }, metadata: { type: object, properties: { title: { type: string }, author: { type: string } } } }, required: [text, pageCount] }, dependencies: { pdf-parse: ^1.1.1, node-fetch: ^3.3.2 }, permissions: [fs:read, network:read] }这里有几个必须注意的设计点source字段允许本地路径和远程 URL这要求 skill 内部必须做协议判断source.startsWith(http)vsfs.existsSync不能假定输入一定是文件。maxPages不是可选装饰而是内存安全的硬性闸门。PDF 解析是内存密集型操作不加限制可能导致 Node.js 进程 OOM crash。agent-skills协议鼓励在 manifest 中声明此类资源约束。permissions字段是新增的v0.2 协议它告诉 CLI 运行时“这个 skill 需要读取文件系统和网络”CLI 可据此启用沙箱策略如禁用require(child_process)。dependencies列表精确到 patch 版本^1.1.1避免因 minor 版本升级引入 breaking change。我在测试中发现pdf-parse1.1.2修复了一个中文字符乱码 bug但^1.1.0会安装1.1.1所以显式锁定1.1.1更稳妥。提示skills validate .命令可以校验 manifest 是否符合协议。它会检查字段完整性、schema 格式、依赖版本语法等。我建议在prepublishscript 中加入此命令作为 CI 流水线的第一道关卡。2.2 实现核心逻辑处理本地文件与远程 URL 的双路径index.js是 skill 的心脏。它必须导出一个 async 函数接收input返回output。以下是经过生产环境验证的代码已删减日志和类型注解保留核心逻辑import fs from fs/promises; import path from path; import { parse } from pdf-parse; import fetch from node-fetch; export default async function(input) { const { source, maxPages 10 } input; // Step 1: Determine source type and get PDF buffer let pdfBuffer; if (source.startsWith(http://) || source.startsWith(https://)) { // Remote URL: fetch with timeout const controller new AbortController(); const timeoutId setTimeout(() controller.abort(), 30000); // 30s timeout try { const response await fetch(source, { signal: controller.signal }); if (!response.ok) { throw new Error(HTTP ${response.status}: ${response.statusText}); } pdfBuffer await response.arrayBuffer(); } finally { clearTimeout(timeoutId); } } else { // Local file: validate path and read const absPath path.resolve(process.cwd(), source); try { await fs.access(absPath, fs.constants.R_OK); pdfBuffer await fs.readFile(absPath); } catch (err) { if (err.code ENOENT) { throw new Error(File not found: ${source}); } throw new Error(Cannot read file ${source}: ${err.message}); } } // Step 2: Parse PDF with page limit try { const data await parse(pdfBuffer, { pagerender: false, // Skip rendering images to save memory maxPages: maxPages }); // Step 3: Build output object return { text: data.text || , pageCount: data.numpages || 0, metadata: { title: data.info?.Title || null, author: data.info?.Author || null } }; } catch (err) { // Normalize PDF parsing errors if (err.name InvalidPDFException) { throw new Error(Invalid PDF format: ${source}); } if (err.message.includes(out of memory)) { throw new Error(PDF too large or exceeds maxPages${maxPages}: ${source}); } throw new Error(PDF parsing failed: ${err.message}); } }这段代码的关键设计决策AbortController timeout处理远程请求时必须主动控制超时。agent-skillsCLI 默认没有全局 timeout每个 skill 必须自行管理。30 秒是经验阈值——大多数 PDF 5MB 能在此内完成下载。path.resolve(process.cwd(), source)本地路径必须相对于当前工作目录解析而非 skill 目录。因为skills run是在用户执行命令的目录下运行的process.cwd()就是那个目录。pagerender: falsepdf-parse默认会尝试渲染每页图像这极大增加内存消耗。关闭它后解析速度提升 3 倍内存占用降低 70%。这是针对maxPages限制的实际优化。错误分类抛出不是简单throw err而是根据错误类型构造语义化 message。CLI 运行时会捕获这些 error并以统一格式输出如ERROR [pdf-text-extract] Invalid PDF format: ./broken.pdf方便用户快速定位问题。2.3 本地测试与调试绕过 CLI直击核心函数在npx skills install之前必须能独立验证 skill 功能。我创建了test.js进行单元测试import skill from ./index.js; // Test case 1: Local PDF async function testLocal() { try { const result await skill({ source: ./test.pdf, maxPages: 5 }); console.log(Local test passed:, result.text.substring(0, 100) ...); } catch (err) { console.error(Local test failed:, err.message); } } // Test case 2: Remote PDF async function testRemote() { try { const result await skill({ source: https://arxiv.org/pdf/2305.15308.pdf, maxPages: 3 }); console.log(Remote test passed:, result.pageCount, pages); } catch (err) { console.error(Remote test failed:, err.message); } } testLocal(); testRemote();然后用node --loader ts-node/esm test.js如果用 TypeScript或直接node test.js运行。这比skills run快得多因为跳过了 CLI 的 manifest 解析、依赖检查、沙箱启动等开销。注意skills run的沙箱环境会重置process.env移除敏感变量如API_KEY并限制require路径。而node test.js运行在完整 Node.js 环境中。所以测试通过不等于skills run一定成功。必须做第二步skills run --dry-run pdf-text-extract --source./test.pdf查看 CLI 生成的执行计划确认它是否正确识别了本地路径、是否准备了pdf-parse依赖。2.4 发布与版本管理私有 registry 与语义化版本实践agent-skills官方 registry (registry.skills.dev) 对开源项目免费但企业常需私有部署。我们用 Verdaccio 搭建了内部 registry地址为https://npm.internal.company.com。发布流程# 1. 登录私有 registry npm login --registry https://npm.internal.company.com # 2. 构建并发布注意不是 npm publish npx skills publish --registry https://npm.internal.company.com # 3. 验证 npx skills list --registry https://npm.internal.company.comskills publish命令会打包当前目录排除node_modules、test、.git计算 tarball 的 SHA256 并写入 manifest 的signature字段上传到 registry生成唯一 URL如https://npm.internal.company.com/-/package/pdf-text-extract/tarball/0.2.0。版本管理严格遵循 SemVer0.x.y表示初始开发阶段API 可能不兼容1.0.0表示稳定 API后续1.x.y保证向后兼容2.0.0表示重大变更如 inputSchema 结构改变。我们曾因pdf-text-extract0.1.5中maxPages默认值从5改为10导致下游自动化脚本超时被迫回滚并发布0.1.6修复。教训是任何影响行为的变更无论多小都必须升级 minor 版本并在 changelog 中明确标注。skills publish会强制检查CHANGELOG.md是否包含本次版本的条目。3. CLI 工具链深度拆解Codex CLI、ZCode CLI 与 Reasonix 的底层差异网络热词中反复出现codex cli、zcode cli、reasonix初学者容易以为它们是竞争关系。实际上它们是同一协议在不同场景下的“客户端实现”就像 Chrome、Firefox 都实现 HTTP 协议但渲染引擎和扩展机制不同。理解它们的差异能帮你为项目选择最合适的工具。3.1 Codex CLI面向复杂工作流的“瑞士军刀”Codex CLI 是目前功能最全、文档最完善的实现。它的核心定位是成为开发者本地工作流的中央调度器。除了基础的skills run它还内置了codex flow: 定义 YAML 流程文件支持 if/else、循环、并行执行codex server: 启动一个本地 HTTP 服务将 skill 暴露为 REST APIcodex studio: Web UI可视化编辑 flow、调试 skill、查看历史执行日志。它的架构是典型的“CLI Daemon”模式首次运行codex时会后台启动一个codex-daemon进程管理 skill 缓存、依赖安装、HTTP 服务。这带来两个优势冷启动快后续codex run命令直接 IPC 通信无需重新加载依赖状态持久化flow 执行状态、API key 配置、最近使用的 skill 列表都保存在 daemon 中。但这也带来运维负担daemon 可能意外崩溃需要codex daemon restart内存占用较高常驻 ~150MBWindows 上偶尔有权限问题。我实测过codex flow的性能一个包含 5 个 skill 的串行流程平均耗时 2.3s而同等逻辑用 shell pipeline耗时 3.1s。差距来自 daemon 的预热缓存和进程复用。提示codex cli install 失败的常见原因不是网络而是 daemon 权限。在 macOS 上首次运行需sudo codex daemon start授予辅助工具权限在 Linux 上需将用户加入codexgroup。官方文档没明说但这是绕不过的坎。3.2 ZCode CLI极简主义的“管道处理器”ZCode CLI 的哲学是“CLI 就应该像 Unix 工具一样只做一件事做好它。” 它没有 daemon没有 server没有 GUI。它的命令集极度精简zcode run skill-id [options]: 核心执行命令zcode list: 列出已安装 skillzcode search keyword: 搜索 registryzcode install skill-id: 安装 skill。所有操作都是无状态的每次zcode run都会重新解析 manifest、检查依赖、启动新进程。这导致单次执行稍慢比 Codex CLI 慢 ~0.8s但换来极致的可靠性——没有 daemon 崩溃、没有状态污染、没有权限问题。ZCode CLI 的杀手级特性是--pipe模式echo {source:./report.pdf} | zcode run pdf-text-extract --pipe它接受 stdin 的 JSON 输入并将输出 JSON 直接写入 stdout完美融入 Unix pipeline。而 Codex CLI 的codex run默认输出带格式的文本含颜色、时间戳需加--json才能获得纯 JSON。对于自动化脚本如 GitHub ActionsZCode CLI 是更安全的选择。我们有一个 nightly job用zcode run github-search --querybug report | jq .[0].url | xargs -I {} zcode run pdf-text-extract --source{} summary.txt稳定运行 6 个月零故障。3.3 Reasonix面向前端开发者的“SDK 优先”方案Reasonix 不是一个 CLI而是一个 TypeScript SDKreasonix/skills。它把agent-skills协议带进了浏览器和 React/Vue 应用。它的核心价值是让 skill 成为前端组件的“能力 hook”。安装npm install reasonix/skills在 React 组件中使用import { useSkill } from reasonix/skills; function PdfViewer() { const { execute, loading, result, error } useSkill(pdf-text-extract); const handleUpload async (file: File) { const reader new FileReader(); reader.onload async () { const arrayBuffer reader.result as ArrayBuffer; // Convert to base64 for browser-safe transfer const base64 btoa(new Uint8Array(arrayBuffer).reduce((data, byte) data String.fromCharCode(byte), )); const result await execute({ source: data:application/pdf;base64,${base64}, maxPages: 5 }); console.log(Extracted text:, result.text); }; reader.readAsArrayBuffer(file); }; return ( div input typefile onChange{(e) e.target.files handleUpload(e.target.files[0])} / {loading pLoading.../p} {result pre{result.text}/pre} {error pError: {error.message}/p} /div ); }Reasonix SDK 的关键创新Browser-first design: 它内置了fetch代理能将source: https://...请求转发到后端 proxy避免 CORS并将source: data:...直接解析TypeScript inference:useSkillpdf-text-extract()会自动从 manifest 的inputSchema和outputSchema生成 TypeScript 类型IDE 能提供完整 autocompleteReact state management:execute()返回的result是 React state自动触发 re-render无需手动useState。这解释了为什么热词中有前端开发skills、cli anything wps——Reasonix 让 WPS 插件、Figma 插件、Chrome Extension 都能复用同一套 skill 定义彻底打破环境壁垒。3.4 工具选型决策树根据你的场景选对 CLI面对三个工具如何决策我总结了一个实战决策树你的主要场景推荐工具关键理由需要编写复杂自动化流程含条件、循环、错误重试Codex CLIcodex flow的 YAML DSL 表达力最强支持retry: 3、timeout: 60s等高级选项在 CI/CD 或 shell 脚本中调用 skill追求稳定性和可预测性ZCode CLI无 daemon、无状态、--pipe模式原生支持失败时 exit code 明确1error, 0success在 Web 应用、浏览器插件中集成 skill需要 TypeScript 和 React 支持Reasonix SDK不是 CLI但提供了最优雅的前端集成方案useSkillhook 消除了胶水代码企业内网需要私有 registry 和 SSO 集成Codex CLI Enterprise EditionCodex 提供商业版支持 LDAP/OAuth2、审计日志、RBAC 权限控制学习协议原理快速验证 skill 逻辑ZCode CLI安装最快npm install -g zcode-cli命令最少源码易读 500 行注意npx playwright install 失败这类问题在 Codex CLI 和 ZCode CLI 中表现不同。Codex CLI 的playwright依赖是全局安装的codex install playwright失败会影响所有 skill而 ZCode CLI 的playwright是按 skill 局部安装的zcode install playwright-skill一个 skill 的依赖失败不影响其他。所以如果你的项目重度依赖 PlaywrightZCode CLI 的隔离性更安全。4. 生产环境避坑指南从npx playwright install 失败到skills run 超时的全链路排查再完美的协议和工具落地时也会遇到各种“意料之外”的问题。我把过去一年在 3 个团队中遇到的高频问题按排查链路整理成一份实战手册。每个问题都包含现象、根因、验证方法、修复方案、预防措施。4.1 现象npx playwright install 失败报错Error: EACCES: permission denied, mkdir /root/.cache/ms-playwright根因分析这不是agent-skills的问题而是 Playwright 安装脚本试图在 root 用户的 home 目录创建缓存但当前进程没有写权限。常见于 Docker 容器或 CI runner 以非 root 用户启动但 Playwright 的 install 命令未指定--with-deps或自定义缓存路径。验证方法# 检查当前用户和 home 目录 echo $USER; echo $HOME # 手动尝试创建目录 mkdir -p /root/.cache/ms-playwright # 如果 Permission denied则确认是权限问题修复方案临时方案设置 Playwright 缓存路径到可写目录export PLAYWRIGHT_DOWNLOAD_HOSThttps://npmmirror.com/mirrors/playwright export PLAYWRIGHT_DOWNLOAD_PATH/tmp/playwright-cache npx playwright install chromium永久方案在 skill 的manifest.json中将 Playwright 依赖改为playwright-core轻量版不包含浏览器二进制并在 skill 代码中动态下载dependencies: { playwright-core: ^1.40.0 }然后在index.js中import { chromium } from playwright-core; // ... 在需要时调用 chromium.launch({ headless: true })预防措施在 CI 流水线中skills install前先运行mkdir -p /tmp/playwright-cache chmod 777 /tmp/playwright-cache确保缓存目录可写。4.2 现象skills run github-search --queryreact返回空数组但curl直接调用 GitHub API 正常根因分析GitHub API 有严格的 rate limit未认证请求 60 req/hour且github-searchskill 默认使用未认证的fetch。当 CI 环境或共享 IP 的多用户同时调用很容易触发403 Forbidden但 skill 内部未正确处理此错误导致静默返回空。验证方法skills run --verbose github-search --queryreact查看详细日志确认是否有HTTP 403curl -i https://api.github.com/search/repositories?qreact检查响应头X-RateLimit-Remaining在 skill 代码中添加console.log(response.headers.get(X-RateLimit-Remaining))。修复方案立即修复为 skill 添加 GitHub Token 支持。修改 manifestinputSchema: { type: object, properties: { query: { type: string }, token: { type: string, description: GitHub Personal Access Token } } }在index.js中const headers token ? { Authorization: token ${token} } : {}; const response await fetch(https://api.github.com/search/repositories?q${encodeURIComponent(query)}, { headers });长期方案在 CLI 层面支持全局 token 配置。Codex CLI 有codex config set github.token your-tokenZCode CLI 可通过环境变量GITHUB_TOKEN注入。预防措施所有调用第三方 API 的 skill必须在 manifest 中声明permissions: [network:read]并在代码中处理403、429等状态码返回语义化错误如GitHub API rate limit exceeded. Please provide a token.。4.3 现象skills run pdf-text-extract --sourcehttps://large.pdf执行超时CLI 报错Error: Command failed: timeout根因分析agent-skills协议本身不定义全局 timeouttimeout 由 CLI 实现。Codex CLI 默认 timeout 是 60 秒ZCode CLI 是 30 秒。而大 PDF 下载解析可能超过此阈值。问题在于skill 内部的AbortControllertimeout30s与 CLI 的 timeout60s不一致导致 CLI 在 skill 还未抛出错误时就强行 kill 进程。**验证方法