Files
InfoRSI/.dependency-cruiser.cjs
iomgaa 75d7cffd27 feat: flow 第 1 部分(骨架、研究开始、第零轮)与第零轮检验
按任务书 12 实现 src/flow:从账本现算下一步的纯函数、主循环、恢复入口、派模型任务和跑正式运行两个共用动作、冻结配置、基线、第零轮三个研究者阶段和入口分配,走到第 1 轮时停下。materials 导出 finalEntries、加 researcherId 和 StudyRecord。

审阅采纳两条:研究编号本机已用过时冻结前报错;docker run 没启动时写完结果就停下,不在本进程里无限起新编号。

eval/ 新增第零轮检验:起研究命令行、回放假模型、检验用 Jev 客户端、六问质量评估、16-real-1 回放、杀进程与两份同时跑。tsc 与 depcruise 也检查 eval/,新增 eval 只经 index.ts 用正式代码的规则。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 10:58:52 -04:00

139 lines
5.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 模块之间的依赖规则,来源是 docs/结构.md 第二部分(模块表)和第六部分(检查规则)。
// 模块按 src/<模块名>/ 认;新建模块目录后自动受这些规则检查。规则主要管 src 下的模块,tests/、eval/ 不受"只有某模块能用某外部包"的限制;
// eval/ 另有一条:只能经 src/<模块>/index.ts 用正式代码(任务书 12 第三部分第 4 条)。
// 模块表"依赖"一列:每个模块除了自己和 vocab 以外,还能引用哪些模块。plugin 装配时可用各模块。
const ALLOWED = {
plugin: [
"flow", "export", "config", "materials", "submissions",
"ledger", "agents", "runner", "tasks", "workspace", "jev", "rules",
],
flow: [
"ledger", "rules", "materials", "submissions", "agents",
"runner", "tasks", "workspace", "config", "jev",
],
export: ["ledger", "rules", "materials"],
config: ["rules"],
materials: ["ledger", "rules"],
submissions: ["jev"],
ledger: [],
agents: [],
runner: [],
tasks: [],
workspace: [],
jev: [],
rules: [],
vocab: [],
};
const MODULES = Object.keys(ALLOWED);
const anyOf = (names) => `(${names.join("|")})`;
// 外部的东西各由哪些名字认出来。核心模块带不带 node: 前缀都认;
// npm 包装好后解析成 node_modules/ 下的路径,没装时是包名本身,两种都认。
const npm = (names) => `(^|node_modules/)${anyOf(names)}(/|$)`;
const SUBPROCESS = [
"^(node:)?(child_process|cluster)$",
npm(["cross-spawn", "execa"]),
];
const SQLITE = ["^node:sqlite$", npm(["better-sqlite3", "sqlite3"])];
const PI = npm(["@earendil-works/[^/]+"]);
const directionRules = MODULES.map((name) => ({
name: `direction-${name}`,
comment: `${name} 只能引用自己、vocab 和模块表里列出的模块:${ALLOWED[name].join("、") || "无"}`,
severity: "error",
from: { path: `^src/${name}/` },
to: { path: "^src/", pathNot: `^src/${anyOf([name, "vocab", ...ALLOWED[name]])}/` },
}));
module.exports = {
forbidden: [
{
name: "no-circular",
comment: "不许循环引用",
severity: "error",
from: {},
to: { circular: true },
},
{
name: "unknown-module",
comment: `src 下只有模块表里的模块目录:${MODULES.join("、")}`,
severity: "error",
from: { path: "^src/", pathNot: `^src/${anyOf(MODULES)}/` },
to: {},
},
...directionRules,
{
name: "through-index",
comment: "别的模块只能通过目录下的 index.ts 引用它",
severity: "error",
from: { path: "^src/([^/]+)/" },
to: { path: "^src/[^/]+/", pathNot: ["^src/$1/", "^src/[^/]+/index\\.ts$"] },
},
{
name: "outside-src",
comment: "src 下的文件只许引用 src/、node_modules/ 与 Node 内置模块,不能借 src 外的文件绕开规则",
severity: "error",
from: { path: "^src/" },
to: { pathNot: ["^src/", "^node_modules/"], dependencyTypesNot: ["core"] },
},
{
name: "eval-through-index",
comment:
"eval/ 像用户一样用正式代码,只能经 src/<模块>/index.ts 引用(CLAUDE.md\"测试\":正式代码和检验代码完全分开)",
severity: "error",
from: { path: "^eval/" },
to: { path: "^src/", pathNot: "^src/[^/]+/index\\.ts$" },
},
{
name: "pure-allowlist",
comment:
"rules 和 vocab 不碰文件、数据库、网络、子进程和 Pi:除了 src 下允许的模块," +
"只许引用 typebox 和 node:crypto",
severity: "error",
from: { path: "^src/(rules|vocab)/" },
to: { pathNot: ["^src/", "^node_modules/typebox/", "^(node:)?crypto$"] },
},
{
name: "sqlite-only-ledger",
comment: "只有 ledger 能用 SQLite",
severity: "error",
from: { path: "^src/", pathNot: "^src/ledger/" },
to: { path: SQLITE },
},
{
name: "pi-only-agents-plugin",
comment: "只有 agents 和 plugin 能用 Pi",
severity: "error",
from: { path: "^src/", pathNot: "^src/(agents|plugin)/" },
to: { path: PI },
},
{
name: "subprocess-only-runner-workspace",
comment: "只有 runner 和 workspace 能起子进程",
severity: "error",
from: { path: "^src/", pathNot: "^src/(runner|workspace)/" },
to: { path: SUBPROCESS },
},
{
name: "tasks-not-runner",
comment: "tasks 不许引用 runner:runner 只管怎么跑,tasks 只管怎么判,由 flow 串起来",
severity: "error",
from: { path: "^src/tasks/" },
to: { path: "^src/runner/" },
},
],
options: {
doNotFollow: { path: "node_modules" },
tsPreCompilationDeps: true,
tsConfig: { fileName: "tsconfig.json" },
// 按 Node 的 ESM 规则读 npm 包的 exports(dependency-cruiser 默认不读),
// 否则 typebox 这类只在 exports 里给入口的包解析不到。
enhancedResolveOptions: {
extensions: [".ts", ".js"],
exportsFields: ["exports"],
conditionNames: ["import", "node", "default"],
},
},
};