OpenHuman App 前端死代码治理实战:把 Knip 当作静态分析回归测试的 11 步清理方案 OpenHuman App 前端死代码治理实战把 Knip 当作静态分析回归测试的 11 步清理方案【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman本文基于仓库内实现计划文档 docs/plans/2026-07-24-knip-cleanup.md 展开并结合app/目录当前真实源码与配置逐条佐证。它回答的是一个非常具体的工程问题在一个同时被 Vite、Vitest、WebdriverIO、Playwright、Tauri、package scripts 与 shell 脚本驱动的 React/TypeScript 前端仓库里如何让 Knip 的死代码报告变得可信并据此安全地删除不可达文件、未用依赖与多余导出同时绝不改变运行时行为。读完你将掌握一套「红red基线 → 独立核证 → 最小改动 → 绿green门禁 → 原子提交」的可复现清理流程以及 Knip 配置建模入口点、隔离有意保留的公共/测试缝隙的完整方法。OpenHuman 是一款本地优先local-first的开源个人 AI 桌面应用其桌面前端位于app/pnpm workspace 中名为openhuman-app的包。随着功能不断叠加app/src/与app/test/中出现了一大批未被任何入口可达的 TypeScript/TSX 文件、未被消费的依赖以及大量「只在本模块使用却仍然导出」的类型与值——它们既不是缺陷也不会立刻引发报错却会让任何后续静态分析、类型检查与代码搜索被噪声淹没。下面这份文档的价值在于它没有把 Knip 当作自动删除清单而是把它当作一台静态分析回归测试机。所有删除动作都必须先有入口图、再有人工核证最后才有删除本身。一、背景与总目标先让报告可信再谈清理1.1 这份计划解决什么问题计划的开篇给出了清晰的定义Make Knips OpenHuman app analysis trustworthy, then remove unreachable TypeScript/React files, unused package dependencies, and unnecessary exported surface without changing runtime behavior.翻译成工程语言就是三个阶段让分析可信把每一种真实入口Vite、Vitest、WebdriverIO、Playwright、Tauri、package scripts、shell 脚本启动的入口都显式建模进 Knip纠正误报的“未使用文件/未声明依赖”按子系统切片清理删除经独立验证确属不可达的 TS/TSX 文件、未使用的包依赖、多余的导出表面不改变运行时行为路由、命令、事件、RPC 方法、分析埋点 ID、载荷字段、可见文案一律不动。1.2 清理范围Scope的严格边界计划明确划定了允许触碰的文件这点对任何大型仓库都极具参考价值允许修改app/knip.json、app/package.json、相关的 pnpm lockfile根级pnpm-lock.yaml与app/pnpm-lock.yaml以及 Knip 确认死亡的app/src/、app/test/下的 TS/TSX 文件明确禁止生成产物generated assets、app/src-tauri/、第三方 vendored 源码、全部 Rust、公开文档以及任何与本次清理无关的格式调整/重构。当前仓库根目录还提供了直接代理到该包的脚本根 package.json 中knip与knip:production均执行pnpm --filter openhuman-app knip/knip:production而 app/package.json 中对应定义为knip --config knip.json与knip --config knip.json --production。1.3 仓库快照对计划的佐证对照当前仓库快照可以确认本计划描述的方案并非纸上谈兵app/knip.json 已存在包含entry/project/tags/ignoreDependencies/ignoreBinaries等完整配置结构app/package.json 的 devDependencies 中已经以^9.24.0显式声明了wdio/globals、wdio/types、webdriverio这正是计划 Task 1 Step 4「声明直接 WDIO 导入」的落地结果计划 Task 2 候选清单中的绝大多数文件在当前快照里已不存在例如app/src/components/LottieAnimation.tsx、app/src/pages/Routines.tsx、app/src/hooks/useScreenIntelligenceItems.ts、app/src/pages/onboarding/pages/ApiKeysPage.tsx、app/test/e2e/helpers/rpc-preflight.ts等均已被删除计划 Task 3 点名的lottie-react与react-ga4已不在 app/package.json 的任何依赖段中grep 依赖锁文件也无匹配仍有个别候选文件存在如app/src/components/intelligence/SyncConfirmDialog.tsx与app/src/features/conversations/index.ts。这并不矛盾计划 Task 2 自己规定「凡入口校正后变得可达的文件必须从删除清单剔除」features/conversations/index.ts至今仍以 entry 身份列于 app/knip.json说明它因入口建模而得以保留。任何在另一时间点再次评估的人都必须重新走一遍完整核证而不是照单机械删除。二、设计原则Knip 是回归测试不是自动删除器计划的核心方法论值得单独成节强调Treat Knip as a static-analysis regression test, not as an automatic deletion list.在此基础上派生出几条硬规则先建入口图再处理结果先对每一个 Vite / Vitest / WDIO / Playwright / Tauri / package-script / shell 启动的入口点建模然后按子系统大小的切片处理 findings四种改动幅度严格区分声明没有任何运行时/构建/测试/文档/生成清单/工具/动态加载职责时 → 删除整个文件声明在其自身模块内仍被使用 →只去掉export把它「内部化internalize」遇到同名命名导出与默认导出重复 → 只保留一边并把 import 收敛到保留形式属于有意保留的公共/测试缝隙 → 用最窄的knip.json例外显式豁免并注明原因每个「红」finding 都要先人工复核静态 import、barrel 再导出、字符串引用、package scripts、测试配置、Tauri 配置、shell/CI 调用链都要查一遍删除死代码后若留下“只为测试死代码而存在”的孤儿测试须独立核实后在同一原子提交中一并删除——测试的存在不能证明某个生产入口是活的。三、强制执行的九条工作纪律计划用整整一节列出执行纪律核心诉求是「多代理并行仓库里不互相踩踏、改动可审计」。逐条梳理如下开工先跑git status --short --branch若其他代理改动过本任务所需文件先协调而不是回滚或覆盖编辑前先运行指定的redKnip 查询把相关输出保存在终端/日志不写入仓库修改前对每个候选对象用rg独立核证含禁止通配的明确 globrg -n symbol-or-file-stem app package.json scripts .github \ --glob !app/pnpm-lock.yaml --glob !pnpm-lock.yaml \ --glob !app/src-tauri/vendor/** --glob !node_modules/** \ --glob !target/**同时每当候选可能「按名字/约定/脚本/Tauri」被加载时检查 app/package.json、app/index.html、app/vite.config.ts、app/test/vitest.config.ts、app/test/wdio.conf.ts、app/playwright.config.ts、app/scripts/、app/src-tauri/tauri.conf.json以及.github/workflows/做最小改动见上节的四种幅度运行指定的green检查本步骤处理过的文件中目标 Knip 类别必须清零且不得引入新的files/dependencies/unlistedfinding只对显式触碰的文件跑 Prettierpnpm --filter openhuman-app exec prettier --check explicit paths复查git diff --check与git diff -- explicit paths验证通过后立即提交逐一手写所有被触碰路径绝不使用 glob、目录、git add或命令替换atomic-commit scoped message -- path/to/file1 path/to/file2前一个任务未提交前不开始下一个任务。这九条纪律解决了大型前端清理最常见的两个事故源误删漏掉了某种动态加载与失控提交一口气改了几百个文件无法 review 与回滚。四、基线快照清理前的体检报告计划在 Node 24 已批准设计的条件下记录了一份基线截至文档撰写时间入口点校正后计数可能下降始终以 post-config 报告为删除依据基线类别数量 / 对象未使用文件unused files34 个未使用依赖unused dependencieslottie-react、react-ga4直接导入但未声明的依赖unlistedwebdriverio、wdio/globals未使用的值导出unused value exports131 个未使用的导出类型unused exported types276 个未使用的枚举成员组1 组重复导出duplicate exports41 处把数值换成工程判断「未使用的导出类型」数量276是「未使用文件」34的八倍——意味着绝大多数清理工作量不是删文件而是把export改回模块私有。这也是为什么计划里大量任务是「internalize内部化」而不是「delete」。五、Task 1建模全部真实入口点让报告可信的第一步本任务只改两个文件app/knip.json以及仅在确需直接依赖证据时app/package.json与两个 lockfile。5.1 记录 red 基线在 Node 24 下运行source $HOME/.nvm/nvm.sh nvm use 24 pnpm --filter openhuman-app exec knip --config knip.json --reporter compact预期结果退出码非零且test/wdio.conf.ts被误报为 unusedwebdriverio/wdio/globals报 unlisted其余清理候选照常列出。5.2 用 rg 证明每条间接入口Knip 只能看见静态可达的 import。像 Vite/Vitest/WDIO/Playwright 这类「被配置文件按 glob 加载」以及「被 shell/package script 显式启动」的入口需要人工取证rg -n src/main\.tsx|vite\.config|vitest\.config|wdio\.conf|playwright\.config|build-parallel|e2e-run-session \ app/index.html app/package.json app/scripts scripts .github rg -n test/e2e/specs|test/playwright/specs|src/test/setup \ app/test app/playwright.config.ts app/package.json app/scripts .github rg -n webdriverio|wdio/globals|wdio/types app/test app/package.json计划的取证要求与当前仓库源码完全吻合以下是需要「永久保留为证据」的调用链app/index.html 第 15 行通过script typemodule src/src/main.tsx加载前端入口package build scripts 执行scripts/build-parallel.mjs而 app/scripts/build-parallel.mjs 内部把tsc作为纯类型门禁与vite build并行跑并透传--mode development等参数单元测试脚本pnpm test加载 app/test/vitest.config.ts其setupFiles: [src/test/setup.ts]引入 app/src/test/setup.tsinclude覆盖src/**/*.test.{ts,tsx}与test/*.test.{ts,tsx}此外该配置还声明了别名与 node polyfillapp/scripts/e2e-run-session.sh第 333/335 行执行pnpm exec wdio run test/wdio.conf.ts --maxInstances 1 ...app/test/wdio.conf.ts 以 globtest/e2e/specs/**/*.spec.ts加载全部 WDIO 规格文件同一进程、同一tauri-driver会话、maxInstances: 1且规格之间刻意顺序依赖app/playwright.config.ts 的testDir: ./test/playwright/specs加载全部 Playwright 规格被源码 import 的 WebdriverIO 类型/全局量必须是直接 devDependencies即使别的 WDIO 包当前以传递方式安装了它们Tauri / Vite / package-script 二进制的存在即使只出现在脚本或 shell 中也是真实依赖。5.3 收窄式修正 Knip 配置在完成取证后把验证过的配置/规格/工具文件显式写进entry。计划给出的最小图谱是{ entry: [ src/main.tsx, vite.config.ts, test/vitest.config.ts, test/wdio.conf.ts, playwright.config.ts, test/e2e/specs/**/*.spec.ts, test/playwright/specs/**/*.spec.ts ] }配套要求同样关键保留project对 app 与 test TypeScript 的覆盖只有当 Knip 无法发现已验证的调用时才追加 package-script/tooling 入口禁止为了消音而加宽泛的scripts/**、test/**或src/**ignoreDependencies/ignoreBinaries中的条目只有在入口图修正后仍无法建模真实使用时才保留如包管理器、Tauri、shell 脚本的调用方式且必须在豁免旁注释精确调用方式。对照当前 app/knip.json它仍保留test/wdio.conf.ts、test/e2e/specs/**/*.spec.ts、test/playwright/specs/**/*.spec.ts等条目ignoreDependencies中保留wdio/*、tailwind、buffer/process/util等包后者由 vitest 的 node-polyfills 别名与构建期 shims 驱动。这类豁免正是 Task 1 / Task 10 反复强调的「有精确调用依据才豁免」。5.4 声明直接 WDIO 依赖若修正图谱后上述 import 仍报 unlisted则把wdio/globals与webdriverio加入app/devDependencies与其它 WDIO 包相同的9.24.x系若 app/test/wdio.conf.ts 经 Knip 或pnpm why wdio/types确认传递依赖wdio/types则一并声明。随后只重生成受影响的 lockfile 区段不升级无关包。当前仓库 app/package.json 中已包含这三者证明该步骤已落地。5.5 绿门禁与提交pnpm --filter openhuman-app exec knip --config knip.json --reporter compact pnpm --filter openhuman-app compile pnpm --filter openhuman-app exec tsc -p test/tsconfig.e2e.json --noEmit pnpm --filter openhuman-app exec prettier --check knip.json package.json git diff --check预期test/wdio.conf.ts与所有验证过的框架/工具入口不再报 unusedwebdriverio/wdio/globals不再报 unlisted且没有宽泛 ignore 掩盖源码。提交atomic-commit chore(app): make knip entry analysis accurate -- app/knip.json app/package.json pnpm-lock.yaml app/pnpm-lock.yaml实际未变动的路径应当从命令中省略但每个实际改动的路径都必须显式写出。六、Task 2删除经独立验证的不可达文件本任务是「删文件」主力候选清单共 33 个文件全部位于app/src/与app/test/例如组件层components/ConnectionBadge.tsx、components/LottieAnimation.tsx、components/accounts/RespondQueuePanel.tsx、components/chat/CycleUsagePill.tsx、components/chat/TokenUsagePill.tsx、components/intelligence/SyncBudgetDialog.tsx、components/skills/SkillResourceTree.tsx、components/routines/RoutineCard.tsx、components/settings/components/PageBackButton.tsx、components/settings/panels/billing/BillingHistoryTab.tsx等页面与特性pages/Routines.tsx、pages/onboarding/pages/ApiKeysPage.tsx、pages/onboarding/pages/ChatProviderPage.tsx、pages/onboarding/steps/ReferralApplyStep.tsx、features/conversations/index.tsHooks / libhooks/useIntelligenceApiFallback.ts、hooks/useIntelligenceStats.ts、hooks/useScreenIntelligenceItems.ts、lib/ai/skillsAgentContext.ts测试辅助test/e2e/helpers/rpc-preflight.ts。并特别注明app/test/wdio.conf.ts明确不是删除候选。6.1 red 检查文件集pnpm --filter openhuman-app exec knip --config knip.json --include files --reporter compact预期只有「扛过 Task 1」的文件还留在候选集里凡因入口修正而可达的文件立即从本任务剔除。6.2 逐个独立核证含大量陷阱提示计划针对高风险文件给出了一组极具实操价值的提示Routines.tsx当前路由会把旧的/routines重定向走不要因为旧页面死了就顺手删掉重定向或 i18n 文案onboarding 页面被注释掉的 JSX 不是活入口不要删除共享 onboarding 类型或当前 wizard 路由GoogleIcon.tsx注意components/oauth/providerConfigs.tsx里另有一个本地GoogleIcon实现活的本地实现必须保留useScreenIntelligenceItems.ts先查hooks/__tests__/useScreenIntelligenceItems.test.ts只有确认它是重复测试死行为的孤儿测试时才在同一提交删除rpc-preflight.ts注释声称「可以被调用」不是执行证据要核实 WDIO 配置或 specs 都没有 import 它settings / routines / intelligence / billing 下的文件除静态 import 外还要查路由注册表与 lazy import。6.3 只删确认死亡的、绿门禁后原子提交删除后仅当 barrel 导出或目录里再无其它被跟踪资产时才清理空导出/空目录不得因为名字相似就删本地化字符串、样式或测试。随后执行pnpm --filter openhuman-app exec knip --config knip.json --include files --reporter compact pnpm --filter openhuman-app compile pnpm --filter openhuman-app test -- --run pnpm --filter openhuman-app lint git diff --check预期无任何已验证的文件候选残留单测、类型、lint 全绿。提交时显式列出每个删除文件及孤儿测试/barrel 更新atomic-commit refactor(app): remove unreachable frontend files -- explicit deleted and modified paths七、Task 3移除未使用的包依赖Task 2 删除LottieAnimation.tsx后lottie-react就失去了唯一的真实 importreact-ga4同样只剩过时注释引用。red 检查pnpm --filter openhuman-app exec knip --config knip.json --include dependencies,unlisted --reporter compact rg -n from \[\]|import\(\[\]\) \ app/src app/test app/vite.config.ts app/scripts随后从app/package.json移除两个包同时更新根 workspace lock 与被跟踪的app/pnpm-lock.yaml且不得顺带升级无关包——需要检查两个 lockfile 的 diff回滚任何与这两项移除及 Task 1 直接 WDIO 声明无关的 resolver 波动。绿门禁使用--include dependencies,unlisted重跑并跑 compile/test/prettier/diff 检查。当前仓库的 app/package.json 已不见这两个包说明移除动作已在分支上完成。atomic-commit chore(app): remove unused frontend dependencies -- app/package.json pnpm-lock.yaml app/pnpm-lock.yaml八、Task 4归一化重复导出与 barrel初始重复导出报告共 41 处集中在components/chat/、components/flows/、components/intelligence/、components/mcp-setup/、components/meetings/、components/skills/、components/userErrors/、features/conversations/、features/human/、features/meet/、features/share/、hooks/、lib/attachments.ts、lib/mcp/rateLimiter.ts、services/api/flowsApi.ts。red 检查使用--include duplicates。处理原则每个符号只保留一个 canonical 导出形态优先保留活消费者已经在用的 import 形态删掉多余的另一半named 或 default只在必要时更新 import 收敛到 canonical 形态不重命名组件、不重构实现。计划还给了三个需要辨析的细节点attachments.ts先核实ATTACHMENT_MAX_IMAGE_SIZE_BYTES与ATTACHMENT_MAX_SIZE_BYTES是否为别名再决定删哪一个导出rateLimiter.ts区分「真正的重复再导出」与「两个不同实现」flowsApi.ts保留多数活调用方使用的 import 形态。若路径清单过大最多拆成三个子系统提交chat/flows/intelligence → meetings/skills/human/share/hooks → lib/services/barrels每个提交都必须独立通过--include duplicates的 Knip 重跑、compile、test --run、lint、git diff --check。任务完成的标志零个无法解释的重复导出 finding。九、Task 5–8把「本模块自用却外泄」的导出内部化这四步是「内部化internalize」的主战场处理的是基线中占比最大的「未使用导出值与类型」。Task 5Agent World 与 mascot范围agentworld/**、features/human/Mascot/**、features/meet/MascotFrameProducer.tsx、features/meet/useMeetingMascots.ts。特别提醒agentworld/iso/index.ts与features/human/Mascot/index.ts这类「看起来公共」的 barrel其内部项在这个私有 app workspace 里未被使用并不等于它是公开包 API——先删死掉的 barrel 再导出底层声明若被直接 import 或在本模块使用则保留组件 props / manifest 类型 / renderer 类型 / hook 结果类型仅本地使用时去掉export而非删除类型。同时严禁触碰运行时渲染、sprite/room 注册、Rive 资源查找、manifest 发现或 Tauri 资源路径Task 6conversations / flows / orchestration / hooks范围含components/flows/**、features/conversations/**、hooks/useFlow*.ts、hooks/useRunsPendingApprovalSet.ts、lib/flows/**、lib/orchestration/**、pages/FlowCanvasPage.tsx、services/api/flowsApi.ts、services/api/workflowRunsApi.ts。改前先在测试中搜索VALIDATION_DEBOUNCE_MS、模型提示、timeline 种类、flow API 辅助函数与 copilot seed 类型等常量保留运行时 hook 注册、事件名、API 载荷形态、flow node-kind 注册表Task 7settings / layout / UI / meetings / features典型安全改动包括export interface FooProps→interface FooProps仅本文件组件使用、export const→const本地代码与测试均未 import、删除全部消费者都直接 import 的 barrel 再导出、无本地使用时才删值/类型。必须保留 settings 路由注册表数据、Tauri command 名、analytics ID、已文档化的扩展点与有意的测试缝隙Task 8services / stores / lib / types / utils / hooks / polyfills对 RPC/API 模块区分「TS 可见性」与「API 形状」——去掉export不能改变运行时对象、载荷、枚举值或 command 名凡是可能作为 IPC 契约的字符串都要搜 Rust/Tauri 边界与文档。高风险管理对象包括services/coreRpcClient.ts、services/rpcMethods.ts、全部services/api/*、Redux slice action/selector对照store/index.ts、中间件、持久化、动态 dispatch、lib/agentworld/invokeApiClient.ts、lib/mcp/*工具分类与限流符号而polyfills.ts是被 app/src/main.tsx 以副作用方式 import 的注释明确要求 polyfills 必须最先导入只能删未用导出绝不删文件或其副作用。Task 8 强制拆成三个原子切片services/API 客户端 → stores/selectors → libraries/types/utils/hooks禁止三合一提交。每一步共用一套验证compile、test --run、lint、knip --include exports,types、git diff --check。Task 5 的绿门禁写法值得一提——它展示了一个易被误解的 shell 语义pnpm --filter openhuman-app exec knip --config knip.json --include exports,types --reporter compact \ | rg src/(agentworld|features/human/Mascot|features/meet/) exit 1 || true这条命令只有在「子系统内不存在可处理的 finding」时才为绿Knip 进程本身的失败绝不能被|| true掩盖。计划中所有rg管道都必须如此小心解读。十、Task 9清理测试辅助导出与未用枚举成员范围集中在test/e2e/helpers/**、test/e2e/mock-server.ts、test/playwright/helpers/**、src/lib/mcp/errorHandler.ts。red 检查命令pnpm --filter openhuman-app exec knip --config knip.json \ --include exports,types,enumMembers --reporter compact核证要点WDIO/Playwrightspecs 是入口helper 不是通过 WDIO 生命周期钩子或 fixture 注册调用的 helper 即使没有 spec 直接 import 也要保留。对ErrorCategory除了枚举成员名还要搜字符串值与计算属性访问CONTACT、GROUP、MEDIA、PROFILE、AUTH、ADMIN、SEARCH、DRAFT只有在确认没有动态使用、且删除不改变序列化行为时才可移除。绿门禁额外包含pnpm --filter openhuman-app exec tsc -p test/tsconfig.e2e.json --noEmit十一、Task 10 与 Task 11收尾豁免与最终独立验证Task 10 解决「确实有意保留」的残余 finding。先跑完整报告与 production 报告pnpm --filter openhuman-app exec knip --config knip.json --reporter compact pnpm --filter openhuman-app exec knip --config knip.json --production --reporter compact对每一个残余做对抗式验证只有存在约定式加载、包/Tauri/工具调用、生成输入、已文档化的公共契约或有意的测试缝隙等 Knip 无法建模的证据时才允许残留。首选方案永远是建模一个更精确的入口或依赖而非加 ignore。豁免必须以精确到文件/包/符号的方式声明并附一行注明加载器或契约的理由禁止目录级 ignore、src/**、test/**或全局导出抑制。若无需豁免则跳过该提交。Task 11 是最终独立验证无计划内编辑确认分支与干净工作区git status --short --branch、git log --oneline --decorate -15期望在chore/knip-cleanup分支上每个切片都有独立原子提交在全新 Node 24 shell 中重跑完整质量门禁source $HOME/.nvm/nvm.sh nvm use 24 pnpm knip pnpm knip:production pnpm typecheck pnpm test pnpm lint pnpm format:check pnpm build全部命令须零退出若format:check发现既有且超范围的失败须先在设计提交处证明其存在再只修复本次清理触碰文件的格式并以显式路径新建原子格式化提交验证无范围泄漏git diff --name-only design-commit..HEAD等命令应显示实现改动仅限app/无 Rust、vendor、生成资产、其它子模块或 umbrella gitlink 变更行为保持性复查完整 diff 中不得有路由、command、事件、RPC 方法、analytics ID、载荷字段或可见文案变化所有入口仍被 Knip 跟踪或有精确文档化豁免删除文件无任何 import/字符串引用/生成清单角色/工具角色/文档契约依赖变化无无关升级每个保留导出都是活的或有意的。收尾动作是「不 push、不开 PR」仅向请求方汇报提交列表、删除的文件与依赖、最终 Knip 结果、每条验证命令及其退出状态、以及任何窄豁免。十二、从计划中提炼的可复用工程模板这份计划的价值远超 OpenHuman 单个仓库抽出后可直接迁移到任何「多入口、多工具链、多运行时」的前端项目入口取证优先index.html→main.tsx、构建并行脚本、vitestsetupFiles/include、e2e 运行脚本对 wdio 的调用、wdio/playwright 配置对 specs glob 的加载都是一条条可以用rg证明的调用链证明成功后才写进knip.json的entry红/绿两阶段门禁每个子系统改动前用 Knip--include files或exports,types,enumMembers,duplicates等类别建立 red 基线改动后用同样命令 compiletestlintgit diff --check建立绿门禁最小可见性改动优先于删除内部化去掉export是默认动作删除是最终手段删除只发生在没有任何角色之后原子提交 显式路径每个 slice 独立提交、独立验证、路径全量手写既保证可回滚也保证可审计豁免必须窄而带注释任何ignoreDependencies/ignoreBinaries例外都要有精确的调用证据包管理器、Tauri、shell 脚本并对 Knip 无法建模的加载方式逐条注释行为保持是硬约束路由、IPC command 名、RPC 方法、枚举的字符串/序列化语义、polyfill 副作用文件都是「看起来死其实活着」的高危区必须单独列出防范。结语本计划展示了一次「高质量前端清理」应有的完整样子以 34 个不可达文件、2 个未用依赖与 448 项131 值 276 类型 41 重复 1 枚举组导出面问题为起点通过把入口图修准Task 1、删除验证过的死文件Task 2、剥离未用依赖Task 3、归一化重复导出Task 4、按 Agent World/mascot、conversations/flows、settings/UI、services/store 四轮内部化导出Task 5–8、清理测试辅助Task 9、窄豁免残余Task 10到最终独立复验Task 11最终让 Knip 报告回归「零可操作 finding」的稳态并使其成为后续每次合并都可持续运行的静态分析回归测试。对希望在自己项目中引入同类清理流程的团队本文第一节到第三节的纪律、第四节到第十一节的命令模板以及仓库内对应的 app/knip.json、app/package.json 与各个测试配置就是一份可以直接对照执行的参照实现。该计划对应的批准设计文档可进一步参考 docs/specs/2026-07-24-knip-cleanup-design.md。【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考