/** * 公司 / task 产物目录的**唯一**推导实现(R-19.3)。 * * 为什么单独一个模块:`graph_files.rel_path` 只存相对路径,绝对路径由代码每次拼。 * 写的一侧(goal-contract 登记契约、graph-engine 登记节点产出)和读的一侧 * (graph-engine 拼提示词、控制台拼可点路径)必须算出**同一个字符串** —— * 算不出同一个,索引就指向空气,而且不报错:文件在,登记也在,只是两边说的不是一个地方。 * 这正是「产生 → 传递 → 落库 → 读回」里「传递」那一环断掉的样子。 * * 此前这两个函数在 graph-engine.js 与 goal-contract.js 各有一份镜像(后者带 ponytail * 注释点名了上限与本升级路径)。三处调用方一出现就必须收拢:靠注释约束「两份保持逐字同构」 * 在第三份出现时已经不成立了。 * * GRAPH_RUNS_DIR **每次调用时读**,不在模块加载时快照 —— 镜像时代两个模块各自快照, * 加载顺序不同就会算出不同的根(测试先 require 再设 env 时尤其明显)。 */ const path = require('path'); const REPO_ROOT = path.resolve(__dirname, '../..'); /** * 公司根目录 —— R-19.3 定案:**代码推导,不入库**。 * 库里存绝对路径会烂(W13 清掉的那 10 条 legacy_path 悬空行就是这个病)。 * GRAPH_RUNS_DIR 覆盖时跟着挪,理由与 runRootDir 那处 override 一致: * 否则测试每跑一次就往仓库 data/companies/ 里堆目录。 */ function companyRootDir(companyId) { const runsRoot = process.env.GRAPH_RUNS_DIR || null; return runsRoot ? path.join(runsRoot, '_companies', companyId) : path.join(REPO_ROOT, 'data', 'companies', companyId); } /** * 本 task 的产物目录(相对公司根,走 tasks/{taskId}/,不走 workspace/)。 * * 按 task 分而不是平铺:同一家公司会跑很多 task,平铺的话第二个 task 的 prd.md * 会覆盖第一个。不走 workspace/ 是因为它的现有语义是「Agent 自治领地、框架不干预」 * (06-沙盒自治),而这里要的是框架管着、可检索的交付物区 —— 两种所有权混在 * 一个目录里,索引就没法保证不漂移。 * * taskId 缺省落 `_no-task`:宁可全归到一个显眼的坑里,也不要散落到公司根上跟别的目录混住。 */ function taskDirRel(taskId) { return path.join('tasks', taskId || '_no-task'); } module.exports = { companyRootDir, taskDirRel, REPO_ROOT };