从零构建AI Agent CLI:TypeScript工程化实践与工具链配置
1. 项目概述:为什么从零构建一个Agent CLI?
如果你关注过近两年的技术趋势,会发现“AI Agent”已经从一个前沿概念,变成了开发者工具箱里越来越常见的组件。无论是自动化代码审查、智能文档生成,还是复杂的业务流程编排,背后往往都有一个或多个Agent在协同工作。然而,当我们想亲手打造一个属于自己的Agent,并将其封装成一个命令行工具(CLI)时,常常会陷入一种困境:网上充斥着各种“五分钟快速入门”的框架教程,但当你真正想构建一个结构清晰、易于维护、测试完备的生产级项目时,却发现无从下手。框架帮你解决了“从0到0.5”的问题,但“从0.5到1”的工程化之路,才是决定项目能否长期健康发展的关键。
这正是我们启动这个系列的原因。我们不打算只教你用某个现成的框架“跑起来”一个Demo,而是要深入工程实践的腹地,从最基础的 项目初始化 和 工程基建 开始,一步步搭建一个高标准的TypeScript CLI项目骨架。这个骨架将具备现代前端工程的所有优秀特质:严格的类型安全、自动化的代码质量检查、单元测试覆盖、以及可复用的构建发布流程。你可以把它看作是为你的Agent大脑打造一个强健、可靠的“身体”。
为什么选择CLI作为载体?因为命令行是开发者与系统交互最直接、最强大的界面。一个设计良好的CLI工具,能够无缝融入开发者的工作流,无论是本地调试、CI/CD流水线,还是服务器端的自动化脚本。将你的Agent能力通过CLI暴露出来,意味着它具备了极强的可集成性和可扩展性。
在第一篇中,我们将聚焦于“基建”。这听起来可能不如直接实现AI功能那么激动人心,但我以多年的项目经验告诉你,前期在工程规范上投入的每一分钟,都会在后续的开发、协作和迭代中十倍地回报你。我们将使用TypeScript作为开发语言,搭配ESLint、Prettier、Vitest等工具链,目标是建立一个即便项目复杂度和团队规模增长,也能保持代码整洁和开发体验流畅的坚实基础。
2. 核心需求与工具选型解析
在动手写第一行代码之前,我们必须想清楚:我们要构建的究竟是一个什么样的CLI?它需要满足哪些核心需求?基于这些需求,我们又该如何选择技术栈?
2.1 核心需求定义
一个面向生产的Agent CLI,其核心需求远不止“能运行”那么简单:
- 类型安全与开发体验 :Agent的逻辑可能涉及复杂的数据结构(如LLM的请求/响应、工具调用规范)。静态类型检查能在编码阶段就捕获大量潜在错误,提供卓越的代码提示和重构能力,这对提升开发效率和代码可靠性至关重要。
- 代码质量与一致性 :当多人协作或项目长期演进时,统一的代码风格和避免常见的错误模式是维持代码库健康的基础。我们需要自动化工具来强制执行这些规范。
- 可测试性 :Agent的核心是逻辑与决策。我们必须能够方便地对这些逻辑进行单元测试、集成测试,确保每次修改都不会破坏现有功能,并为重构提供信心。
- 良好的开发者体验(DX) :包括清晰的错误提示、丰富的命令行帮助、易于理解的参数解析以及平滑的调试流程。
- 可维护性与可扩展性 :项目结构应该清晰,模块职责分明,便于后续添加新的命令、集成新的AI模型或工具。
- 打包与分发 :最终产物应该是一个可以全局安装、独立运行的二进制文件,并且最好能支持跨平台。
2.2 技术栈选型与理由
基于以上需求,我们做出如下选型,并解释其背后的考量:
-
语言:TypeScript
- 理由 :它是满足“类型安全”需求的不二之选。对于CLI项目,其强类型系统能完美约束命令行参数、配置对象以及Agent内部复杂的流程状态。相较于纯JavaScript,它能极大减少运行时因类型错误导致的崩溃。社区生态和类型定义文件也极其完善。
-
包管理与项目初始化:
npm init/pnpm init- 理由 :
npm是Node.js生态的事实标准。近年来,pnpm因其更快的速度和高效的磁盘空间利用(通过硬链接和符号链接)而备受青睐,尤其适合Monorepo场景。本系列将使用pnpm,但其命令与npm大多兼容。选择哪个取决于团队偏好,pnpm在性能上确有优势。
- 理由 :
-
代码质量工具链:ESLint + Prettier
- ESLint :用于识别并报告JavaScript/TypeScript代码中的问题模式,确保代码质量。我们可以配置适用于TypeScript的规则集(如
@typescript-eslint),并继承一些优秀的开源配置(如Airbnb、Standard),快速建立规范。 - Prettier :一个“有主见”的代码格式化工具。它接管了所有关于代码风格的决策(缩进、分号、引号等),让开发者从无休止的风格争论中解放出来,并与ESLint分工合作(ESLint负责代码质量问题,Prettier负责风格问题)。
- ESLint :用于识别并报告JavaScript/TypeScript代码中的问题模式,确保代码质量。我们可以配置适用于TypeScript的规则集(如
-
测试框架:Vitest
- 理由 :这是一个基于Vite的下一代测试框架。它与Vite共享配置、转换器和解析器,速度极快,对TypeScript和ES模块的支持是原生级的。其API与Jest高度兼容,学习成本低,但拥有更优秀的开发体验(如智能监听、模块级模拟)。对于新项目,Vitest是比Jest更现代、更快速的选择。
-
构建与打包工具:
tsup或tsx- 理由 :我们需要将TypeScript源代码编译、打包成单一的、可在Node.js环境运行的JavaScript文件。
tsup基于esbuild,配置极其简单,打包速度飞快,非常适合CLI工具。它支持生成CommonJS和ESM格式,并能将依赖打包进去(通过--bundle),减少用户环境依赖问题。tsx则更侧重于开发时的即时执行,可以作为tsup的补充。
- 理由 :我们需要将TypeScript源代码编译、打包成单一的、可在Node.js环境运行的JavaScript文件。
-
命令行框架:
commander.js或cac- 理由 :解析命令行参数、生成帮助信息是CLI的基础功能。使用成熟的框架能避免重复造轮子,处理复杂的子命令、选项、参数验证等。
commander.js历史悠久、功能全面、文档完善;cac更轻量、更现代。我们将根据项目复杂度进行选择。
- 理由 :解析命令行参数、生成帮助信息是CLI的基础功能。使用成熟的框架能避免重复造轮子,处理复杂的子命令、选项、参数验证等。
注意 :工具选型没有绝对的“最佳”,只有“最适合”。这里的选择是基于当前(2024年)社区主流趋势、项目需求和个人偏好的平衡。例如,如果你对Jest更熟悉,完全可以用Jest替代Vitest,核心的工程化思想是相通的。
3. 项目初始化与基础配置实操
理论说再多,不如动手做。现在,让我们打开终端,开始搭建项目。
3.1 创建项目并初始化
首先,为你的Agent CLI项目创建一个新目录并进入。
mkdir my-agent-cli && cd my-agent-cli
接着,初始化 package.json 。这里我使用 pnpm ,如果你用 npm ,将 pnpm 替换为 npm 即可。
pnpm init
你会被提示输入项目名称、版本、描述等信息。这里可以先快速按回车使用默认值,我们稍后再来修改 package.json 。一个更高效的方式是使用 -y 参数快速生成默认配置:
pnpm init -y
现在,你的目录下应该有了一个基础的 package.json 文件。
3.2 安装TypeScript及基础依赖
安装TypeScript作为开发依赖,同时安装Node.js的类型定义,因为我们的CLI会运行在Node环境中。
pnpm add -D typescript @types/node
-D 参数表示将这些包安装在 devDependencies 中,因为它们是开发工具,最终用户不需要。
接下来,生成TypeScript配置文件 tsconfig.json :
npx tsc --init
这个命令会创建一个包含大量默认选项(大部分被注释掉)的 tsconfig.json 文件。对于CLI项目,我们需要一个针对性更强的配置。让我们直接替换其内容:
{
"compilerOptions": {
/* 基础选项 */
"target": "ES2022", // 编译目标ES版本,现代Node.js支持ES2022
"module": "ESNext", // 使用ES模块,便于tree-shaking和现代打包工具
"lib": ["ES2022"],
"moduleResolution": "bundler", // 配合现代打包工具的解析策略
"resolveJsonModule": true, // 允许导入JSON文件
"allowSyntheticDefaultImports": true,
/* 类型检查与严格模式 */
"strict": true, // 启用所有严格类型检查选项
"skipLibCheck": true, // 跳过库文件的类型检查以提升速度
"noUnusedLocals": true, // 报告未使用的局部变量
"noUnusedParameters": true, // 报告未使用的函数参数
"noFallthroughCasesInSwitch": true, // 防止switch语句贯穿
/* 输出控制 */
"outDir": "./dist", // 编译输出目录
"rootDir": "./src", // 源代码根目录
"declaration": true, // 生成.d.ts类型声明文件
"declarationMap": true, // 为声明文件生成sourcemap
"sourceMap": true, // 为JavaScript生成sourcemap,便于调试
/* 其他 */
"esModuleInterop": true, // 改善CommonJS和ES模块的互操作性
"forceConsistentCasingInFileNames": true // 强制文件名大小写一致
},
"include": ["src/**/*"], // 包含src目录下所有文件
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] // 排除不需要编译的文件
}
关键配置解读 :
“target”: “ES2022”:Node.js 18+ 已良好支持 ES2022 特性,选择较新的目标版本能生成更简洁的代码。“module”: “ESNext”和“moduleResolution”: “bundler”:这是为使用tsup、Vite等现代打包工具做的准备,它们能更好地处理 ES 模块。“outDir”和“rootDir”:清晰地分离源代码(src)和编译产物(dist),这是保持项目结构清晰的好习惯。“strict”: true: 强烈建议开启 。严格的类型检查初期可能会让你多写一些类型注解,但它能避免无数潜在的运行时错误,是TypeScript价值的核心体现。
3.3 配置ESLint与Prettier(代码质量守卫)
首先,安装ESLint及其相关插件:
pnpm add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier
eslint: ESLint核心库。@typescript-eslint/parser: 使ESLint能够解析TypeScript语法。@typescript-eslint/eslint-plugin: 提供针对TypeScript的linting规则。eslint-config-prettier: 关闭所有与Prettier冲突的ESLint规则,让两者和谐共处。
接下来,创建ESLint配置文件 .eslintrc.cjs (使用 .cjs 扩展名确保在Node环境下能被正确识别为CommonJS模块):
// .eslintrc.cjs
module.exports = {
root: true, // 表明这是根配置文件,ESLint将不再向上查找
env: {
node: true, // 启用Node.js全局变量和语法
es2022: true, // 启用ES2022全局变量
},
parser: '@typescript-eslint/parser', // 指定TypeScript解析器
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module', // 使用ES模块
project: './tsconfig.json', // 告诉ESLint你的tsconfig位置,用于基于类型的规则
},
plugins: ['@typescript-eslint'], // 加载TypeScript插件
extends: [
'eslint:recommended', // ESLint推荐规则
'plugin:@typescript-eslint/recommended-type-checked', // TS推荐规则(需要类型信息)
'plugin:@typescript-eslint/stylistic-type-checked', // TS风格规则
'prettier', // 必须放在最后,用于禁用与Prettier冲突的规则
],
rules: {
// 可以在这里覆盖或添加自定义规则
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
], // 允许以下划线开头的变量未使用(常用于忽略参数)
},
ignorePatterns: ['dist', 'node_modules', '*.cjs', '*.js'], // 忽略这些目录和文件
};
一个常见陷阱 :如果你在配置中启用了需要类型信息的规则(如 recommended-type-checked ),但在VSCode或其他编辑器里ESLint仍然报错,提示找不到某些模块或类型(例如网络热词中提到的“amap is undefined”),这通常是因为ESLint没有正确读取到 tsconfig.json 中的 compilerOptions.paths 别名配置,或者项目依赖没有完全安装。确保:
parserOptions.project路径正确。- 运行
pnpm install确保所有依赖已安装。 - 在VSCode中,可以尝试重启ESLint服务器或重新加载窗口。
现在,安装并配置Prettier:
pnpm add -D prettier
创建Prettier配置文件 .prettierrc.json :
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"endOfLine": "lf"
}
这些是常见的Prettier配置,定义了分号、单引号、缩进等格式规则。你可以根据团队习惯调整。
最后,我们需要一个机制让ESLint和Prettier在代码保存时自动运行。这通常由编辑器的插件(如VSCode的ESLint和Prettier插件)配合设置实现。但为了确保团队一致性,我们还可以在 package.json 中定义脚本,并配置 lint-staged 和 husky 在提交前自动检查。这是更高级的工程化步骤,我们可以在后续篇章展开。
3.4 配置Vitest(测试堡垒)
安装Vitest及相关工具:
pnpm add -D vitest @vitest/ui
vitest: 测试框架本身。@vitest/ui: 提供一个漂亮的图形化测试界面,便于调试和查看覆盖率。
创建Vitest配置文件 vitest.config.ts :
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true, // 类似Jest,允许使用describe, it, expect等全局API
environment: 'node', // 测试环境设为Node.js
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], // 测试文件匹配模式
coverage: {
provider: 'v8', // 使用Node.js内置的V8覆盖率收集器
reporter: ['text', 'json', 'html'], // 生成多种格式的覆盖率报告
exclude: ['**/*.test.ts', '**/*.spec.ts', 'dist', 'node_modules'], // 排除项
},
},
});
现在,更新 package.json ,添加测试脚本:
{
"scripts": {
"test": "vitest",
"test:ui": "vitest --ui",
"test:coverage": "vitest run --coverage",
"type-check": "tsc --noEmit" // 只做类型检查,不输出文件
}
}
让我们立刻验证一下。创建源代码目录和第一个测试文件:
mkdir src
// src/math.test.ts
import { describe, it, expect } from 'vitest';
function add(a: number, b: number): number {
return a + b;
}
describe('math functions', () => {
it('should add two numbers correctly', () => {
expect(add(1, 2)).toBe(3);
expect(add(-1, 5)).toBe(4);
});
});
运行测试:
pnpm test
你应该能看到测试通过的输出。运行 pnpm test:ui 可以打开浏览器查看图形化界面。
3.5 配置构建脚本与入口
我们的CLI需要一个入口点。创建 src/cli.ts 作为主入口文件:
#!/usr/bin/env node
// 上面的shebang行告诉系统这个文件应该用Node.js来执行
import { program } from 'commander'; // 我们稍后会安装commander
program
.name('my-agent') // 你的CLI工具名
.description('一个强大的AI Agent命令行工具')
.version('0.1.0'); // 从package.json读取版本号更好,这里先写死
program.parse(process.argv);
现在,我们需要一个构建脚本,将TypeScript编译打包成可执行文件。安装 tsup :
pnpm add -D tsup
在 package.json 中添加构建脚本和 bin 字段, bin 字段用于指定当用户全局安装你的包时,哪个命令对应哪个可执行文件。
{
"name": "my-agent-cli",
"version": "0.1.0",
"description": "A powerful AI Agent CLI tool",
"main": "dist/cli.js",
"bin": {
"my-agent": "./dist/cli.js" // 命令名: 入口文件路径
},
"scripts": {
"build": "tsup src/cli.ts --format cjs,esm --dts --clean --minify",
"dev": "tsup src/cli.ts --format cjs --watch",
"start": "node dist/cli.js",
// ... 之前添加的test脚本
},
// ... 其他字段
}
tsup 配置解释:
src/cli.ts: 入口文件。--format cjs,esm: 同时生成CommonJS和ES Module格式。--dts: 生成类型声明文件(.d.ts)。--clean: 构建前清理dist目录。--minify: 压缩代码。--watch(在dev脚本中): 监听文件变化并重新构建。
现在,运行 pnpm build ,你会在 dist 目录下看到生成的文件。为了在开发时方便地测试CLI,我们可以使用 pnpm link 在本地创建一个全局软链接:
# 在项目根目录执行
pnpm link --global
执行后,理论上你就可以在终端任何地方运行 my-agent 命令了。它会执行 dist/cli.js 。试试看:
my-agent --help
你应该能看到 commander 生成的帮助信息(目前只有版本和描述)。
4. 工程化进阶:Git Hooks与自动化工作流
基础配置完成后,我们可以引入一些“守卫”来自动化代码质量流程,确保提交到仓库的代码是符合规范的。
4.1 配置Husky与lint-staged
Husky 允许我们方便地定义Git钩子(如 pre-commit , pre-push )。 lint-staged 则允许我们对**暂存区(staged)**的文件运行特定的脚本,避免每次提交都检查整个项目。
安装依赖:
pnpm add -D husky lint-staged
初始化Husky:
npx husky init
这个命令会创建 .husky 目录,并在其中添加 pre-commit 钩子文件。同时,它会在 package.json 中添加一个 “prepare”: “husky install” 脚本。
现在,配置 lint-staged 。在 package.json 中添加:
{
// ... 其他配置
"lint-staged": {
"*.{js,ts,jsx,tsx}": [
"eslint --fix --max-warnings=0", // 对暂存区的JS/TS文件运行ESLint并自动修复
"prettier --write" // 运行Prettier格式化
],
"*.{json,md,yml,yaml}": [
"prettier --write" // 格式化其他类型的文件
]
}
}
然后,修改 .husky/pre-commit 文件,将其内容替换为:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged
npx vitest run --changed # 可选:对更改的文件运行测试
这样,每次执行 git commit 时, lint-staged 会自动对暂存区中符合条件的文件执行ESLint修复和Prettier格式化。如果ESLint有无法自动修复的错误或测试失败,提交就会被阻止。
4.2 完善package.json与项目结构
让我们回头完善一下 package.json ,添加一些元信息和更合理的脚本。
{
"name": "my-agent-cli",
"version": "0.1.0",
"description": "A powerful AI Agent CLI tool built with TypeScript",
"keywords": ["cli", "agent", "ai", "typescript", "automation"],
"license": "MIT",
"author": "Your Name <your.email@example.com>",
"homepage": "https://github.com/your-username/my-agent-cli#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/your-username/my-agent-cli.git"
},
"bugs": {
"url": "https://github.com/your-username/my-agent-cli/issues"
},
"type": "module", // 声明包使用ES模块,影响Node.js如何解析导入
"main": "./dist/cli.js",
"module": "./dist/cli.mjs", // 为ESM打包工具提供入口
"types": "./dist/cli.d.ts", // 类型声明文件入口
"bin": {
"my-agent": "./dist/cli.js"
},
"files": ["dist"], // 发布到npm时只包含dist目录
"scripts": {
"dev": "tsup src/cli.ts --format cjs --watch",
"build": "tsup src/cli.ts --format cjs,esm --dts --clean --minify",
"start": "node dist/cli.js",
"lint": "eslint . --ext .ts,.js --fix --max-warnings=0",
"format": "prettier --write .",
"type-check": "tsc --noEmit",
"test": "vitest",
"test:ui": "vitest --ui",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"prepublishOnly": "npm run build", // 在npm publish前自动构建
"prepare": "husky install"
},
"engines": {
"node": ">=18"
},
"publishConfig": {
"access": "public"
},
// ... dependencies and devDependencies
}
项目结构梳理 : 至此,你的项目目录结构应该大致如下:
my-agent-cli/
├── .husky/ # Git钩子配置
│ └── pre-commit
├── .vscode/ # (可选)编辑器配置
├── dist/ # 构建输出目录(由tsup生成,应在.gitignore中)
├── src/ # 源代码目录
│ ├── cli.ts # CLI主入口
│ └── math.test.ts # 示例测试文件
├── .eslintrc.cjs # ESLint配置
├── .eslintignore # (可选)ESLint忽略文件配置
├── .prettierrc.json # Prettier配置
├── .prettierignore # (可选)Prettier忽略文件配置
├── .gitignore # Git忽略文件配置
├── vitest.config.ts # Vitest配置
├── tsconfig.json # TypeScript配置
├── package.json # 项目配置和依赖
└── pnpm-lock.yaml # pnpm锁文件(如果是npm则是package-lock.json)
务必在 .gitignore 文件中添加 dist/ , node_modules/ , coverage/ 等目录。
5. 常见问题与排查技巧实录
在搭建这套基建的过程中,你几乎一定会遇到一些问题。以下是我在实际操作中踩过的坑和解决方案,希望能帮你快速排雷。
5.1 TypeScript配置与模块解析问题
问题 :在 src/cli.ts 中导入其他模块时,VS Code提示“找不到模块”或“没有默认导出”,但运行 tsc --noEmit 类型检查却通过。 排查 :
- 检查
tsconfig.json中的“moduleResolution”。如果你使用了“bundler”,确保你的打包工具(如tsup)支持它。对于更传统的Node.js项目,可以尝试改为“node16”或“nodenext”。 - 检查导入路径是否正确。使用相对路径(
‘./utils’)或配置了“paths”的别名。 - 重启TypeScript语言服务器。在VS Code中,按
Cmd+Shift+P(Mac) 或Ctrl+Shift+P(Windows/Linux),输入并选择“TypeScript: Restart TS Server”。
5.2 ESLint与Prettier冲突或报错
问题 :保存文件时,ESLint和Prettier互相“打架”,或者ESLint报告一些奇怪的语法错误(如网络热词中的 object-curly-spacing 错误)。 解决 :
- 确保配置顺序正确 :在
.eslintrc.cjs的extends数组中,‘prettier’必须放在 最后 ,以确保它能覆盖其他配置中与Prettier冲突的规则。 - 检查规则覆盖 :有时某个插件(如
@typescript-eslint)的规则会与Prettier冲突。eslint-config-prettier就是用来解决这个的。确保你已安装并正确扩展了它。 - 规则具体配置 :像
object-curly-spacing这类风格规则,应该完全交给Prettier处理。如果ESLint还在报错,可以在.eslintrc.cjs的rules中显式关闭它:“object-curly-spacing”: “off”。但更推荐的做法是确保eslint-config-prettier生效。 - 编辑器插件设置 :在VS Code中,确保设置了
“editor.formatOnSave”: true,并且“editor.defaultFormatter”是你的Prettier插件。同时,确保ESLint插件已启用并配置为在保存时运行。有时需要设置“eslint.validate”包含“typescript”。
5.3 Vitest测试无法识别或运行缓慢
问题 : pnpm test 找不到测试文件,或者测试运行异常缓慢。 排查 :
- 检查配置文件 :确认
vitest.config.ts中的test.include模式能匹配到你的测试文件。测试文件通常以.test.ts或.spec.ts结尾。 - 检查环境 :如果你的代码依赖浏览器API(如
document,window),但测试环境配置为“node”,就会出错。对于CLI项目,环境应为“node”。如果部分代码需要浏览器环境,可以考虑使用jsdom环境,或使用vi.mock进行模拟。 - 速度问题 :首次运行Vitest可能会稍慢,因为它要收集和转换测试。后续运行在
watch模式下会很快。如果一直很慢,检查是否在测试中引入了巨大的模块或进行了真实的网络请求/文件IO。尽量使用模拟(mock)。
5.4 构建产物无法运行或行为异常
问题 : pnpm build 成功,但运行 node dist/cli.js 或全局链接后的命令报错(如 Cannot find module )。 排查 :
- 检查shebang :确保
src/cli.ts第一行是#!/usr/bin/env node。 - 检查
package.json中的bin字段 :路径是否正确指向构建后的文件(例如./dist/cli.js)。 - 检查依赖打包 :如果你的CLI依赖了某些第三方包,默认情况下
tsup不会将它们打包进输出文件。这意味着用户安装你的CLI时,必须同时安装这些依赖。对于简单的CLI,可以将依赖放在dependencies中。对于希望生成单一可执行文件的情况,可以使用tsup的--bundle标志(注意处理原生模块等边界情况)。更复杂的打包可以考虑pkg或nexe。 - 文件权限 :在Unix系统上,构建后的JS文件需要有可执行权限。
tsup通常不会设置这个权限。你可以在package.json的“scripts”中添加一个后置脚本,例如在build后执行chmod +x dist/cli.js。或者,更规范的做法是,在npm publish后,由npm在全局安装时自动处理。
5.5 Git Hooks不生效
问题 :配置了Husky和lint-staged,但提交时代码没有被检查或格式化。 排查 :
- Husky是否安装成功 :确保项目根目录下有
.husky文件夹,并且里面的钩子文件(如pre-commit)有可执行权限(在Unix系统上)。你可以手动运行chmod +x .husky/pre-commit。 -
prepare脚本是否运行 :Husky的安装通常由npm install或pnpm install后自动运行的prepare脚本触发。如果你克隆了一个已有项目,可能需要手动运行一次pnpm prepare或pnpm install。 - lint-staged配置 :检查
package.json中的lint-staged配置路径和命令是否正确。可以手动运行npx lint-staged来测试。 - Git版本 :确保你的Git版本在2.9以上,Husky对旧版本支持可能有问题。
搭建一个坚实的工程基础,就像为高楼打下地基。虽然前期花费了一些时间在配置上,但当你开始真正编写Agent业务逻辑时,你会感谢现在所做的一切:代码提示精准、错误在编写时就被捕获、代码风格统一、测试运行迅速、提交前自动检查。这一切都将使你的开发体验变得顺畅,并极大地提升项目的可维护性。
在下一篇中,我们将在这个坚实的基建之上,开始设计并实现我们Agent CLI的核心命令解析架构,并接入第一个AI模型,让我们的工具真正“智能”起来。你会发现,有了好的工程习惯,添加新功能将变得有条不紊,水到渠成。
更多推荐



所有评论(0)