ECC coding-standards 技能详解:TypeScript、React 与 API 设计的跨项目编码规范
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
ECC(The agent harness performance optimization system)将一套通用的 TypeScript/JavaScript、React 与 Node.js 编码规范封装为 Kiro 平台的按需技能coding-standards,安装到项目后可通过聊天/菜单直接调用,用于代码审查、新模块起步和团队规范落地。本文完整拆解该技能的规范体系——四大质量原则、命名与不可变性准则、React 与 API 设计标准、性能与测试规范、代码坏味道检测清单——并结合 ECC 仓库中的规则层文件与 ESLint 配置,说明这些规范如何在工程中真正被约束和验证。读完后,你既能把这份规范直接套用到自己的 TS/React 项目中,也能理解它在 ECC 分层体系中的定位与配套落地手段。
一、coding-standards 是什么:Kiro 技能机制与激活时机
该技能定义在.kiro/skills/coding-standards/SKILL.md,文件以 YAML frontmatter 声明元数据:
--- name: coding-standards description: > Universal coding standards, best practices, and patterns for TypeScript, JavaScript, React, and Node.js development. metadata: origin: ECC ---根据.kiro/README.md的说明,.kiro/skills/目录下共安装了 43 个技能,它们是“可经由聊天/菜单按需调用的工作流”(Skills are on-demand workflows invocable via the/menu in chat)。每个技能都是一个包含SKILL.md的目录,frontmatter 中的name决定菜单中的可调用名称,description决定其语义边界。因此开发者在 Kiro 中输入/并选择coding-standards,即可让 Agent 以这份规范为审查/编码基准开展工作。
技能文档同时明确了激活场景(When to Activate),即这份规范适用于以下六类工作:
- 启动新项目或新模块
- 以质量与可维护性为目标审查代码
- 重构既有代码以符合约定
- 强制执行命名、格式或结构一致性
- 配置 lint、格式化或类型检查规则
- 帮助新贡献者了解编码约定
需要注意技能的范围定位。ECC 主仓中对应的基线版技能skills/coding-standards/SKILL.md在 frontmatter 之后额外给出了明确的边界说明:它是“共享的底线,而非详细框架手册”(the shared floor, not the detailed framework playbook)——
- React 组合、hooks、渲染与 UI 架构问题应使用
frontend-patterns; - 后端架构、API 设计、数据库分层应使用
backend-patterns或api-design; - 只需要最短可复用规则层时,应参考
rules/common/coding-style.md。
这种“技能管完整流程、规则管最小约束”的分层设计,是 ECC 规范体系的一个重要特征,后文第四节会结合具体文件展开。
二、代码质量四原则:Readability、KISS、DRY、YAGNI
技能的第一部分确立了四条贯穿全部后续规范的质量原则,理解它们是读懂其余条款的钥匙。
1. Readability First(可读性优先)
- 代码被阅读的次数远多于被编写的次数
- 变量与函数命名必须清晰
- 自解释代码优于注释
- 保持格式一致
2. KISS(Keep It Simple, Stupid)
- 采用能工作的最简单方案
- 避免过度设计
- 不做过早优化
- 易理解的代码 > 炫技的代码
3. DRY(Don't Repeat Yourself)
- 将公共逻辑提取为函数
- 创建可复用组件
- 跨模块共享工具
- 杜绝复制粘贴式编程
4. YAGNI(You Aren't Gonna Need It)
- 不提前构建尚不需要的功能
- 避免臆测性泛化(speculative generality)
- 仅在确有需求时引入复杂度
- 从简单开始,必要时再重构
ECC 的规则层文件rules/common/coding-style.md将这同一套原则压缩成了更短的可复用表述,例如 DRY 条目补充了一条实践判断标准:“Introduce abstractions when repetition is real, not speculative”(当重复是真实存在的而非臆测时才引入抽象),YAGNI 条目则强调 “Start simple, then refactor when the pressure is real”(从简单开始,等压力真实到来时再重构)。技能版讲“何时激活什么行为”,规则版给“最短可执行判据”,两者互为表里。
三、TypeScript/JavaScript 规范:命名、不可变性、错误处理与类型安全
这是技能的核心章节,全部采用 PASS/FAIL 对照代码示例,可直接作为代码审查清单使用。
3.1 变量命名:描述性名称
// PASS: GOOD: Descriptive names const marketSearchQuery = 'election' const isUserAuthenticated = true const totalRevenue = 1000 // FAIL: BAD: Unclear names const q = 'election' const flag = true const x = 1000要点:布尔变量使用is/has/should/can前缀表达语义(isUserAuthenticated),名称应承载业务含义而非缩写。
3.2 函数命名:动词-名词模式
// PASS: GOOD: Verb-noun pattern async function fetchMarketData(marketId: string) { } function calculateSimilarity(a: number[], b: number[]) { } function isValidEmail(email: string): boolean { } // FAIL: BAD: Unclear or noun-only async function market(id: string) { } function similarity(a, b) { } function email(e) { }纯名词(market、email)无法表达函数“做什么”,应统一采用fetchMarketData、calculateSimilarity这类动词-名词结构,并在参数与返回值上补全类型。
3.3 不可变性模式(技能标记为 CRITICAL)
// PASS: ALWAYS use spread operator const updatedUser = { ...user, name: 'New Name' } const updatedArray = [...items, newItem] // FAIL: NEVER mutate directly user.name = 'New Name' // BAD items.push(newItem) // BAD这是技能中唯一被标注为 “CRITICAL” 的条目。ECC 的规则层对此给出了统一的伪代码判据(见rules/common/coding-style.md):
WRONG: modify(original, field, value) → changes original in-place CORRECT: update(original, field, value) → returns new copy with change其理由写明:不可变数据可防止隐藏副作用、让调试更容易、并支持安全的并发。值得注意的是,技能允许有意识地违反这一默认值,但必须在注释中说明原因——注释规范章节(第六节)的示例正是如此:// Deliberately using mutation here for performance with large arrays配合items.push(newItem)。规则是默认值,带理由的例外优于无理由的遵守。
3.4 错误处理:全面而非缺失
// PASS: GOOD: Comprehensive error handling async function fetchData(url: string) { try { const response = await fetch(url) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } return await response.json() } catch (error) { console.error('Fetch failed:', error) throw new Error('Failed to fetch data') } } // FAIL: BAD: No error handling async function fetchData(url) { const response = await fetch(url) return response.json() }模式拆解:先用response.ok拦截 HTTP 层失败并抛出自带状态码的明确错误,再在catch中记录详细上下文(console.error带原始 error 对象)并向上传播精简后的错误消息。这与规则层“错误处理”章节的四条要求一一对应:每一层显式处理、面向 UI 的代码提供用户友好消息、服务端记录详细上下文、绝不静默吞错(Never silently swallow errors)。
3.5 Async/Await:能并行就并行
// PASS: GOOD: Parallel execution when possible const [users, markets, stats] = await Promise.all([ fetchUsers(), fetchMarkets(), fetchStats() ]) // FAIL: BAD: Sequential when unnecessary const users = await fetchUsers() const markets = await fetchMarkets() const stats = await fetchStats()无依赖关系的多个异步调用应使用Promise.all并发执行;串行await会把总耗时累加为各请求之和。
3.6 类型安全:拒绝any
// PASS: GOOD: Proper types interface Market { id: string name: string status: 'active' | 'resolved' | 'closed' created_at: Date } function getMarket(id: string): Promise<Market> { // Implementation } // FAIL: BAD: Using 'any' function getMarket(id: any): Promise<any> { // Implementation }示例中status字段使用字符串字面量联合('active' | 'resolved' | 'closed')而非enum,与 ECC 的 TypeScript 规则层rules/typescript/coding-style.md的建议一致:对象形状用interface(可被扩展/实现),联合、交叉、元组与工具类型用type,并优先字符串字面量联合代替enum。该规则文件还进一步给出any的替代路径——对外部/不可信输入使用unknown再安全收窄:
// CORRECT: unknown forces safe narrowing function getErrorMessage(error: unknown): string { if (error instanceof Error) { return error.message } return 'Unexpected error' }该规则文件顶部带有pathsfrontmatter(**/*.ts、**/*.tsx、**/*.js、**/*.jsx),说明 ECC 的规则按 glob 路径条件注入——这正是“规则管最小约束、按文件类型生效”的实现方式。
四、React 最佳实践:组件、Hooks、状态与条件渲染
4.1 组件结构:函数式组件 + 显式 Props 类型
// PASS: GOOD: Functional component with types interface ButtonProps { children: React.ReactNode onClick: () => void disabled?: boolean variant?: 'primary' | 'secondary' } export function Button({ children, onClick, disabled = false, variant = 'primary' }: ButtonProps) { return ( <button onClick={onClick} disabled={disabled} className={`btn btn-${variant}`} > {children} </button> ) } // FAIL: BAD: No types, unclear structure export function Button(props) { return <button onClick={props.onClick}>{props.children}</button> }示例涵盖了技能隐含的组件四要素:命名interface定义 Props(而非React.FC,规则层明确 “Do not useReact.FCunless there is a specific reason”)、解构 + 默认值参数、回调属性显式类型、variant用字面量联合收敛取值范围。
4.2 自定义 Hooks:可复用的防抖示例
// PASS: GOOD: Reusable custom hook export function useDebounce<T>(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState<T>(value) useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value) }, delay) return () => clearTimeout(handler) }, [value, delay]) return debouncedValue } // Usage const debouncedQuery = useDebounce(searchQuery, 500)实现要点:泛型<T>使 hook 适用于任意值类型;useEffect依赖[value, delay];清理函数clearTimeout保证值变化时旧定时器不残留——这是手写防抖 hook 最容易漏掉的一环。
4.3 状态管理:函数式更新
// PASS: GOOD: Proper state updates const [count, setCount] = useState(0) // Functional update for state based on previous state setCount(prev => prev + 1) // FAIL: BAD: Direct state reference setCount(count + 1) // Can be stale in async scenariossetCount(count + 1)读取的是当前渲染周期的闭包值,在事件循环、异步回调或连续触发场景下可能拿到过期状态;setCount(prev => prev + 1)始终基于最新状态计算,应作为默认写法。
4.4 条件渲染:拒绝三目嵌套地狱
// PASS: GOOD: Clear conditional rendering {isLoading && <Spinner />} {error && <ErrorMessage error={error} />} {data && <DataDisplay data={data} />} // FAIL: BAD: Ternary hell {isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}短路与并列布尔表达式比多层嵌套三目更易读、更易局部修改;isLoading && <Spinner />这类写法在三个状态互斥时同样成立(假值不渲染任何有意义的东西)。
五、API 设计标准:REST 约定、统一响应格式与 Zod 校验
5.1 REST 资源路由约定
GET /api/markets # List all markets GET /api/markets/:id # Get specific market POST /api/markets # Create new market PUT /api/markets/:id # Update market (full) PATCH /api/markets/:id # Update market (partial) DELETE /api/markets/:id # Delete market # Query parameters for filtering GET /api/markets?status=active&limit=10&offset=0资源用名词复数、全量/部分更新分别用PUT/PATCH、过滤与分页走查询参数(status/limit/offset)——这是与响应结构中meta.total/page/limit字段相互呼应的分页契约。
5.2 统一响应结构
// PASS: GOOD: Consistent response structure interface ApiResponse<T> { success: boolean data?: T error?: string meta?: { total: number page: number limit: number } } // Success response return NextResponse.json({ success: true, data: markets, meta: { total: 100, page: 1, limit: 10 } }) // Error response return NextResponse.json({ success: false, error: 'Invalid request' }, { status: 400 })泛型ApiResponse<T>让每个端点复用同一信封:成功时success: true携带data(分页接口附带meta),失败时success: false携带error字符串并配正确的 HTTP 状态码。前端因此只需一套解包逻辑即可处理所有端点。
5.3 输入校验:Zod Schema 在系统边界拦截
import { z } from 'zod' // PASS: GOOD: Schema validation const CreateMarketSchema = z.object({ name: z.string().min(1).max(200), description: z.string().min(1).max(2000), endDate: z.string().datetime(), categories: z.array(z.string()).min(1) }) export async function POST(request: Request) { const body = await request.json() try { const validated = CreateMarketSchema.parse(body) // Proceed with validated data } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json({ success: false, error: 'Validation failed', details: error.errors }, { status: 400 } } } }要点:Schema 即接口契约(长度限制min/max、ISO 日期校验z.string().datetime()、非空数组min(1));parse失败时返回400并回传校验详情,让调用方一次修全。这一点与规则层“输入校验”章节的边界原则直接对应:“ALWAYS validate at system boundaries”“Never trust external data (API responses, user input, file content)”——外部数据在边界处校验失败要快速失败(Fail fast)并给出清晰错误消息。一个小的版本差异值得留意:ECC 主仓的基线版技能skills/coding-standards/SKILL.md在同一段示例中回传的是error.issues(较新 Zod 版本的属性名),而 Kiro 版使用error.errors——实际项目中以所用 Zod 版本的 API 为准即可,两者语义相同。
六、文件组织与命名约定
6.1 项目结构(以 Next.js App Router 为例)
src/ ├── app/ # Next.js App Router │ ├── api/ # API routes │ ├── markets/ # Market pages │ └── (auth)/ # Auth pages (route groups) ├── components/ # React components │ ├── ui/ # Generic UI components │ ├── forms/ # Form components │ └── layouts/ # Layout components ├── hooks/ # Custom React hooks ├── lib/ # Utilities and configs │ ├── api/ # API clients │ ├── utils/ # Helper functions │ └── constants/ # Constants ├── types/ # TypeScript types └── styles/ # Global styles结构逻辑是按职责分层:app/只放路由(含(auth)这类不产生 URL 段的 route group),components/再按 ui/forms/layouts 细分子类,lib/按 api/utils/constants 归拢基础设施,types/集中共享类型。
6.2 文件命名规则
components/Button.tsx # PascalCase for components hooks/useAuth.ts # camelCase with 'use' prefix lib/formatDate.ts # camelCase for utilities types/market.types.ts # camelCase with .types suffix组件文件名与组件名同形(PascalCase)便于检索与自动导入;hook 文件以use前缀保持与函数命名一致;纯类型文件用.types.ts后缀区分“只含类型”与“含实现”的文件。
规则层rules/common/coding-style.md对“文件多大算大”给出了量化标准,可作为上述结构的补充判据:
- MANY SMALL FILES > FEW LARGE FILES:高内聚低耦合
- 源文件典型规模 200–400 行,800 行为可维护性的软上限(测试、生成与 vendored 文件因职责所需可豁免)
- 按 feature/domain 组织,而非按 type 组织
七、注释与文档:解释 WHY 而非 WHAT
7.1 何时该写注释
// PASS: GOOD: Explain WHY, not WHAT // Use exponential backoff to avoid overwhelming the API during outages const delay = Math.min(1000 * Math.pow(2, retryCount), 30000) // Deliberately using mutation here for performance with large arrays items.push(newItem) // FAIL: BAD: Stating the obvious // Increment counter by 1 count++ // Set name to user's name name = user.name两条正例展示了注释的合法用途:一是解释非显而易见的设计动机(指数退避避免故障期压垮 API,并内嵌了 30 秒上限Math.min(..., 30000)),二是为“故意违反默认规则”(第三节中的不可变性)提供豁免理由。反例则是复述代码字面行为的无效注释。
7.2 公共 API 的 JSDoc
/** * Searches markets using semantic similarity. * * @param query - Natural language search query * @param limit - Maximum number of results (default: 10) * @returns Array of markets sorted by similarity score * @throws {Error} If OpenAI API fails or Redis unavailable * * @example * ```typescript * const results = await searchMarkets('election', 5) * console.log(results[0].name) // "Trump vs Biden" * ``` */ export async function searchMarkets( query: string, limit: number = 10 ): Promise<Market[]> { // Implementation }公共函数的 JSDoc 模板包含五个要素:功能一句话、每个@param的含义与默认值、@returns的排序/形状约定、@throws的失败条件、@example可运行示例。规则层补充了一条面向纯 JS 项目的实践:在.js/.jsx文件中当 TypeScript 迁移不现实时,用 JSDoc 表达类型且必须与运行时行为保持一致(“Keep JSDoc aligned with runtime behavior”)。
八、性能最佳实践:记忆化、懒加载与查询裁剪
8.1 记忆化(Memoization)
import { useMemo, useCallback } from 'react' // PASS: GOOD: Memoize expensive computations // Copy before sorting - Array.prototype.sort mutates in place const sortedMarkets = useMemo(() => { return [...markets].sort((a, b) => b.volume - a.volume) }, [markets]) // PASS: GOOD: Memoize callbacks const handleSearch = useCallback((query: string) => { setSearchQuery(query) }, [])注意[...markets].sort(...)这一细节:Array.prototype.sort原地修改数组,直接对状态数组排序既违反不可变性原则(第三节 CRITICAL 条目)又会触发难以追踪的状态污染,因此注释先声明 “Copy before sorting” 再展开拷贝。这展示了技能内部各章节的交叉引用——性能优化代码同样受不可变性约束。
8.2 懒加载重型组件
import { lazy, Suspense } from 'react' // PASS: GOOD: Lazy load heavy components const HeavyChart = lazy(() => import('./HeavyChart')) export function Dashboard() { return ( <Suspense fallback={<Spinner />}> <HeavyChart /> </Suspense> ) }lazy+ 动态import()将重图表拆成独立 chunk,Suspense的 fallback 与第四节条件渲染的<Spinner />复用同一组件,保持加载态视觉一致。
8.3 数据库查询:只取需要的列
// PASS: GOOD: Select only needed columns const { data } = await supabase .from('markets') .select('id, name, status') .limit(10) // FAIL: BAD: Select everything const { data } = await supabase .from('markets') .select('*')列裁剪 +limit是最基础的传输层优化,与第五节分页契约(limit/offset)保持一致:API 层约定分页参数,查询层必须兑现。
九、测试标准:AAA 结构与描述性命名
9.1 AAA 模式(Arrange–Act–Assert)
test('calculates similarity correctly', () => { // Arrange const vector1 = [1, 0, 0] const vector2 = [0, 1, 0] // Act const similarity = calculateCosineSimilarity(vector1, vector2) // Assert expect(similarity).toBe(0) })测试体固定分三段:准备输入(含正交的向量 1 与向量 2)、执行单一被测调用、断言精确结果。正交向量余弦相似为 0,使断言值本身可手工验证。
9.2 测试命名:描述“场景-行为”
// PASS: GOOD: Descriptive test names test('returns empty array when no markets match query', () => { }) test('throws error when OpenAI API key is missing', () => { }) test('falls back to substring search when Redis unavailable', () => { }) // FAIL: BAD: Vague test names test('works', () => { }) test('test search', () => { })正例遵循 “<行为> when <条件>” 句式,覆盖边界(无匹配)、故障(密钥缺失)与降级(Redis 不可用回退)三类场景;测试名本身就是文档,失败日志能直接定位问题。
十、代码坏味道检测:三类反模式的量化判据
技能将坏味道检查收敛为三类,且都给出了可量化的重构手法。
10.1 长函数(超过 50 行)
// FAIL: BAD: Function > 50 lines function processMarketData() { // 100 lines of code } // PASS: GOOD: Split into smaller functions function processMarketData() { const validated = validateData() const transformed = transformData(validated) return saveData(transformed) }重构模式是“管道式分解”:原函数退化为 validate → transform → save 三步编排,每步独立命名、可单独测试。规则层将此量化为 checklist 项 “Functions are small (<50 lines)”。
10.2 深层嵌套(5 层以上)
// FAIL: BAD: 5+ levels of nesting if (user) { if (user.isAdmin) { if (market) { if (market.isActive) { if (hasPermission) { // Do something } } } } } // PASS: GOOD: Early returns if (!user) return if (!user.isAdmin) return if (!market) return if (!market.isActive) return if (!hasPermission) return // Do something守卫子句(guard clause)把 5 层嵌套压平成 5 个线性早退,主逻辑的缩进深度归零。规则层 checklist 对应项为 “No deep nesting (>4 levels)”。
10.3 魔法数字
// FAIL: BAD: Unexplained numbers if (retryCount > 3) { } setTimeout(callback, 500) // PASS: GOOD: Named constants const MAX_RETRIES = 3 const DEBOUNCE_DELAY_MS = 500 if (retryCount > MAX_RETRIES) { } setTimeout(callback, DEBOUNCE_DELAY_MS)命名常量的关键在语义命名:MAX_RETRIES表达“上限”,DEBOUNCE_DELAY_MS表达“防抖延迟”且带单位后缀MS。规则层 checklist 对应项为 “No hardcoded values (use constants or config)”,并补充了命名规范总表:变量/函数camelCase、布尔值is/has/should/can前缀、接口/类型/组件PascalCase、常量UPPER_SNAKE_CASE、hookuse前缀。
技能文末的收束句值得原样引用:“Code quality is not negotiable. Clear, maintainable code enables rapid development and confident refactoring.”——代码质量不可妥协,清晰可维护的代码换来的是快速开发与可信赖的重构。
十一、从源码结构看:规范如何被 ECC 工程化地执行
前述规范不是孤立文档。结合仓库中的实际文件,可以看出 ECC 用一个“三层执行体系”把 coding-standards 技能从文本变成约束:
第一层:技能层(完整流程)。.kiro/skills/coding-standards/SKILL.md(Kiro 版)与skills/coding-standards/SKILL.md(主仓基线版)承载本文正文的全部规范内容。主仓版额外增加的 “Scope Boundaries” 小节明确了技能的激活面(描述性命名、不可变默认值、KISS/DRY/YAGNI 执行、错误处理与坏味道审查)与非激活面(React 组合、后端分层、已有更窄技能覆盖的框架指导),防止通用技能被误用于它不该主导的场景。
第二层:规则层(按路径注入的最小约束)。rules/common/coding-style.md是跨语言通用规则(含 800 行文件软上限、200–400 行典型规模、代码质量 checklist);rules/typescript/coding-style.md通过pathsfrontmatter 声明只对**/*.ts、**/*.tsx、**/*.js、**/*.jsx生效,补充了技能中示例背后的成文规则——interface vs type 的取舍、unknown替代any的安全收窄、React Props 禁用React.FC、JS 文件 JSDoc 与运行时对齐等。从源码结构看,这种 “common 打底 + 语言包叠加” 的组织方式,让同一套原则可以按文件类型精准生效,而不需要把全部规范塞进每个技能。
第三层:工具层(可机检的兜底)。仓库根目录的 eslint.config.js 展示了技能中“配置 lint 规则”这一激活场景在 ECC 自身工程里的落地形态——flat config 下:
ecmaVersion: 2022,默认 CommonJS、.mjs文件切换为 module;- 引入
@eslint/js的 recommended 基线; no-unused-vars提升为error,但通过argsIgnorePattern: '^_'、varsIgnorePattern: '^_'、caughtErrorsIgnorePattern: '^_'允许下划线前缀的刻意未用变量/参数/捕获错误——这与技能注释规范中“有理由的例外要显式声明”的精神一致,用命名约定把例外白名单化;no-undef: 'error'堵住未定义引用,eqeqeq: 'warn'提示用严格相等。
此外,.kiro安装目录下还配套了审查类代理(如.kiro/agents/typescript-reviewer.md、.kiro/agents/react-reviewer.md),与技能同属一个生态:技能负责在开发/审查时注入规范,reviewer 代理负责按规范执行审查。
适用前提与限制
- 该技能面向TypeScript/JavaScript、React 与 Node.js技术栈(frontmatter description 明确),示例大量使用 Next.js(
NextResponse、App Router)与 Supabase 客户端;若项目栈不同,示例的载体 API 需替换,但原则与结构(命名、不可变性、响应信封、Zod 边界校验、AAA 测试)是框架无关的。 - 技能中的量化阈值(函数 <50 行、嵌套 >4 层即坏味道、文件 800 行软上限)来自 ECC 规则层的团队约定,属于建议性判据而非硬约束,可按团队规模调整。
- Kiro 侧的调用前提是项目已通过
.kiro安装器完成技能安装(/菜单可见),frontmatter 中origin: ECC标记了技能来源谱系,便于在多技能环境中溯源。
小结
coding-standards技能的完整脉络可以概括为:四大原则(Readability/KISS/DRY/YAGNI)定方向 → TS/JS 规范(描述性命名、CRITICAL 级不可变性、全面错误处理、Promise.all并行、拒绝any)定日常写法 → React 与 API 标准(显式 Props、函数式状态更新、统一响应信封、Zod 边界校验)定系统形态 → 文件组织与注释规范(按职责分层、WHY 注释、五要素 JSDoc)定协作界面 → 性能与测试实践(拷贝后排序、懒加载、列裁剪、AAA 与场景化测试名)定质量下限 → 三类坏味道的量化判据(<50 行、>4 层、命名常量)定审查清单。再叠加 ECC 仓库中“技能—规则—ESLint”三层执行体系,这份文档从“写给 Agent 看的规范”变成了“人、Agent 与工具共同遵守的工程契约”。将其安装进自己的 TypeScript/React 项目后,最先值得落地的三件事是:把不可变性设为代码审查的一票否决项、在系统边界引入 Schema 校验、并用 rules/common/coding-style.md 末尾的 checklist 作为每次提交前的自检清单。
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考