Files
DemonGatanjieu-Anomalous_Mo…/AGENTS.md
T
2026-11-08 01:36:44 +08:00

19 KiB
Raw Blame History

开发与维护规范

适用于本插件的所有修改,包括 Gemini、Codex 和人工维护。目标是让 UX 持续改善,同时让代码职责、状态来源和验证方式保持清楚。 用户明确的当前要求优先;确需偏离本规范时,采用最小例外,在交付说明中写明原因、影响和验证。常规实现选择自行处理,不因本规范增加无必要的确认步骤。

0. 每次提交的硬性要求

以下几条每次提交都要做到,没有“这次改动小”的例外;其余各节是怎么做好的指引。

  1. 结构和文档同步。 按下表更新文档,与代码放在同一次提交里。新增、删除、改名、拆分源码文件一律算改了模块职责:职责清单同时是文件目录,每个源码文件都要有一行。
  2. 跑结构检查。 node tools/check_structure.mjs,失败不提交。它检查每个源码文件都登记在架构文档里、每个前端模块都能从入口引用到、每个前端文件都能按浏览器的方式解析(node --check 对 .js 文件会漏掉浏览器报错的写法)、CSS 里没有按 style 属性匹配的 :has()(会让拖动画布掉帧,见 lessons.md),并执行规模阈值(第 2 节):新文件不能一开始就超线,已超线的文件比上次提交只能变短或持平。
  3. 不留旧实现。 被取代的模块、样式、文案 key、文档说明同一次提交删掉(第 6 节)。
  4. 按风险验证(第 7 节),只提交本任务的文件,没有明确同意不推送。收尾时工作区干净,或在交付说明里列出每个有意留下的未提交文件。
  5. 测试产物不进仓库。 测试代码放 tests/;截图、录屏、日志、原始测试数据、审计附件放在 .agents/(已忽略,只留本机),不用 git add -f 绕过忽略规则。提交的文件里不写本机路径、用户名或 file:/// 链接,文档之间用相对链接。
  6. 交付说明写清:改了什么和为什么、验证结果和没验证到的地方、遗留问题、提交号;用了规范例外就写原因和影响。
改了…… 更新
新增 / 删除 / 改名 / 拆分源码文件,模块职责 ARCHITECTURE.md 职责清单,或最窄的 docs/architecture/ 专题
数据流、接口、持久化格式、安全边界、跨系统规则 对应的 docs/architecture/ 专题;系统图或阅读地图变了才改 ARCHITECTURE.md 入口
用户能感觉到的行为 CHANGELOG.md;使用方法变了同步 README.md 或 docs/guides/
长期有效的产品或架构取舍 docs/decisions/
反复出现的坑、严重故障 docs/architecture/lessons.md
开发规范本身 只改本文件

普通修复、样式微调不写进架构文档;没有变化的边界不写“本次未改变”。

1. 修改前先定位责任

  1. 查看 git status 和相关差异,保留已有工作;不覆盖、回退或提交他人的无关修改。
  2. 阅读 ARCHITECTURE.md,再按阅读地图打开与任务有关的专题,避免每次加载全部文档。
  3. 搜索目标函数的调用方、相关状态、CSS 选择器及已有辅助函数,再确定修改位置。界面上的按钮或文字,先用 node tools/ui_map.mjs find <屏幕上的字> 查它在哪个文件、样式在哪、调哪个接口、后端哪个函数;每块界面的用途和统一叫法见 ui-flows.md。改了界面文字或流程,顺手更新那里(结构检查会指出对不上的地方)。
  4. 简短说明本次行为变化和负责它的模块。一个修复优先落在能解释问题的最小责任范围内。

UX 请求默认允许调整布局、交互和文案,不代表允许改变文件存储位置、接口协议、工作流语义、模型识别依据或用户数据。

小型 UX 修改快速流程

仅调整文案、图标、颜色、间距或局部交互时:查看相关差异 → 定位负责规则 → 最小修改 → 验证受影响界面 → 本地提交。 同一任务已读过且未变化的规范不反复通读;只读相关专题,不做全仓审查,不顺手重构。 按第 7 节选择相关检查,不默认运行全部 JS/Python 测试。检查通过后,除非又改了代码或出现新问题,不重复运行。 没有改变职责、接口或持久化契约时,不更新架构文档或新增经验记录。提交说明由 AI 根据实际差异编写,无需用户代写。

任务中断后的接续与快照

  • 开工先检查状态和差异。工作区干净时直接继续,不制造空提交。
  • 上次因额度或其他原因中断,存在属于该任务的改动时,先确认文件范围,再选择性暂存这些文件;不得使用无差别的 git add . 收入用户数据、凭据、临时文件或无关工作。
  • 已完成且有验证记录的改动可补正式提交;尚未验证或未完成的改动可先保存 chore(checkpoint): <实际改动摘要> 恢复快照,提交正文明确“未完成/验证待完成”、已做检查和下一步。快照是恢复点,不代表验收通过。
  • 后续修改和验证另作正式提交,不自动 amend、reset 或改写快照历史。若无法区分遗留文件归属,保留原状并说明,不猜测打包。
  • 长任务按可独立验证的完整阶段提交,避免把所有 Git 收尾留到最后。测试范围内检查完成后及时提交,不为额外润色拖延快照。
  • 上述快照和正式提交均只保存在本地,未经明确授权不推送。

2. 模块职责与规模

  • web/main.js 负责注册和接线;ui_sidebar.js 的 createDOM 负责外壳装配。新工具的完整实现放在自己的模块,不继续塞进这两个入口。
  • 界面模块负责交互和渲染;组合、转换、校验等纯逻辑放在对应领域模块。底层模块不能反向导入上层界面,也不能读取 DOM 或选中节点来暗中决定业务行为。
  • 一个模块应有可用一句话解释的主要职责。按“谁拥有状态、谁负责关闭、谁发起请求”拆分,不按随意的行号切割。
  • 复用现有 ui_lifecycle.js、ui_dom.js、translation_service.js、node_material_actions.js 等接口。不要为同一行为再复制一套实现。
  • 通用文件不能成为杂物箱。不要为了省一个文件,把新领域逻辑塞进 utils、素材详情渲染器或浏览器主对象。
  • 不引入没有当前调用方的管理器、适配层、配置项、事件总线或依赖。一次性的简单逻辑可以留在其责任模块内。

规模阈值(只减不增): 普通逻辑文件以 600 行为线,单函数以约 100 行为线。

  • 新文件不超过 600 行;写不下说明有两种以上职责,先拆。
  • 已经超过 600 行的老文件,每次改动后只能变短或持平,不能变长。要在里面加功能,先把一块独立职责搬出去,腾出行数再加。
  • 不为了达标专门大拆;改到哪个文件,就顺手从它身上拆走一块,让超线文件随日常修改逐步变少。
  • 语言目录、数据表和样式表不按这个行数计算。不能通过空壳包装、压缩代码、删注释或碎片化文件绕过。
  • tools/check_structure.mjs 按上次提交比对,新文件超线或老文件变长都会失败。

3. 状态、关闭与异步

  • 每份可变状态只有一个权威来源。预览、计数、序列化结果从它派生,不维护几份会互相覆盖的数据。
  • 子视图状态默认留在子视图。跨界面确需保留的状态才放到 owner;新增共享字段时说明拥有者、初始化、重置和释放时机。
  • 父子视图传容器、必要数据和明确回调,不让子模块随意修改父视图的私有 DOM 和字段。
  • 新建临时窗口优先使用 createViewScope()。按钮、Esc、遮罩、替换窗口、父窗口关闭必须走同一个清理入口;重复关闭应安全。
  • 视图创建的全局事件、观察器、定时任务、拖拽监听和临时预览都要有对应释放路径。禁止仅 element.remove() 就当作关闭完成。
  • 拖拽中关闭也必须释放鼠标监听,恢复此前的 cursor 和 user-select。子窗口消费 Esc 时,不能顺带关闭父窗口。
  • 视图读取请求使用其生命周期的 AbortSignal;重新查询时取消或隔离旧请求。请求返回后检查当前视图和请求身份,不能让旧结果覆盖新内容。
  • 异步写入画布前捕获原 graph/node/widget/value,返回后复核身份及输入;不能在返回后重新找“当前选中节点”然后直接写。
  • 已发出的保存可能在窗口关闭后完成。不要假称取消了服务端写入,也不要让完成回调重新打开或修改已关闭的界面。

提示词工坊的具体状态约定见 frontend.md。不要恢复已删除的嵌入式工坊、旧导入抽屉或第二套草稿来源。

4. CSS 和 UX 迭代

  • 改样式前搜索同名选择器及主题、响应式覆盖,修改实际负责该属性的规则。禁止每轮都在文件末尾追加“最终修复 / override v2”覆盖包。
  • 变更后删除本次取代的重复声明、失效选择器和旧布局分支;不能仅依靠更高 specificity 让旧实现暂时失效。
  • 优先使用现有 --amb-* 设计变量。新增变量必须有实际用途和清楚的归属,不为每个常量包装一层变量。
  • 不新增无解释的 !important。确因宿主样式或既有层叠边界需要时,在附近注释说明冲突对象与原因,并验证普通模式和受影响主题。
  • 静态布局和外观放在 CSS。行内样式用于实际运行时值,例如拖动宽度、定位和数据决定的颜色,不用 JavaScript 重写整套固定样式。
  • 保持插件选择器作用域,避免影响 ComfyUI 的其他按钮、弹窗和输入框。
  • 添加功能时检查窄宽度、长中文、空列表、加载中、失败和禁用状态,以及焦点、键盘访问和嵌套窗口层级。
  • 不为了视觉调整改变按钮的写入、覆盖、删除含义。成功提示必须来自真实成功结果,失败和取消不能显示“已应用”。

5. 文案、数据与文件

  • 新增固定界面文案放入 locales.js,同步中英文;不继续增加散落的 lang === 'zh' ? ... : ... 分支。
  • 用户输入、文件名、模型名和元数据通过 textContent 或已验证的转义工具进入 DOM;不要拼进未转义的 innerHTML。
  • 列表摘要不能当作详情。正文通过对应详情接口读取;分页、去重、空结果和取消语义必须明确。
  • 路径与文件名在后端使用现有边界校验;不能只检查 ..。前端校验不能替代后端校验。
  • 修改模型、封面、附属文件或导入包前先完整校验和暂存。失败时保留旧数据,避免先删除旧文件再尝试保存新文件。
  • 修改多文件发布流程要覆盖中途失败和冲突。单个 JSON 的原子写入不能冒充整组文件的事务。
  • UI 适配不能偷偷迁移用户数据、修改全局配置或改变现有路由与存储格式。确需改协议时同步调用方、兼容策略和测试。

安全底线

ComfyUI-Manager 收录审核检查的就是这几类口子(2026-10 审 Anomalous_TTS 时逐条指出过)。没有“先这样、以后再补”的例外:

  1. 不执行下载来的或用户文件里的代码。 数据不用 pickle、eval、exec、动态导入读;配置文件当数据解析。模型文件只读 safetensors / GGUF 的文件头,.ckpt / .pt / .pth / .bin 不打开,界面提醒它们可能带代码。
  2. 下载要能核对。 只从允许的 https 站点下载,先写 .part,核对 SHA-256 后才改名放入;没有可核对的指纹时在界面上说明。下载的东西只当数据用。
  3. 接口不接受任意本机路径。 只收“类型 + 根目录序号 + 相对路径”,在后端用 resolve_within 校验;需要指向本机某个文件时,由服务端自己找到它,只给页面一个令牌。模型文件本身可以是链接(云服务器上模型文件夹里全是指向平台模型盘的链接):文件夹部分照样用 resolve_within,文件用 model_file_within / model_reference_within 按名字取,不跟着链接走出去,封面、信息和改动都在链接旁边。
  4. 会写入、移动、删除文件或替用户联网的接口只接受本机请求(请求来自本机,没有经过代理,Host 也是本机;ComfyUI 只监听局域网地址时,本机用这个地址打开也算本机)。用 --listen 开放到局域网时,别的设备只能查看。由 api/local_guard.py 的中间件统一把关:/anomalous/ 下 GET 以外的请求默认只接受本机,确实只读的 POST 列进 OPEN_POSTS,不只是读的 GET(备份文件、联网、本机文件夹)列进 LOCAL_GETS;新接口要想清楚属于哪一类,不要为了方便放进 OPEN_POSTS。唯一的例外是云服务器用户在服务器上的插件文件夹里放了 allow_remote_changes 文件(启动时读一次,网页建不了也删不掉):这时 local_guard.may_change 也放行别的设备;接口里要自己判断时用 may_change,只有“浏览器就在这台电脑上”才成立的事(比如在本机的下载文件夹里找原文件)才用 is_local。MCP 始终只接受本机。
  5. 用户的文件删除一律进回收站,没有回收站就拒绝;从不覆盖(同名另存为“名字 (2)”或拒绝)。插件自己产生的临时文件(.part、暂存区)可以直接删。
  6. 只读的接口也按第 3 条来。 “只是读”不是例外;能按名字、编号取的,就不收路径,由服务端在自己登记的范围里找到文件。
  7. 读用户文件要有上限。 限制读取的大小和条数;读不了或超大的文件跳过并在结果里说明,不让一个坏文件拖垮整个请求。读到的内容进页面只当纯文本(本节第二条)。

资源占用

ComfyUI 的内存、显存和 CPU 是留给出图的。插件闲着的时候应该几乎不占资源:

  1. 用户动了才做事。 不在后台轮询、定时扫描或预加载;确需定时的(扫描进度、跟随选中的节点)只在对应界面打开期间进行,关掉就停。
  2. 耗时的活放后台。 大目录遍历、哈希和大量磁盘 I/O 使用已有工作线程/进程路径,不阻塞 aiohttp 事件循环。
  3. 数据跟着界面走。 界面打开时才读,关掉就释放;跨次使用的缓存要小、有上限,写清楚何时失效。长列表只渲染看得到的或前几十条。
  4. 图片用缩略图。 网格和列表用缓存的缩略图,原图只在看大图或拖到画布时读取;浏览器里不常驻大量原图。

功能原则

几个功能对用户的承诺。改这些功能时不能破坏;确需例外,先问维护者:

  1. 模型检查(模型医生)从不自己改工作流。 检查只读;只有用户按了“换上”或“下载”才动节点,而且只换成同一个文件(SHA-256 指纹一致)。只是同名、没法核对的候选,标明“按文件名”由用户决定。下载的来源(C 站按指纹、工作流带的链接、ComfyUI-Manager 模型清单)在界面上写明。完整的判断规则(三档可信度、基础组件只认指纹、下载来源与核对)见 docs/guides/model-check-rules.md(英文版 model-check-rules.en.md,README 的按钮指向这两份),改模型检查前先读、改了规则两份一起改。
  2. 搭配只记住,从不修改参数数值。 存的时候是什么,放回画布就是什么:强度、CLIP 层数、提示词等一律原样,不用节点默认值顶替,也不替用户“调”。想要别的数值,在画布上调好再存一个新搭配。放上画布只新放一组节点,从不改画布上已有的节点。(理由见 docs/decisions/README.md AD-021;模型检查的见 AD-005、AD-006、AD-020。)

6. 清理旧实现

  • 替换一条路径时搜索它的导入、导出、调用、字段、事件和选择器;确认无用后一起移除。
  • 不保留注释掉的大段旧代码、EXTRACTED 占位、无人使用的备选实现或“以后可能需要”的分支。
  • 拆模块后检查移动函数引用的闭包变量、导入、回调参数和返回值。语法通过不代表按钮点击不会出现未定义变量。
  • 不保留两个相互覆盖的 onclick 或两条完成同一请求的路径;让所有入口调用同一个实现。
  • 不用空 catch、伪造成功值或任意 optional chaining 掩盖结构错误。可选宿主能力才允许局部降级,并给出准确结果。

7. 按风险验证

从插件根目录运行相关检查。选择与变化相称的验证,不为纯文案、文档或低风险样式改动制造镜像测试。

修改范围 至少验证
导入、导出、模块拆分 JS 语法、模块链接,以及受影响按钮的真实执行路径
提示词工坊、词块 node tests/prompt_tags.mjs、node tests/prompt_boxes.mjs
素材提示词、节点参数 node tests/material_prompt_cross_node.mjs、node tests/node_material_actions.mjs、node tests/node_parameter_sets.mjs
搭配、往画布插节点、撤销 node tests/combo_slots.mjs、node tests/graph_splice.mjs、node tests/canvas_undo.mjs
提交前全部跑一遍 node tools/run_tests.mjs(说明见 docs/guides/testing.md)
CSS、布局、交互 实际浏览器验证受影响状态;涉及宿主行为时验证 ComfyUI
文件修改、导入、存储 对应 Python 测试,至少覆盖成功、冲突和中途失败保留旧数据
仅文档 检查链接、命令、实际代码一致性和 Git 差异
  • 模拟测试尽量加载实际模块,只替换外部系统边界;不要把待验证的业务函数也 mock 成成功。
  • 修复故障时,优先补充能复现原故障的行为测试。不能只通过源码字符串“存在某段代码”来证明修复。
  • UX 明确替换旧交互时,更新测试到新的用户流程,并保留原本要保护的行为;不要仅删除失败断言或重新塞回废弃功能。
  • 新增应随仓库交付的回归测试要检查 .gitignore,确认确实进入版本控制。
  • Python 测试要在 ComfyUI 的 Python 环境里跑(node tools/run_tests.mjs 会自己找),核对实际发现的数量;零项测试不算通过。
  • 无法运行真实宿主、网络服务或完整测试时,准确说明缺口;不要将模拟画布、语法检查或已有通过数量称为本轮宿主验证。

8. 文档与交付

  • 架构文档只记录职责、数据流、契约和关键约束。颜色、像素值及审美描述以 CSS 为准,不每次 UX 更新都往架构入口追加长篇设计说明。
  • 该更新哪份文档见第 0 节的表。规范以本文件为唯一正文,避免几份要求各自漂移。
  • 完成前审查差异、死代码、临时文件和空白错误;保留现有文件编码及换行风格。

交付自查: 新职责放对位置了吗?是否只有一个状态来源?每条关闭路径会释放资源吗?迟到请求会写错对象吗?旧代码和旧 CSS 清掉了吗?新文案已本地化吗?用户文件失败时还在吗?新接口会动文件或联网吗,只接受本机请求了吗?接口收了路径吗,读用户文件有上限吗?插件闲着时还占着 CPU、内存或显存吗?测试验证了实际行为吗?