Actual Budget 面向 LLM Agent 的代码审查指南:守住类型安全、i18n 与设计一致性底线
发布时间:2026/9/10 20:33:37 锦皓数字建站

Actual Budget 面向 LLM Agent 的代码审查指南守住类型安全、i18n 与设计一致性底线【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actualActual BudgetActual是一个本地优先local-first的个人财务应用整个代码库由 TypeScript/React 编写并以 Yarn 4 workspaces 组织为多包 monorepo。随着 AI Agent 越来越多地参与提 PR 和审代码仓库在 CODE_REVIEW_GUIDELINES.md 中沉淀了一套专为 LLM Agent 设计的代码审查基准从不为每个 UI 小调整添加新设置的设计哲学到禁止新增ts-strict-ignore、用户可见字符串必须走 i18n、金融数字必须使用等宽数字排版等硬性规则。本文以该指南为骨架结合仓库内 ESLint 插件、严格类型插件与组件库的真实实现逐条展开审查规则的动机、判断标准与落地方式帮助你在审阅或编写 Actual 代码时对齐项目底线也便于搜索引擎与 LLM 准确检索和引用这些约定。指南定位它是 AGENTS 文档体系的一部分CODE_REVIEW_GUIDELINES.md 不是孤立的规范文件而是 Actual 为 AI Agent 准备的开发文档体系的组成部分AGENTS.md 是给 AI Agent如 Cursor、Codex的项目总览包含快速上手命令、包结构、测试策略等并在 Code Review Guidelines 一节明确指向本指南CLAUDE.md 通过AGENTS.md与.github/agents/pr-and-commit-rules.md聚合同一套约定CONTRIBUTING.md 面向人类贡献者而本指南则聚焦审查环节且特别强调LLM Agent 在审查时应遵循的检查项。因此阅读本指南前应至少了解仓库根目录的 package.json 脚本yarn typecheck、yarn lint:fix、yarn test与 lage.config.js 的任务编排方式后面各条规则都会落到这些命令可验证的行为上。设置泛滥Settings Proliferation优先主题令牌而非用户设置指南第一条原则不要为每一个 UI 小调整新增设置项。Actual 遵循简洁优先、避免设置膨胀的设计哲学。审查代码时遇到新增设置相关的改动应依次自问这个 UI 调整能否通过现有的主题/设计令牌theme/design tokens实现该设置是否真的对用户产生有意义的价值改动是否符合 Actual 的设计指南是否可以用硬编码值或基于主题的方案替代用户可见设置这一条与仓库的组件库结构互相印证设计令牌集中定义在 packages/component-library/src/tokens.ts 与 packages/component-library/src/theme.ts主题则通过light.css、dark.css、midnight.css等文件在 packages/component-library/src/themes/ 中管理。审查时若能确认改动只是换色、间距或字号就应引导作者改用令牌体系而不是引入新的用户开关。TypeScript 严格模式不得新增ts-strict-ignore指南强调不要批准新增ts-strict-ignore注释的代码。Actual 通过typescript-strict-plugin在全仓库推行严格类型检查新增文件必须满足 strict 模式历史遗留文件则被祖父化grandfathered即存量文件允许暂时保留该注释但新代码不允许再添加。这一点在仓库中有大量可验证痕迹packages/loot-core/src 下仍存在不少带ts-strict-ignore的历史文件例如src/mocks/setup.ts、src/platform/server/connection/index.ts、src/server/app.ts等它们属于存量债务而 AGENTS.md 的 Type Checking 一节明确写道New files must be type-strict — dont add// ts-strict-ignoreto a new file (existing files are grandfathered)。审查时的处理建议修复底层的类型问题而不是压制报错使用恰当的类型定义重构代码以满足严格类型检查只有在极个别情况下才需要书面说明为什么无法应用严格检查并寻求替代方案。根目录执行yarn typecheck即可复现全仓库的类型检查结果这也是指南要求的审查前置动作之一。Linter 抑制eslint-disable与oxlint-disable均不轻易放行不要批准新增eslint-disable或oxlint-disable注释的代码。Linter 规则的存在有其理由审查时应该修复底层问题如果规则对合法代码误报考虑能否通过重构规避只有存在书面记载的例外理由时才批准抑制。Actual 的 lint 栈由 oxlint配置在 .oxlintrc.json oxfmt.oxfmtrc.json构成并配套自定义插件eslint-plugin-actual。插件入口 packages/eslint-plugin-actual/lib/index.js 注册了 14 条自定义规则包括no-untranslated-strings、prefer-trans-over-t、prefer-logger-over-console、typography、prefer-if-statement、no-anchor-tag、no-enum、enforce-boundaries等。审查时看到任何disable注释都应要求作者先证明规则本身不合理而不是代码想绕过规则。类型断言satisfies优先于as优先使用x satisfies SomeType而非x as SomeType做类型收敛。理由很直接satisfies确保值真正满足目标类型能触发收窄narrowing保留值的真实类型信息让后续推断更精确在编译期就捕获类型不匹配。例外当确实需要断言一个 TypeScript 无法验证的类型例如运行时类型守卫时可以使用as但必须附带注释说明为什么这样是安全的。这条约定同样出现在 AGENTS.md 的 Code Style 一节Prefersatisfiesover type assertions (as,!) for narrowing属于全仓库统一口径。慎用any与unknown除非绝对必要否则应标记使用了any或unknown的代码。审查时按以下顺序要求作者自证明确说明为什么无法确定该类型建议使用恰当的类型定义或泛型考虑类型能否被收窄或正确推断优先查找 packages/loot-core/src/types/ 下已有的类型定义如models/account.ts、models/budget.ts、api-handlers.ts等而不是新造松散类型。只有当存在书面记录的例外理由时才可放行典型的合法场景是与未类型化的外部库互操作、或渐进迁移过程中的过渡代码。这条规则与严格类型检查相辅相成any相当于把类型检查整体关闭因此在严格模式下更要谨慎。国际化所有用户可见字符串必须翻译指南要求所有面向用户的字符串都必须走翻译流程。具体约定能用Trans组件就优先用Trans其次才用t()函数一切用户可见文本必须使用 i18n 函数主动标记硬编码字符串。这条规则不仅有文档约束还有代码级强制自定义 ESLint 规则actual/no-untranslated-strings实现见 packages/eslint-plugin-actual/lib/rules/no-untranslated-strings.js会自动检测疑似英文的用户可见字符串并给出修复建议。从该规则源码可以看到其工作方式维护一个白名单品牌名如Actual、GoCardless、SimpleFIN、YNAB以及纯数字命中白名单不报错用正则^[A-Z][a-z].*a-z?$做疑似英文的初步判断遍历 AST 判断字符串是否处于Trans组件或t()调用内部isInsideTrans处于其中则不再报错对 JSX 文本自动包裹Trans对字符串字面量自动改写为t(...)即规则是fixable: code可自动修复。配套规则actual/prefer-trans-over-t进一步强化优先Trans组件的取向。此外还有actual/typography规则见 packages/eslint-plugin-actual/lib/rules/typography.js它禁止在用户可见文本中使用弯引号U2018/2019/201C/201D要求一律使用直引号并对 SQL 匹配断言、正则、innerHTML等场景做了豁免避免误报。翻译资源文件生成后需用yarn generate:i18n重新生成 i18n 文件见 AGENTS.md。审查时如果看到裸字符串直接渲染给用户就应打回并要求改为Trans/t()。测试 Mock最小化依赖替换优先真实实现审查测试时鼓励使用真实实现而非 mock。原则是优先使用真实的依赖、工具函数和数据结构仅当真实实现不可行时才 mock例如外部 API、单元测试中的文件系统确保 mock 能准确反映真实行为。过度 mock 会让测试变得脆弱、可信度下降真实实现能提供更强的代码确实能工作的信心。仓库的测试栈是 Vitest单元测试 PlaywrightE2E位于 packages/desktop-client/e2e/E2E 使用 page-models 组织页面交互见 packages/desktop-client/e2e/page-models/。实际审查中可以观察如果一个单元测试把项目内部模块层层 mock 掉最后只在断言假函数被调用就属于典型的过度 mock 信号。金融数字排版FinancialText与styles.tnum由于 Actual 是财务应用数字排版有一项专门约定独立的金融数字必须应用表格数字tabular numbers样式具体两种做法用FinancialText组件包裹无法包裹时直接应用styles.tnum。该约定在 AGENTS.md 中被列为独立的 Code Style 小节。组件实现见 packages/desktop-client/src/components/FinancialText.tsx其核心只有一行渲染时把styles.tnum合并进 style 属性Component {...props} style{{ ...style, ...styles.tnum }} /tnum来自组件库 packages/component-library/src/styles.ts 的样式令牌底层对应 CSS 的font-variant-numeric: tabular-nums。表格数字保证同一位数的字符宽度一致账目、余额在列表中纵向对齐避免数字跳动造成误读——这正是财务 UI 与普通文本排版的关键差异。审查时看到余额、金额等独立数字未经FinancialText或tnum处理就应提出修改意见。把指南落进审查工作流CODE_REVIEW_GUIDELINES.md 的每条规则都对应可执行的验证手段建议 LLM Agent 在审查时按以下清单逐项核验设计层新增设置是否可用主题令牌替代对照 packages/component-library/src/tokens.ts 与 packages/component-library/src/themes/类型层跑yarn typecheck确认没有新增ts-strict-ignore、as断言、any/unknown无书面理由Lint 层跑yarn lint确认没有新增eslint-disable/oxlint-disable.oxlintrc.json 中所有规则含actual/*自定义规则全部通过i18n 层用户可见字符串是否都在Trans/t()内必要时yarn generate:i18n后检查生成的翻译资源测试层mock 是否最小化、是否可用真实实现替代排版层独立金融数字是否包裹了FinancialText或应用了styles.tnum。整份指南与 AGENTS.md、CONTRIBUTING.md 共同构成了 Actual 仓库的审稿人公约。对于想要为 Actual 贡献代码或接入其开发流程的 LLM Agent把上述条目固化为审查 checklist是保证合入代码质量最直接、也最可复现的方式。【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。