从零开发一个Coding Agent:monorepo项目搭建

本篇文章是《从零开发一个Coding Agent》系列第二篇,主要介绍如何使用npm搭建一个monorepo项目,以及如何管理多个子项目。

什么是monorepo项目

monorepo项目是指在一个代码仓库中管理多个子项目的项目。每个子项目都是一个独立的npm包,它们之间通过npm的依赖管理机制进行协调。npm workspaces 中,本地包之间仍然通过 package.json 声明依赖;区别是安装时 npm 会把依赖链接到本地 workspace,,而不是从 npm registry 下载。 举个例子: agent包 需要引用 ai 包。

根目录已经声明:

json 复制代码
{
  "workspaces": ["packages/*"]
}

packages/ai/package.json:

json 复制代码
{
  "name": "@di-code/ai",
  "version": "0.0.0"
}

在 packages/agent/package.json 中声明:

json 复制代码
{
  "name": "@di-code/agent",
  "version": "0.0.0",
  "dependencies": {
    "@di-code/ai": "0.0.0"
  }
}

然后从根目录安装: npm install

npm 会建立类似下面的本地链接:

text 复制代码
node_modules/@di-code/ai
    -> D:\pi\di-code\packages\ai

Windows 上实际可能是 junction(目录联接),但效果与符号链接一致,不会复制一份源码。 于是 agent 中可以像使用普通 npm 包一样导入:

javascript 复制代码
import type { Message } from "@di-code/ai";

不要使用跨目录相对导入:

javascript 复制代码
import type { Message } from "../../ai/src/types.js";

环境和目录

接下来我们就进入了项目的真正开发了,首先需要检查自己的环境是否符合要求。node版本至少为22.19.0

新建项目目录,我这里选择名称为di-code,并初始化根 package.json

json 复制代码
{
	"name": "di-code",
	"version": "0.0.0",
	"private": true,
	"type": "module",
	"workspaces": ["packages/*"],
	"scripts": {
		"build": "npm run build --workspace @di-code/tui && npm run build --workspace @di-code/ai && npm run build --workspace @di-code/agent && npm run build --workspace @di-code/coding-agent",
		"check": "biome check . && tsc --noEmit -p tsconfig.json",
		"test": "npm run test --workspaces --if-present"
	},
	"devDependencies": {
		"@biomejs/biome": "2.3.5",
		"@types/node": "22.19.19",
		"typescript": "5.9.3",
		"vitest": "4.1.9"
	},
	"engines": {
		"node": ">=22.19.0"
	}
}

关键字段说明:

  • private: true 防止对根聚合包执行意外发布。
  • type: module 确立根脚本的 ESM 语义。
  • workspaces 只匹配四个直接子包,不把未来示例或临时目录意外变成 workspace。
  • build 的显式顺序对应未来依赖方向。
  • check 先运行 Biome;只有 Biome 成功才运行 TypeScript。
  • test 将测试命令分发到所有定义了 test script 的 workspace。
  • 所有 devDependency 都使用精确版本,不使用 ^~

然后新建packages目录,用于存放所有的子项目。在该目录下创建ai, agent, coding-agent, tui四个子目录。 每个子目录下创建src目录,用于存放源代码。

TypeScript配置

在 根目录创建一个tsconfig.base.json文件:

json 复制代码
{
	"compilerOptions": {
		"target": "ES2022",
		"lib": ["ES2022"],
		"module": "NodeNext",
		"moduleResolution": "NodeNext",
		"strict": true,
		"erasableSyntaxOnly": true,
		"verbatimModuleSyntax": true,
		"noEmitOnError": true,
		"declaration": true,
		"declarationMap": true,
		"sourceMap": true,
		"inlineSources": true,
		"esModuleInterop": true,
		"forceConsistentCasingInFileNames": true,
		"skipLibCheck": true,
		"resolveJsonModule": true,
		"types": ["node"]
	}
}

部分选项说明:

  • target 决定输出 JavaScript 的语法基线;ES2022 在最低 Node 22 运行时上可用。
  • modulemoduleResolution 同时使用 NodeNext,让 TypeScript 按现代 Node.js 的 ESM/CJS 规则判断包边界。不要把一个改为 NodeNext、另一个留成旧的 node
  • strict 是项目约束,后续不得为了消除错误而关闭。
  • verbatimModuleSyntax 要求 import/export 写法与最终模块语义一致,并促使类型导入使用 import type
  • noEmitOnError 防止类型错误时留下看似可用的构建产物。
  • declarationdeclarationMap 为 workspace 公共类型生成 .d.ts 与映射。
  • sourceMapinlineSources 为后续调试保留源码定位。
  • skipLibCheck 只跳过第三方声明文件内部的检查,不跳过本项目源码检查。
  • types: ["node"] 明确引入 Node.js 全局类型,避免环境中其他 @types/* 包意外污染全局命名空间。

然后在根目录写入TS配置文件tsconfig.json

json 复制代码
{
	"extends": "./tsconfig.base.json",
	"compilerOptions": {
		"noEmit": true
	},
	"include": ["packages/*/src/**/*.ts", "packages/*/test/**/*.ts"],
	"exclude": ["**/node_modules/**", "**/dist/**"]
}

根配置的职责是全仓检查,不是构建:

  • include 同时覆盖源码和未来测试。
  • noEmit 保证 npm run check 不修改工作区。
  • dist 被排除,避免检查生成文件并重复报告问题。

编写四个 workspace package.json

在四个目录 ai, agent, coding-agent, tui 下创建 package.json 文件。它们的脚本和导出形状保持一致,名称和描述不同。

packages/ai/package.json

json 复制代码
{
	"name": "@di-code/ai",
	"version": "0.0.0",
	"description": "Provider-neutral AI contracts and adapters for di-code",
	"private": true,
	"type": "module",
	"main": "./dist/index.js",
	"types": "./dist/index.d.ts",
	"exports": {
		".": {
			"types": "./dist/index.d.ts",
			"import": "./dist/index.js"
		}
	},
	"scripts": {
		"build": "tsc -p tsconfig.build.json",
		"test": "vitest run --passWithNoTests"
	},
	"engines": {
		"node": ">=22.19.0"
	}
}

packages/agent/package.json

json 复制代码
{
	"name": "@di-code/agent",
	"version": "0.0.0",
	"description": "Core agent state and loop for di-code",
	"private": true,
	"type": "module",
	"main": "./dist/index.js",
	"types": "./dist/index.d.ts",
	"exports": {
		".": {
			"types": "./dist/index.d.ts",
			"import": "./dist/index.js"
		}
	},
	"scripts": {
		"build": "tsc -p tsconfig.build.json",
		"test": "vitest run --passWithNoTests"
	},
	"engines": {
		"node": ">=22.19.0"
	}
}

packages/coding-agent/package.json

json 复制代码
{
	"name": "@di-code/coding-agent",
	"version": "0.0.0",
	"description": "Coding agent product layer for di-code",
	"private": true,
	"type": "module",
	"main": "./dist/index.js",
	"types": "./dist/index.d.ts",
	"exports": {
		".": {
			"types": "./dist/index.d.ts",
			"import": "./dist/index.js"
		}
	},
	"scripts": {
		"build": "tsc -p tsconfig.build.json",
		"test": "vitest run --passWithNoTests"
	},
	"engines": {
		"node": ">=22.19.0"
	}
}

packages/tui/package.json

json 复制代码
{
	"name": "@di-code/tui",
	"version": "0.0.0",
	"description": "Reusable terminal UI library for di-code",
	"private": true,
	"type": "module",
	"main": "./dist/index.js",
	"types": "./dist/index.d.ts",
	"exports": {
		".": {
			"types": "./dist/index.d.ts",
			"import": "./dist/index.js"
		}
	},
	"scripts": {
		"build": "tsc -p tsconfig.build.json",
		"test": "vitest run --passWithNoTests"
	},
	"engines": {
		"node": ">=22.19.0"
	}
}
  • main 指向运行时 ESM 入口。
  • types 指向 TypeScript 声明入口。
  • exports 限制包的公开入口为根入口,防止后续调用者依赖内部文件路径。

编写 workspace 构建配置

在以下四个位置创建相同内容的 tsconfig.build.json

text 复制代码
packages\ai\tsconfig.build.json
packages\agent\tsconfig.build.json
packages\coding-agent\tsconfig.build.json
packages\tui\tsconfig.build.json

内容均为:

json 复制代码
{
	"extends": "../../tsconfig.base.json",
	"compilerOptions": {
		"rootDir": "./src",
		"outDir": "./dist"
	},
	"include": ["src/**/*.ts"],
	"exclude": ["node_modules", "dist", "test"]
}
  • extends 让四个包继承完全相同的严格模式和 ESM 语义。
  • rootDir 告诉编译器源码相对根为 src
  • outDir 使输出留在各自包内,不把不同包混到根 dist
  • build 只包含 src,测试不进入发布产物。

入口创建

在以下四个文件中各写一行:

text 复制代码
packages\ai\src\index.ts
packages\agent\src\index.ts
packages\coding-agent\src\index.ts
packages\tui\src\index.ts

内容:

ts 复制代码
export {};

配置 Biome 格式化工具

Biome 是面向 JavaScript、TypeScript、JSON 等文件的代码质量工具,简单来说就是ESLint + Prettier

di-code\biome.json 写入:

json 复制代码
{
	"$schema": "https://biomejs.dev/schemas/2.3.5/schema.json",
	"files": {
		"includes": [
			"package.json",
			"biome.json",
			"tsconfig*.json",
			"packages/*/package.json",
			"packages/*/tsconfig*.json",
			"packages/*/src/**/*.ts",
			"packages/*/test/**/*.ts"
		]
	},
	"formatter": {
		"enabled": true,
		"formatWithErrors": false,
		"indentStyle": "tab",
		"lineWidth": 120
	},
	"linter": {
		"enabled": true,
		"rules": {
			"recommended": true
		}
	}
}

编写 .gitignore

在根目录下创建 .gitignore 写入:

gitignore 复制代码
# Dependencies
node_modules/

# Build and test output
dist/
coverage/
*.tsbuildinfo

# Logs
*.log
npm-debug.log*

# Environment and credentials
.env
.env.*
!.env.example

# Editors and operating systems
.vscode/
.idea/
.DS_Store
Thumbs.db

这些都不需要提交代码仓库

安装依赖与构建

到这里我们基本已经完成了基础的 monorepo 配置。 接下来,我们可以开始安装依赖并构建项目。

bash 复制代码
npm install
npm run build

构建完成之后我们就能看到每个包下面都有一个 dist 目录,里面包含了编译后的代码。

最后执行一下检查,确保代码质量。

bash 复制代码
npm run check

如果 Biome 只报告格式差异,可以执行

powershell 复制代码
npx biome check --write package.json tsconfig.base.json tsconfig.json biome.json packages

进行修复,然后再执行 npm run check 确保格式符合要求。

到这里我们已经完成了基础的 monorepo 配置。本章节git分支Monorepo 初始化

相关推荐
葬送的代码人生1 小时前
别再让 AI 瞎写代码了!Vibe Coding 三步法教你写出靠谱代码
前端·设计模式·架构
FF2501_940228581 小时前
HarmonyOS开发实战:小分享-App项目架构全景解析
后端·华为·harmonyos·鸿蒙
Shirley~~1 小时前
Code-Review-Graph:面向 AI 辅助代码审查的结构化上下文引擎
前端·ai编程
长大19881 小时前
解决 PHP 常见内存溢出问题:从日志定位到代码优化实战
后端
大勇前进1 小时前
Composer 保姆级教程:依赖冲突、版本锁、国内镜像避坑
后端
AI多Agent协作实战派1 小时前
AI多Agent协作系统实战(十七):凌晨4点,我的AI系统在“假装工作“——3个bug同时爆炸的5小时
java·前端·bug
qq_2518364572 小时前
基于java Web 动漫视频网站毕业论文
java·开发语言·前端
未秃头的程序猿2 小时前
给公司做了个AI客服Agent,用的Spring AI 1.0,3天上线领导拍板了
java·后端·ai编程
an317422 小时前
6MB 组织树大文件性能优化全流程
前端·javascript·vue.js