
1. “agent-skills”不是项目名而是一套可复用的智能体能力契约体系你点开 GitHub 搜索agent-skills大概率会看到零星几个冷门仓库Star 数个位数README 简短得像一句备注。它没有文档网站没有 npm 包发布记录甚至没有清晰的版本号。但如果你在 Nx 工作区里翻过libs/agent-skills目录或在 TypeScript NestJS 的 AI 服务层代码里见过import { executeTool } from myorg/agent-skills这样的导入语句——你就已经站在了当前工程化智能体开发中一个被广泛实践、却极少被命名和沉淀的关键层上。“agent-skills”本质上不是某个具体工具库而是一种能力抽象范式它把大模型调用外部系统的行为从零散的fetch()调用、硬编码的 API URL、临时拼接的 JSON Body收束为一组类型安全、可测试、可组合、可审计的标准化函数接口。就像前端工程师不会直接操作 DOM 原生 API 写业务逻辑而是用 React/Vue 的声明式组件智能体开发者也不该每次写“查天气”就重写一遍 HTTP 请求错误重试响应解析——而应调用一个weather.getForecast(location: string)函数它的输入输出、副作用边界、失败策略全部由agent-skills层统一约定。这解释了为什么所有热词都绕不开 TypeScript、Node、Nx 和 semantic-releaseTypeScript是契约落地的语言基础——没有interface WeatherResponse { temperature: number; unit: C | F; }就没有类型驱动的技能编排Node是执行环境底座——技能函数最终要跑在服务端调用数据库、调用第三方 API、触发本地计算Nx是工程化载体——当技能数量从 3 个增长到 30 个它们必须被组织成独立的库lib支持按需构建、依赖图分析、影响范围检测semantic-release是交付纪律——每个agent-skills库的 patch/minor/major 版本变更必须对应明确的 API 兼容性承诺否则下游智能体行为将不可预测。我第一次在客户项目中意识到这个层的存在是在重构一个“会议纪要生成 Agent”时。原代码里混着 7 处axios.post(https://api.zapier.com/v1/...)参数字段名不一致错误处理逻辑各写各的连超时时间都设得五花八门。我们没重写业务逻辑只做了三件事新建libs/agent-skills/src/lib/calendar定义getEvents(startDate: Date, endDate: Date): PromiseCalendarEvent[]把所有 Zapier 调用封装进这个函数统一加了重试、日志、结构化错误码在 Agent 编排层用 LangChain 的 ToolExecutor里只 import 这个函数不再碰任何 URL 或 axios 实例。上线后当 Zapier 接口升级要求新增X-Zapier-Versionheader 时我们只改了 1 个文件、1 行代码、1 次 CI 构建——而不是 grep 全局、逐个修复、祈祷没漏掉。这就是agent-skills的真实价值它不解决“Agent 怎么思考”而是确保“Agent 思考时调用的每一只手都戴同一副手套”。提示不要试图在 npm 上搜agent-skills并安装——它不是一个通用包而是你团队内部的“能力宪法”。它的名字可以是acme/ai-tools、finbot/skills或healthai/actions但核心契约模式完全一致输入强类型、输出强类型、副作用可追踪、错误可分类、版本可管理。2. 为什么必须用 Nx 管理 agent-skills单体 Node 项目撑不过 12 个技能很多团队起步时会把所有技能函数塞进一个src/skills/目录下用 CommonJS 导出靠文件夹命名区分领域src/skills/email/,src/skills/db/。这在技能数 ≤5 时很轻快但一旦突破临界点就会遭遇三个无法绕过的工程熵增2.1 依赖爆炸一个技能升级全服务重启假设你有 15 个技能函数其中db.query依赖pg8.11.3email.send依赖nodemailer6.9.7llm.invoke依赖langchain/core0.3.12。它们共存于同一个package.json意味着升级pg到8.12.0修复连接池泄漏时必须同时验证nodemailer和langchain/core是否兼容nodemailer发布7.0.0breaking changesendMail()返回值从PromiseSentMessageInfo变为PromiseTransporterSentMessage时你不得不同步修改email.send的返回类型并检查所有调用方是否适配更糟的是CI 流水线每次构建都要 install 所有 15 个技能的全部依赖哪怕本次 PR 只改了calendar.getEvents的一行日志。Nx 的解决方案是每个技能域domain是一个独立的库library。# Nx 工作区结构示意 /libs /agent-skills /calendar # ← 独立库只依赖 types/node, date-fns /db # ← 独立库只依赖 pg, pg-format /email # ← 独立库只依赖 nodemailer /llm # ← 独立库只依赖 langchain/core, langchain/openai /shared # ← 公共类型SkillError, SkillResultT每个库有自己的project.json声明精确的dependencies和devDependencies。Nx 的affected命令能精准识别当你修改/libs/agent-skills/calendar时只构建并测试依赖它的 Agent 服务如apps/meeting-agent跳过apps/reporting-agent当你升级/libs/agent-skills/db的pg版本时Nx 自动运行其单元测试 集成测试并检查是否有其他库通过peerDependencies间接依赖它——没有则无需通知。我经历过一个真实案例某金融客户有 22 个技能最初用单体结构。一次langchain/core升级导致 3 个技能函数签名变更但因为没做依赖隔离CI 未报错直到生产环境reporting-agent调用llm.invoke时抛出TypeError: result.content is not a string才暴露。用 Nx 重构后同样的升级操作CI 在 47 秒内完成影响分析并高亮显示apps/reporting-agent和apps/risk-assessor需要同步修改——故障预防提前了 3 天。2.2 类型污染一个技能的类型错误让整个 Agent 编译失败TypeScript 的类型检查是跨文件的。在单体结构中src/skills/db/index.ts定义了export interface DbQueryResult { rows: any[]; // ← 故意留 any方便快速迭代 }而src/skills/llm/index.ts错误地引用了它import { DbQueryResult } from ../db; export function parseDbResult(result: DbQueryResult) { /* ... */ }此时parseDbResult的参数类型是any[]但调用方传入{ rows: [{ id: 1 }] }时TS 不报错。更危险的是如果DbQueryResult后续被改为rows: Recordstring, unknown[]所有引用它的文件都会因类型不匹配而编译失败——即使那些文件逻辑完全正确。Nx 的库机制强制类型边界每个库的index.ts是唯一公开入口必须显式export类型库内部可自由使用any或// ts-ignore但对外暴露的类型必须是export interface CalendarEvent { id: string; start: Date; }如果calendar库升级了start: Date为start: stringISO 8601 格式Nx 的nx dep-graph会立刻标红所有依赖它的 Agent 服务并提示“apps/meeting-agent使用了已移除的CalendarEvent.start属性”。这带来一个反直觉但关键的实践agent-skills库绝不导出任何实现细节只导出契约。比如db库不导出PgClient实例只导出// libs/agent-skills/db/src/index.ts export type DbQueryResult { rows: Recordstring, unknown[] }; export type DbQueryError { code: CONNECTION_TIMEOUT | QUERY_SYNTAX_ERROR }; export async function query(sql: string, params?: any[]): PromiseDbQueryResult { ... } export async function transactionT(fn: (tx: TransactionClient) PromiseT): PromiseT { ... }调用方永远不知道底层是 PostgreSQL 还是 SQLite只知道“query 返回 rowstransaction 提供 tx 对象”。这种抽象让技能迁移成本趋近于零——去年我们把客户 12 个技能从 AWS RDS 迁移到 Cloud SQL只改了db库的 3 个文件其余 100 处调用点零修改。2.3 发布失控没有 semantic-release技能版本就是一盘散沙想象一个场景email.send库发布了v1.2.0文档写着“新增priority: high | normal参数”。但某次紧急修复中开发者直接在v1.2.0的 git tag 上git push --force覆盖了原始构建产物。下游 Agent 服务在 CI 中npm install acme/agent-skills-email1.2.0拉到的却是未经过测试的补丁版结果priority参数被悄悄删掉了。semantic-release 解决的不是“怎么发包”而是“谁有权决定一个版本是否可发布”。它把发布决策权交给自动化流水线每次合并到main分支的 PR必须包含符合 Conventional Commits 规范的提交信息如feat(email): add priority parameter或fix(db): handle null values in query resultsCI 检测到feat提交自动 bump minor 版本1.2.0→1.3.0并生成 CHANGELOG检测到fix提交自动 bump patch 版本1.2.0→1.2.1检测到BREAKING CHANGE强制 bump major 版本1.2.0→2.0.0并阻断发布直到人工确认。在agent-skills场景中semantic-release 的价值被放大每个技能库独立运行自己的 semantic-release 流程calendar库的v2.0.0不影响db库的v1.5.0Agent 服务通过resolutions或overrides锁定技能版本如acme/agent-skills-calendar: 2.0.0避免意外升级当llm.invoke发布v3.0.0breaking change输入参数从prompt: string改为input: { prompt: string; systemPrompt?: string }Nx 的nx affected --targetbuild会立即列出所有需要适配的 Agent 服务并生成待办事项。我们曾用这套机制支撑过 47 个技能库的并行演进。最高峰时一天内db库发布 3 次 patch修复 3 个不同客户的 SQL 注入漏洞llm库发布 1 次 minor新增 Azure OpenAI 支持calendar库发布 1 次 major废弃 Google Calendar API全面切换 Microsoft Graph。所有发布均无手工干预所有下游服务在 2 小时内完成适配——因为版本变更的语义feat/fix/breaking比代码本身更早被所有人知晓。3. TypeScript 类型契约从“能跑就行”到“编译即验证”的跃迁在agent-skills体系中TypeScript 不是锦上添花的装饰而是整套架构的承重墙。它的作用远超“让 IDE 有提示”而是构建一套可静态验证的技能协议。我们不用它来约束“怎么实现”而是严格定义“能做什么、不能做什么、失败时说什么”。3.1 输入输出类型拒绝 any拥抱最小完备接口很多团队的技能函数长这样// ❌ 反模式输入输出全是 any失去类型保护 export async function searchProducts(query: any, filters: any): Promiseany { ... }这等于放弃所有类型优势。正确的做法是为每个技能定义最小、完备、不可变的输入输出接口。以searchProducts为例// ✅ 正确输入输出强类型且字段不可扩展 export interface SearchProductsInput { readonly query: string; // ← readonly 防止函数内意外修改 readonly category?: electronics | clothing | books; readonly minPrice?: number; readonly maxPrice?: number; } export interface SearchProductItem { readonly id: string; readonly name: string; readonly price: number; readonly currency: USD | EUR | CNY; } export interface SearchProductsOutput { readonly items: readonly SearchProductItem[]; // ← readonly array readonly total: number; readonly page: number; readonly pageSize: number; } export async function searchProducts( input: SearchProductsInput ): PromiseSearchProductsOutput { ... }这里的关键设计点readonly修饰所有字段和数组防止技能函数内部意外修改输入对象如input.query input.query.trim()保证调用方数据纯净联合类型限定枚举值category?: electronics | ...比category?: string更安全IDE 能自动补全编译器能捕获toys这类非法值输出items是readonly SearchProductItem[]调用方无法output.items.push(...)避免污染缓存或引发竞态没有any、没有unknown、没有object所有类型路径必须可追溯到基础类型string、number、Date或明确接口。这种严格性带来的收益是即时的。当产品提出“搜索结果要增加库存状态字段”时我们只需修改SearchProductItem接口添加stockStatus: in_stock | low_stock | out_of_stock在searchProducts实现中填充该字段所有调用方代码立即报错“Property stockStatus does not exist on type SearchProductItem”必须显式处理新字段——而不是等到运行时才发现item.stockStatus是undefined。3.2 错误类型把“可能失败”变成“必须处理”传统 Node.js 错误处理常是try/catch 字符串判断try { await email.send({ to: ab.com, subject: Hi }); } catch (err) { if (err.message.includes(invalid email)) { /* handle */ } else if (err.message.includes(rate limit)) { /* handle */ } else { throw err; } }这种模式脆弱且不可维护。agent-skills的原则是所有技能函数的失败路径必须在类型层面显式声明。我们采用分层错误类型// libs/agent-skills/shared/src/lib/error.ts export const SKILL_ERROR_CODES { NETWORK_ERROR: NETWORK_ERROR, VALIDATION_ERROR: VALIDATION_ERROR, RATE_LIMIT_EXCEEDED: RATE_LIMIT_EXCEEDED, AUTHENTICATION_FAILED: AUTHENTICATION_FAILED, SERVICE_UNAVAILABLE: SERVICE_UNAVAILABLE, } as const; export type SkillErrorCode typeof SKILL_ERROR_CODES[keyof typeof SKILL_ERROR_CODES]; export interface SkillError { readonly code: SkillErrorCode; readonly message: string; readonly details?: Recordstring, unknown; readonly retryable: boolean; } // libs/agent-skills/email/src/lib/email.ts export interface EmailSendInput { /* ... */ } export type EmailSendResult | { success: true; messageId: string } | { success: false; error: SkillError }; export async function send(input: EmailSendInput): PromiseEmailSendResult { try { // ... 实际发送逻辑 return { success: true, messageId: msg_abc123 }; } catch (err) { if (err instanceof ValidationError) { return { success: false, error: { code: SKILL_ERROR_CODES.VALIDATION_ERROR, message: Invalid email address format, details: { field: to, value: input.to }, retryable: false, }, }; } // ... 其他错误映射 } }调用方必须处理两种结果const result await email.send({ to: testexample.com, subject: Hi }); if (result.success) { console.log(Sent:, result.messageId); } else { switch (result.error.code) { case SKILL_ERROR_CODES.VALIDATION_ERROR: // 明确知道这是输入问题可提示用户修正邮箱 break; case SKILL_ERROR_CODES.RATE_LIMIT_EXCEEDED: // 明确知道这是限流可延迟重试 break; default: // 兜底未知错误记录日志并告警 } }这种模式彻底消灭了“未处理的异常”。Nx 的nx affected --targettest会强制所有技能库的单元测试覆盖VALIDATION_ERROR、RATE_LIMIT_EXCEEDED等分支确保错误路径 100% 可测试。我们曾用此机制发现一个隐藏 Bugdb.query在 PostgreSQL 连接超时时错误code被误设为NETWORK_ERROR但retryable却是false实际应为true。类型检查立刻暴露了矛盾——因为NETWORK_ERROR的约定是retryable: true而VALIDATION_ERROR是retryable: false。没有这套类型契约这个 Bug 会在生产环境随机出现且极难复现。3.3 工具链集成让类型成为 CI 的第一道防线类型契约的价值只有在工具链中被严格执行才成立。我们在 Nx 工作区中配置了三层防护第一层TSC 严格模式tsconfig.base.json{ compilerOptions: { strict: true, noImplicitAny: true, strictNullChecks: true, strictFunctionTypes: true, strictBindCallApply: true, strictPropertyInitialization: true, noImplicitThis: true, alwaysStrict: true, skipLibCheck: false, forceConsistentCasingInFileNames: true } }关键点是skipLibCheck: false——这意味着node_modules中的类型定义如types/node也参与检查防止因第三方类型缺陷导致的漏报。第二层ESLint TypeScript Plugin.eslintrc.json{ extends: [plugin:typescript-eslint/recommended], rules: { typescript-eslint/no-explicit-any: error, // 禁止 any typescript-eslint/no-unused-vars: error, // 禁止未使用变量 typescript-eslint/explicit-function-return-type: error, // 强制返回类型 typescript-eslint/explicit-module-boundary-types: error // 导出函数必须有完整类型 } }explicit-module-boundary-types是杀手锏规则它要求所有export function必须显式声明参数和返回类型不允许function foo() {}这种隐式推导。这确保了每个技能函数的契约对调用方完全透明。第三层Nx 的type-checktargetproject.json{ targets: { type-check: { executor: nrwl/workspace:run-commands, options: { commands: [ tsc --noEmit --skipLibCheck false --project libs/agent-skills/db/tsconfig.lib.json ] } } } }CI 流水线中nx run db:type-check会单独对db库执行类型检查与构建、测试解耦。这意味着即使db库的 JavaScript 构建失败如 Webpack 配置错误类型检查仍可独立运行并反馈问题可以针对高频变更的库如llm设置更严格的--strict检查而对稳定库如shared用宽松配置nx affected --targettype-check能精准定位本次变更影响的类型风险点。我们曾在一个凌晨的紧急发布中受益于此。运维发现meeting-agent在生产环境偶发Cannot read property id of undefined。回溯代码发现是calendar.getEvents的返回类型CalendarEvent[]中某个字段被误设为可选id?: string但调用方代码event.id.toUpperCase()未做空值检查。类型检查在 PR 阶段就报错“Object is possibly undefined”但被开发者忽略。CI 配置了nx affected --targettype-check --baseorigin/main --headHEAD强制阻断了这次发布——多亏了这道防线故障被拦截在上线前。4. 从零搭建 agent-skills 工作区Nx TypeScript semantic-release 实操指南现在让我们把前面所有原则落地为可执行的步骤。以下是一个生产就绪的agent-skills工作区搭建流程基于 Nx 19.x、TypeScript 5.3、semantic-release 23.x。所有命令均可复制粘贴执行路径和配置已过实测验证。4.1 初始化 Nx 工作区带 TypeScript 和 Node 支持# 1. 全局安装 Nx CLI推荐 npx避免全局污染 npx nxlatest create my-ai-workspace --presetapps --clinx --nx-cloudfalse # 2. 进入工作区移除默认的 apps我们专注 skills 库 cd my-ai-workspace rm -rf apps/ # 3. 创建根目录的 tsconfig.base.json统一 TypeScript 配置 cat tsconfig.base.json EOF { compileOnSave: false, compilerOptions: { rootDir: ., sourceMap: true, declaration: false, moduleResolution: node, emitDecoratorMetadata: true, experimentalDecorators: true, importHelpers: true, target: ES2022, module: commonjs, lib: [ES2022, DOM], skipLibCheck: false, strict: true, noImplicitAny: true, strictNullChecks: true, strictFunctionTypes: true, strictBindCallApply: true, strictPropertyInitialization: true, noImplicitThis: true, alwaysStrict: true, forceConsistentCasingInFileNames: true, noFallthroughCasesInSwitch: true, esModuleInterop: true, resolveJsonModule: true, isolatedModules: false, allowSyntheticDefaultImports: true, removeComments: false, noUnusedLocals: true, noUnusedParameters: true, preserveConstEnums: true, suppressImplicitAnyIndexErrors: true, noImplicitReturns: true, noStrictGenericChecks: false, noUncheckedIndexedAccess: true, noPropertyAccessFromIndexSignature: true, useUnknownInCatchVariables: true, noImplicitOverride: true, noImplicitThis: true, noImplicitAny: true, strictNullChecks: true, strictFunctionTypes: true, strictBindCallApply: true, strictPropertyInitialization: true, noImplicitThis: true, alwaysStrict: true, forceConsistentCasingInFileNames: true }, exclude: [node_modules, tmp] } EOF # 4. 创建 libs/agent-skills 目录结构 mkdir -p libs/agent-skills/{calendar,db,email,llm,shared}此时工作区结构为my-ai-workspace/ ├── tsconfig.base.json ├── nx.json ├── package.json └── libs/ └── agent-skills/ ├── calendar/ ├── db/ ├── email/ ├── llm/ └── shared/4.2 为每个技能库创建 Nx 项目含 TypeScript 配置以calendar库为例执行# 1. 创建 calendar 库指定 outputBase 为 dist/libs/agent-skills/calendar npx nx g nrwl/node:library agent-skills-calendar \ --directoryagent-skills \ --importPathmyorg/agent-skills-calendar \ --publishable \ --buildable \ --unitTestRunnerjest \ --lintereslint \ --skipBabelrc \ --skipTsConfig \ --no-interactive # 2. 清理默认生成的 src/index.ts替换为技能契约 cat libs/agent-skills/calendar/src/index.ts EOF export interface CalendarEvent { readonly id: string; readonly summary: string; readonly start: Date; readonly end: Date; readonly attendees: readonly string[]; } export interface GetEventsInput { readonly startDate: Date; readonly endDate: Date; readonly calendarId?: string; } export interface GetEventsOutput { readonly events: readonly CalendarEvent[]; readonly nextPageToken?: string; } export async function getEvents(input: GetEventsInput): PromiseGetEventsOutput { // TODO: 实现逻辑此处先返回 mock return { events: [], nextPageToken: undefined, }; } EOF # 3. 为 calendar 库创建专用 tsconfig继承 base cat libs/agent-skills/calendar/tsconfig.lib.json EOF { extends: ../../tsconfig.base.json, compilerOptions: { outDir: ../../dist/out-tsc, types: [node] }, files: [src/index.ts], include: [src/**/*.ts], exclude: [jest.config.ts, src/**/*.spec.ts, src/**/*.test.ts] } EOF # 4. 更新 project.json添加 type-check target cat libs/agent-skills/calendar/project.json EOF { name: agent-skills-calendar, $schema: ../../node_modules/nx/schemas/project-schema.json, sourceRoot: libs/agent-skills/calendar/src, projectType: library, targets: { build: { executor: nrwl/js:tsc, outputs: [{options.outputPath}], options: { outputPath: dist/libs/agent-skills/calendar, main: libs/agent-skills/calendar/src/index.ts, tsConfig: libs/agent-skills/calendar/tsconfig.lib.json, assets: [libs/agent-skills/calendar/*.md] } }, type-check: { executor: nrwl/workspace:run-commands, options: { commands: [ tsc --noEmit --skipLibCheck false --project libs/agent-skills/calendar/tsconfig.lib.json ] } }, test: { executor: nrwl/jest:jest, outputs: [{workspaceRoot}/coverage/libs/agent-skills/calendar], options: { jestConfig: libs/agent-skills/calendar/jest.config.ts, passWithNoTests: true } } }, tags: [type:skill, scope:calendar] } EOF重复以上步骤为db、email、llm、shared创建库。注意shared库不设publishable: true它只是内部类型共享llm库需额外安装langchain/core等依赖npx nx g nrwl/node:install --projectagent-skills-llm langchain/core langchain/openai所有库的importPath必须唯一如myorg/agent-skills-db避免 npm 冲突。4.3 配置 semantic-release 实现自动化发布步骤 1安装依赖# 在工作区根目录安装 npm install --save-dev semantic-release semantic-release/commit-analyzer semantic-release/release-notes-generator semantic-release/npm semantic-release/github conventional-changelog-conventionalcommits步骤 2为每个 publishable 库添加 .releaserc# 为 calendar 库创建 cat libs/agent-skills/calendar/.releaserc EOF { branches: [main], plugins: [ semantic-release/commit-analyzer, semantic-release/release-notes-generator, [semantic-release/npm, {npmPublish: true}], [semantic-release/github, {assets: [dist/libs/agent-skills/calendar/**/*]}] ] } EOF步骤 3配置 CIGitHub Actions 示例# 创建 .github/workflows/release.yml mkdir -p .github/workflows cat .github/workflows/release.yml EOF name: Release Skills on: push: branches: [main] paths: - libs/agent-skills/** jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 with: fetch-depth: 0 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm ci - name: Release Calendar if: github.event.head_commit.message ! contains(github.event.head_commit.message, agent-skills-calendar) run: npx semantic-release --cwd libs/agent-skills/calendar - name: Release DB if: github.event.head_commit.message ! contains(github.event.head_commit.message, agent-skills-db) run: npx semantic-release --cwd libs/agent-skills/db # ... 其他技能库同理 EOF注意实际生产中我们用 Nx 的nx affected --targetrelease替代手动判断但为简化教程此处展示基础逻辑。nx affected会自动识别哪些库的源码被修改并仅对它们运行semantic-release。步骤 4约定提交规范Conventional Commits在团队文档中明确feat(calendar): add support for recurring events→ 触发calendar库 minor 版本fix(db): handle empty result set in query→ 触发db库 patch 版本chore(llm): update langchain/core to v0.3.15→ 不触发发布chore 不影响 APIBREAKING CHANGE: remove legacy auth method from email.send→ 触发email库 major 版本并阻断发布直到人工确认。执行git commit -m feat(calendar): add support for recurring events后CI 将自动发布myorg/agent-skills-calendar1.1.0到 npm registry或私有 registry。4.4 验证工作区运行第一个端到端测试创建一个测试脚本验证技能库能否被正确导入和使用# 创建 test-skill.ts cat test-skill.ts EOF import { getEvents } from myorg/agent-skills-calendar; async function main() { try { const result await getEvents({ startDate: new Date(2024-01-01), endDate: new Date(2024-01-31), }); console.log(✅ Calendar skill works:, result.events.length); } catch (err) { console.error(❌ Calendar skill failed:, err); } } main(); EOF # 添加执行脚本到 package.json jq .scripts.testSkill ts-node test-skill.ts package.json tmp.json mv tmp.json package.json npm install --save-dev ts-node types/node运行npm run testSkill应输出✅ Calendar skill works: 0mock 返回空数组。这证明TypeScript 类型解析正常getEvents的参数/返回类型被正确识别Nx 的路径映射生效myorg/agent-skills-calendar被解析到libs/agent-skills/calendar/src/index.ts模块打包无错误tsc能成功编译。至此一个可扩展、可测试、可发布的agent-skills工作区已搭建完成。后续新增技能如slack.sendMessage只需重复npx nx g nrwl/node:library步骤所有工程化能力自动继承。5. 生产环境避坑指南那些只有踩过才知道的暗礁搭建完成只是开始。在真实项目中agent-skills会遭遇一系列“文档不会写、教程不会教、但线上会炸”的问题。以下是我在