Skip to content

roarpeng/graphflow

v2.2.0Apache-2.0

图谱上下文压缩与任务规划插件(10 个 MCP 工具)。能力:压缩上下文、DAG 规划、增量建图、技能飞轮、诊断与产物导入导出。DeepSeek Harness:dsh plugin --profile web add @roarpeng/graphflow;工具名为 mcp__graphflow__graphflow_*。先调 graphflow_context(传 rootDir),复杂任务再 plan,改完代码后 index。

Changelog

All notable changes to this project are documented in this file.

[Unreleased]

Fixed — 第 0 步性能与健壮性(迁移 Rust 前的架构债清偿,复审登记项全闭环)

  • file 传输读路径共享缓存(P2-8):GraphifyFileClient.peekStore() 静态共享读入口(走进程内 graphifyFileStoreCache,stat 校验+delta 已应用,不开句柄不写);graphStoreNeedsIndexing 与 readFileGraphStore/resolveGraphStoreAfterIndex 不再各自 readFileSync+JSON.parse 整个 9.5MB store——每 preview 省 2 次全量读+解析。消费方 mutation 全审计(全只读),peek 结果仍做浅拷贝防御未来调用方。
  • embedding 后台推理限额:deferred pass 从每 preview 最多 512 次 ONNX CPU 推理降为默认 128(GRAPHFLOW_EMBEDDING_PASS_LIMIT 可覆盖;deadline 不变兜底)。
  • sqlite 并发硬化:构造 busy_timeout=15s(原 5s);migrate() 无锁快路径(健康库并发打开零写锁)+ BEGIN IMMEDIATE 锁内 user_version 双检——两进程同时首开旧库不再因 duplicate column 构造失败;mergeSiblingJsonStoreIntoSqlite 的 snapshot→plan→upsert→rename 全段进目标写锁,锁内重检 JSON 兄弟存在性(输家不再用过期快照覆盖赢家重编号的对话轮——混合宿主丢写入根因),无 withMergeLock 的目标降级 best-effort 锁文件。
  • HTTP stateful 会话空闲 TTL:默认 30 分钟(GRAPHFLOW_HTTP_SESSION_TTL_MS,0 禁用),每请求刷新活跃;DELETE/TTL 扫描/关服共用同一 teardown;弃置会话不再随进程永生。
  • 快照物化缓存:实测否决(诚实登记):对真实库(95.4% 行带 metadata,均 968B)A/B 测量——任何保留"每快照独立可变对象"契约的缓存方案(structuredClone 10x、JSON 重解析 7x 负优化)都劣于现状 lazy getter;结论写入 rowToSnapshotNode 注释+契约测试锁定。根治 P0-3 需改 preview 调用方(一次 preview 8-12 次 readSnapshot),留待后续。
  • 测试加固:TTL 扫描用例改静默等待+双探测(轮询会刷新活跃时间,自相矛盾——原固定 500ms 在全量负载下窗口不足)。

Tests

  • 新增 26 用例:m-fileread-cache(12:peek 零重读探针/行为等价/大文件回退/限额 env)、sqlite-concurrency-hardening(9:构造竞态/健康库零锁/合并锁序/输家跳过/锁文件回退/快照契约)、mcp-http-session-ttl(5)。全量 296 文件 / 2782 用例绿,tsc/eslint 干净。

[Unreleased]

Fixed — configPath 穿透角色/探测链(跨工作区操作用错配置的 live 事故)

  • 根因(两处泄漏):diagnoseRoutingResult 的 role 解析闭包调用 resolveModelForRole/resolveModelWithFallback 时丢弃了 configPath(回落到进程 cwd 层);executeRolePrompt 内部 resolveConfig() 无参——同样解析 cwd 层并据此装配 provider 环境。后果:从 A 仓库对 B 项目跑 --config 时,模型/凭据来自 A 的层——live:对 Ele 工作区的探测把 gpt-4.1-mini(GraphFlow 仓库层的默认)发到了 Ele 的 DeepSeek 端点。
  • 修复:resolve 闭包穿透 configPath;executeRolePrompt 的 opts 增加 configPath(resolveConfig(opts?.configPath));probe 全链接线——probeRoleConnectivity 增参,plan/run 两处预检探测与 probeRoutingConnectivity 均传入。其他 executeRolePrompt 调用点不传则维持 cwd 语义(零回归)。
  • live 验证:Ele selfcheck 的 llm-probe 不再出现 gpt-4.1-mini——模型解析正确;剩余的 "Missing provider credentials" 是该工作区的真实状态(Ele 层以 ${OPENAI_API_KEY} 占位覆盖了全局明文 key 且该 env 未设),探测如实报告。

Fixed — providerPriority 开放给已配置的自定义 provider(用户工作区被 fail-fast 挡死的 live 事故)

  • 根因:providers 映射是开放的(Record<string, ProviderConfig>,支持任意 OpenAI 兼容自定义端点),但 routingPolicy.providerPriority 的校验是封闭五元枚举(openai/anthropic/bailian/doubao/deepseek)——两者自相矛盾。用户在优先级里列出自己配置的 provider(如 openbmb 连 localhost 服务)时,叠加项目层 fail-fast 直接让整个工作区无法加载配置(错误提示还误导性地指向"反斜杠路径")。
  • 修复:三处对齐开放语义——schema 的 providerPriority 放宽为 string[](交叉引用校验移到能看见 providers 映射的 loader);validateConfig 与 validateConfigDetailed 的允许集 = 五内置 ∪ Object.keys(input.providers);buildFallbackChain 透传自定义名(健康/失败簿记仍按内置 ProviderName 键控,自定义名不带追踪——注释说明)。错误信息现在点名未知 provider 并列出合法集合,不再是无信息量的泛句。
  • live 验证:触发事故的真实工作区配置(openbmb + openai-compat + localhost:8000)config validate 通过、context preview 正常返回锚点。

Tests

  • 新增 m-provider-priority-open(5 用例):已配置自定义名通过 / 未知名失败且错误点名 / detailed 报告区分已配置与未知 / resolveConfig 加载含自定义优先级的项目层 / 内置优先级与默认链不变。全量 297 文件 / 2789 用例绿,tsc/eslint 干净。

[2.2.0] — 2026-10-02

Added — 成本经济学升级 Phase 2+3(U4 SoL-Pi 接线 / U5 负知识库 / U6 判断层 / U7-U8 设计稿)

  • U4a 装饰开关修复(两处 settings 开关真实生效):reduceObservationImpl 入口门控 reduce.enabled——false 时返回明确拒绝理由(含开关路径与恢复指引),不再静默全量/静默压缩,MCP reduce:true 入口被 settings 真实控住;dsh 自动投影判定改为三级优先 env 显式值 > settings(observations.enabled,三层配置逐层合并镜像 resolveConfig)> 默认开,settings 关闭后投影拒绝执行(不 spawn CLI)。
  • U4b Compact 压力供给(替代通道,诚实约束已注释):dsh plugin 会话级计数器(每个 tool/result 累计原始 bytes,投影成功后结算为投影 bytes),持久化 .graphflow/observation-pressure.json(≤32 会话,never throws);注:toContextPressure 有意丢弃"只有 usedTokens 无 maxTokens"的信号,估算需与已知窗口组合才真正生效——该约束在代码与设计上均如实保留。
  • U4c ObservationPack 保守默认(MCP preview):text copy 超 inlineThresholdBytes(默认 8192)且机制开启时自动 packObservation——pack 优先于桩化(句柄可召回,桩化丢信息),失败回退既有桩化路径;structuredContent 附 observationHandle。大响应进对话史的体积从源头收敛。
  • U5 负知识库(fail → 教训 → 注入):updateEpisodeOutcome fail 分支对非任务回显的 lessons 幂等 upsert anti-pattern-lesson 节点(指纹=taskKey+lessonKey+symbolRefs,failCount/episodeIds 累积,episodeIds ≤10);精度门 failCount≥2 才注入——suggestSkillConditionHints 的 avoidPatterns 追加前 3 条(avoid: <教训>(N 次 episode 实证)),单次失败不注入;pass 分支 resolve 同 taskKey 教训(重开证据周期语义:再失败从 failCount=1 重新累计,不借旧账)。
  • U6 判断层路由(存量复用):确认 TypeSafe System One 客户端(src/routing/typesafe-systemone.ts,真实 API 契约:choice/score/noul 类型化判定)即判断层;TYPESAFE_API_KEY(或 economy 侧挂 localhost)启用;selfcheck judgment-tier 报告 local-jev / cloud-jev / cloud-economy / rules-only 四态。零配置用户恒为 rules-only,降级可见。
  • U7/U8 设计稿:docs/design-output-toolfirst.md(输出侧 tool-first:executionDescriptor 的 resultProtocol/edit-intent-v1、SKILL.md 输出纪律"引用锚点不复述原文"、意图密度测量里程碑)、docs/design-blast-radius.md(working-set 与 diff-challenge 合并为 N 跳影响面引擎,viaPath 全路径 reason,迁移以现有测试锁定行为)。

Tests

  • 新增 24 用例:u4-sol-pi-wiring(17:reduce 门控/dsh 三级优先/压力计数结算落盘/preview pack 召回闭环/回退)、m-anti-pattern-lessons(7:两次失败注入/单次不注入/复读拦截/pass resolve/独立指纹/上限 3/去重有界)。

Added — 成本经济学升级 Phase 1(U1 台账 / U2 前缀可缓存性 / U3 质询门)+ 判断层自检

  • U1 成本台账(两栏测量):provider-executor 全路径捕获 ProviderUsageStats(含 promptCacheHit/Miss/Write,此前解析后零消费)→ drainProviderUsageEvents;新 src/learning/cost-ledger.ts 落 graphflow-out/cost-ledger.jsonl(llm/deliver 两类事件,>4000 行截老保新 2000);新 src/routing/model-prices.ts 价格表(DeepSeek/OpenAI/Anthropic 近似价,env GRAPHFLOW_PRICE_* 可覆盖;localhost/127.0.0.1 baseUrl 一律零价=本地判断层免费;cacheHit 按 0.1 因子计价)。栏 A 自有 LLM 成本:run 出口与 MCP 工具出口双 drain 落账,reportOutcome 把 drain 汇总快照进 EpisodeRecord.costSummary;栏 B 宿主交付字节:每个 MCP 工具响应的 text copy 字节数(归因贡献,非宿主账单——宿主侧计费不可测,已注释明示)。selfcheck 新增 cost-ledger 项(estCost/cacheHit%)。
  • U2 宿主前缀可缓存性契约:锚点通道出口统一稳定排序(分数决定选谁、id 决定顺序——quota/budget 等质量决策读排序前的 packed 序,选择集合与质量零变化,只有展示顺序变稳);dialogue 行按 (sessionId, seq) 稳定序(去 updatedAt 变序);graphflow_context 的 text copy 只投影稳定面,易变数值(tokenBudget 全部/unbudgetedTokens/accountedTokens/contextPressure/updatedAt)移出 text copy 只留 structuredContent(尾行 volatile-metrics: see structuredContent);同 query TTL 过期重算时锚点集合签名不变则复用上一轮字节(context-cache stableCopyTrail)。新 src/graph/response-stability.ts 的 computePrefixStability(UTF-8 字节口径)。顺序语义变化:anchorChannel=(layer,id) 字典序——retrieval-rank 基线经文档化机制刷新(132 条纯重排,recall 100%/top-K ≥90% 不变);m79 断言改 relevance 语义(成员资格不变)。
  • U3 计划质询门(规则版,零 LLM):diff-challenge 新增 planNodes 入参与 extractTouchedFromPlan(文件/camelCase/PascalCase/snake_case 提取,符号经图精确解析落文件,不臆测);桥接主集成——graphflow_insight merge 对合并后的 agent 计划自动跑图事实质询(external-caller/deleted-symbol/requirement-link,≤10 条),challenges[] 附 merge 响应(MCP 面已透传),SKILL.md 指示执行前必须回答;LLM 路径同挂(planSource=llm 时 advisory 默认,GRAPHFLOW_PLAN_GATE=enforce 命中即降级 suggested);fail-open 全路径。live:本机 LLM 计划命中 10 条质询。
  • U6(部分)判断层自检:selfcheck 新增 judgment-tier 项——local-jev(localhost baseUrl)/cloud-jev/cloud-economy/rules-only 四态可见(存量 TypeSafe System One 客户端即判断层,TYPESAFE_API_KEY 或 economy 侧挂即启用)。
  • 效率门诚实化:evaluateEfficiencyFloor 在显式阈值 + 0 配对记录时以明确指引 FAIL("no paired-arm data — run mechanism trial / benchmarks --record"),不再让 "0 < 1" 冒充质量结论。

Tests

  • 新增 25 用例:m-cost-ledger(7:价格/env 覆盖/localhost 零价/截断/聚合/episode 快照)、m-context-stability(9:字节稳定/前缀追加/dialogue 稳定序/text copy 禁入字段/trail 复用/prefixStability)、m-plan-challenge-gate(9:命中/符号解析/fail-open/截断/提取单元)。全量 291 文件 / 2732 用例绿,tsc/eslint 干净。
  • 已知边界(登记):自定义 config+全新空图的 E2E merge 计划组装为空(默认配置 m80 全绿覆盖同流程);openai 适配器 usage 捕获为 best-effort 待扩展(deepseek 完整)。

Fixed — 代码审计驱动的性能与诚实性批次(Wave 1+2,每项均代码级复现后修复)

  • preview 热路径(P0):readGitVisibleFiles 增加进程内 5s TTL 缓存——此前每次 preview 都 spawn 一个 git ls-files 子进程(256MB maxBuffer);manifest(index-state.json,124KB)从双重解析合并为 loadCacheStateCached 单次记忆化(mtime:size 指纹失效,上限 64 条)。
  • 连接生命周期(P0):previewContext/indexFile 全路径 try/finally 关闭自己创建的图客户端(缓存命中分支同样)——此前每次 preview/watcher 保存都新开 sqlite 连接且永不关闭,常驻 MCP 进程的 fd/WAL 映射持续累积。延迟向量通道(deferred embedding)移交的客户端除外。watcher 增量索引失败从 .catch(() => {}) 静默吞错改为 logger.warn。
  • file 传输倒排索引增量修补(Wave 2,读路径写放大):preview 的自身写(对话轮/workbench topic)走 delta 追加时不再把倒排索引置 null——按被触及节点的旧 token 删除/新 token 插入原地修补,成本 O(触及节点 token) 而非全店重分词 O(n×content);删除节点同样修补。全量重写路径保持原语义。与全量重建的等价性有测试背书。
  • 两个无界增长文件(P1):token-savings.json records 环形上限 2000 条(存量超限文件下次写入自愈;被截明细的聚合计数折入持久化 truncatedPrefix,累计统计与全量日志完全一致);.graphflow/mcp-http-audit.jsonl 追加改用进程内尾条缓存(size 未变即用缓存 seq/prevHash,连续追加零全量读;哈希链语义逐字节不变,resetAuditTailCache 测试钩子)。

Fixed — 第二轮复审修复(Wave 3)

  • deferred 向量路径的图客户端所有权闭环(复审 #1,高):preview 触发索引时若把 client 移交给延迟 embedding pass,此前无人再关闭它——常驻 MCP server 每个 preview 泄漏一个 sqlite 句柄(Windows 上 WAL 文件 EBUSY 锁定,探针实证)。现在:pass 完成时若已被更新 target 取代则自行关闭;refreshIndexForPreview 覆盖 target 时释放旧 client(pass 进行中则留给其 finally);warmContextPreview 尊重移交布尔值并在 finally 关闭自有 client;server 优雅停机新增 closeAllGraphClients()(SIGTERM/SIGINT/stdin EOF 路径),退出前释放全部图句柄。
  • m-index-patch 测试空转修正(复审 #2,中):首版测试的 store 仅 328KB(< 4MB delta 阈值),patchIndexInPlace 从未被执行——改用构造选项 deltaMinBaseBytes: 1024 压低阈值并加"delta 文件必须存在"守卫,测试现在真正覆盖增量修补路径(修补正确性已由复审的 >4MB 探针独立背书)。
  • git 失败结果不再入 5s 缓存(复审 #3,低):broken repo 修复后最长 5s 仍用非 gitignore walk 的陈旧失败缓存——现在 status!==0 与 spawn 异常同样不记忆化,下次调用即重试。
  • deleteEdge 保留倒排索引(复审 #5 项,info→修):边删除不触及任何节点 token,补空 patch 使索引免于全量重建。

Fixed — 承诺核验收口(round 3 verification)

  • 中文查询口径对齐到有工件的证据:README(英/中)与 docs/flywheel-reproduction.md 中 "englishQuery 提供 5/5、不提供 0/5" 的断言无仓库工件支撑,且与权威冻结目录 benchmarks/flywheel-proof-claims.json 记载的 v2.0.3 held-out 审计(中文查询 2/5)冲突——三处全部改为引用该 commit 锚定目录;flywheel-reproduction.md 同时移除无工件的 "15-query independent audit" 段,替换为 claims 目录的实测口径。

Fixed — TS/JS AST 索引依赖与降级可观测

  • typescript(^6.0.3)进入 optionalDependencies:此前仅存在于 devDependencies,npm 全局/npx 安装树上没有 TS 编译器,TS/JS(目标用户主力语言)索引静默降级为正则解析(仅 logger.error, 用户不可见)。现在默认安装大概率带上编译器,同时平台解析失败也不毁安装(尊重既有降级路径)。
  • 降级可观测:src/graph/language-indexers/typescript.ts 新增导出 getTypescriptBackendStatus(): "compiler" | "regex"(模块级 memo:loadTs 成功一次即 "compiler",require 失败发生降级即 "regex")。
  • graphflow selfcheck 新增 ts-indexer 检查:compiler → ok("TS/JS parsed with the TypeScript compiler");regex → warn("TS/JS fell back to REGEX extraction — the optional 'typescript' package did not resolve from this install; AST features (calls/inherits/jsdoc) are degraded")。
  • disclosure.network 补 https://huggingface.co:仅用于首次语义嵌入模型下载,可经 HF_ENDPOINT 镜像;embeddingProvider: "fnv" 可完全避免该网络访问(已在 disclosure.permissions.network 注明)。

Docs — README 口径诚实化(中英同步,12 处)

  • "11 languages tree-sitter ASTs" → 准确口径:10 个 tree-sitter 文法语言(含 C/C++)+ TS/JS 走 TypeScript 编译器(可选依赖,缺失降级正则);Markdown 正则。
  • "Fully offline / 完全离线" 三处绝对化表述 → "本地优先":默认语义向量后端首次从 huggingface.co 下载一次模型,失败降级完全离线 hash 后端;embeddingProvider:"fnv" 可完全不联网。
  • "golden set in CI: Hit@5=100%" → CI 门禁实为 ≥80% recall / ≥90% top-K;100%/MRR/NDCG 是 commit 锚定基准快照。
  • 删除无工件支撑的 "independent audit 15 held-out queries" 及 20-query 开发集数字(仓库内无数据集/脚本/结果)。

Tests

  • 新增 17 用例:m-hotpath-fixes(5)、m-index-patch(3)、m-unbounded-files(4)、m-ts-indexer-status(5)。全量 288 文件 / 2707 用例绿,tsc/eslint 干净。

[2.1.0] — 2026-10-02

修复 2.0.3 中 MCP 常驻进程内存/线程无限增长、graphflow-mcp --http 只能服务一次请求两个问题——都需要升级到本版才生效; 另含凭证环境变量优先、上下文预览提速约 45%、Efficiency Agent 2.x 包(仓库内,未发布到 npm)。

Added — Efficiency Agent 2.x 工程规范落地(packages/efficiency-agent)

  • §27 端到端管线(eff-agent run):真实指纹/Project Twin/经验检索/命名空间缓存/GraphFlow MCP 上下文/Reuse Gate/安全门/工具与模型路由/合同/成本优化/动态 harness/写入审计/trace。 无执行器不再报成功:not-executed/unverified/blocked/violation 各有独立退出码。
  • §22 特性开关(默认值与规范一致,broker 默认封顶为 shadow)+ flags rollback 一键回滚; §9 fail-open/closed(GraphFlow 故障→twin-only、缓存损坏→FRESH、策略文件损坏→STRICT、 遥测不可写→不学习、管线异常→原生 worker)。
  • §6–§8 安全:能力模型、R0–R5 风险分级与默认/STRICT 策略、验证命令与 worker 启动的准入判定、 运行后基于 git porcelain 的写入审计、脱敏、不可信内容包裹、注入检测、缓存准入(防投毒)。
  • §2 Execution Contract v1 增量字段(decisionId/budget/permissions/validationPolicy/provider/ graphVersion/toolchainHash/avoidPatterns),schema 与 TS 校验双向一致。
  • §11/§24 trace:事件序列(stage/outcome/reason/evidence/policyVersion)、决策记录、 安全判定、成本;trace replay 与 OTLP JSON 导出。§15 策略生命周期(Shadow→Canary→Production)。
  • §18 基准:五轨(baseline/graphflow/shadow/conservative/adaptive),固定 baseCommit 的独立 worktree、oracle 判定、隐藏测试、回归守卫;bench compare 输出 delta、Net Saving 与 §28 验收门。
  • benchmarks/eff-tasks-v1.jsonl 更名为 golden-v1.jsonl(50 任务全部带 baseCommit 与 oracle)。
  • §18 数据集补齐:Golden-Extended 200(15 个任务族,scripts/gen-extended.mjs 生成并可 --check 复现)与 Long-Horizon 20(125 步,同一会话共用一个 worktree,逐步标注 fresh/reuse-allowed/ must-refresh)。check-golden.mjs --dataset all(84 个提交、0 错误)与可复现检查进入 release gate 的 golden 门;workflow 新增 datasets-nightly 夜间矩阵(需 EFF_AGENT_CLI,未配置时报告跳过)。
  • 常驻 GraphFlow 服务:EFF_GRAPHFLOW_MCP=http://127.0.0.1:PORT/mcp 以 Streamable HTTP 连接已运行的 graphflow-mcp --http --port PORT,不再每个进程冷启动;非回环地址必须带 EFF_GRAPHFLOW_MCP_TOKEN (Bearer),否则以拒绝原因 fail-open。实测本仓决策 P50:每进程拉起已发布 2.0.3 为 5.3 s、拉起本仓 源码服务为 4.6 s、常驻 HTTP 为 1.35 s(规范目标 < 1.5 s)。冷进程本身达不到目标:node+模块≈1 s、 ONNX 嵌入模型≈1.7 s、tokenizer≈0.3 s,再加一次预览。
  • §19/§20 发布门禁 npm run gate:eff-agent(code/contract/security/cache/golden/chaos/perf/package 八门,缺测试即 FAIL)、GitHub workflow、SBOM/SHA256SUMS/provenance、secret scan。

Fixed — Efficiency Agent 测试中发现的缺陷

  • 安全:结果缓存回放发生在安全门之前,被拒绝(deny/approval-required)的请求仍可回放缓存结果; 且验证命令与执行器参数不在指纹中,换了验证命令或 --model 也会命中。现安全门先于回放, 验证命令、执行器 args/promptVia/env 键名进入指纹环境轨(env 值不入,防泄密)。
  • Windows .cmd 垫片(npm 安装的 claude/codex/gemini、npm test)超时只杀掉 cmd.exe,真实进程 持有管道导致超时失效(实测 500ms 超时跑满 17s)。agent 与验证 worker 改为 taskkill /T /F 杀进程树。
  • complex harness 的"同一失败重复两次"停止条件只比较 agent 自身退出码,验证在进步时也在第 2 轮停止; 现同时比较验证反馈。
  • 自由填写的类别(--category、语料 category)写入 trace 后不符合 schema,bench compare 也照收; 现 CLI 退出码 2、语料报违规、管线回退到分类器,provenance 门拒收。trace schema 补齐 R2–R4 度量规则,与 TS 校验一致。bugfix 分类覆盖 crashes/crashed/failed 等词形。
  • eff-agent 读取 GraphFlow 上下文时优先使用 MCP structuredContent(mcp.textCopy: "auto" 下 大响应的文本副本只是占位)。
  • CLI:已知命令自身报错(如 governance release-gate 未达标)时不再附带误导性的 unknown command "governance"。
  • 结果缓存此前永不过期(回放跳过执行与验证);新增 TTL(默认 6h,ttl-expired), PipelineDeps.cacheTtlMs 可分别覆盖 context/result TTL。
  • 写审计改为内容签名快照:可检测重复修改已脏文件、git-ignored 文件写入,以及子目录根下越出工作区的写入 (旧逻辑把 ../sibling 误算成根内文件放行);writeAudit 新增 rewrittenDirty/ignoredChanged/outsideRoot; 声明写范围越出根目录时执行前即拒绝(R3)。
  • 新增 readCredentialEnv(Windows 注册表 env 回退,30s 缓存,GRAPHFLOW_NO_REGISTRY_ENV=1 关闭); TypeSafe-JEV worker 默认用它读取 TYPESAFE_API_KEY。

Fixed — 上下文预览延迟与 HTTP 模式

  • graphflow-mcp --http 只能服务第一个请求:服务入口把同一个 SDK Server 交给每个无状态 HTTP transport,第二个请求起即 "Already connected to a transport"。现每个 transport 新建 Server (新增入口级回归测试,回退修复即失败)。
  • SQLite readSnapshot 每次都为全部节点 JSON.parse 元数据,一次预览调用约 8 次(每次≈90 ms
    • GC)。快照节点的元数据改为首次访问时解析(仍可枚举/序列化/赋值,各快照互不影响);对话节点 判定先看 id 前缀并跳过 File/Module/Symbol 代码节点。暖预览 1.0–1.3 s → 0.57–0.65 s,检索金标 149/149 不变。

Fixed — 测试写入真实用户目录

  • 安装器测试靠改 process.env.HOME/USERPROFILE/APPDATA 做沙箱;在 --pool=threads 下这份 env 只在线程内生效, os.homedir() 仍指向真实用户目录,于是写出了真实的 ~/.graphflow/workspace-build.json,并把多个宿主 (Claude Code、opencode、Gemini、Cursor、Windsurf、VS Code、Trae)的 graphflow 条目改成已删除临时目录里的 假 server.js;之后未沙箱的 dsh 测试又读到这个标记而失败。vitest.config.ts 固定 pool: "forks", tests/helpers/setup.ts 在 worker 线程中直接拒绝运行。
  • tests/workspace-build.test.ts 的 newWorkspace 在 return 之后才登记临时目录,清理从未执行(每次运行泄漏数十个目录)。
  • dsh 的两条 cordis.patch.yml 一致性测试读的是开发者真实的 workspace-build 偏好,开启后必然失败; buildGraphFlowDshInsertPatch 新增 home 选项,测试改传空的临时 home。
  • Efficiency Agent:createTaskWorkspace 在 worktree 里软链 node_modules,POSIX 上 node_modules/ 忽略规则 不匹配软链,git status 把它报成未跟踪文件,noChanges 拒答判定在 Linux/macOS 上恒失败(CI 唯一失败用例); workspaceChanges 排除 node_modules。

Fixed — MCP episode 往返与根套件负载抖动

  • graphflow_report_outcome 对同一 MCP server 刚由 graphflow_run 创建的 episode 报 "Episode not found": 运行时无法加载 better-sqlite3 时 episode 写入 JSON 回退存储,而任一 SQLite 宿主(源码 CLI/测试/扩展) 打开同一图会把 JSON 合并进 SQLite 并改名移走。现进程内保留近期 episode(上限 128),report 未命中时 恢复写回后重试;返回形状不变。
  • graphflow_run / graphflow_report_outcome 新增可选 rootDir(此前被忽略);CLI outcome report 新增 --root-dir。
  • graphflow_skill_insights 在空图上不再按进程 cwd 索引整个仓库,改为遵循配置的 workspaceRoot。
  • 从计划生成 workbench 改为一次批量 upsertGraph(此前每个 topic 全量重写 file 存储,N 步 = 2N+1 次)。
  • 跨进程/重启后 episode 仍丢失的存储层根因:SQLite 宿主合并后把 JSON 存储改名为 .merged-bak, 无 better-sqlite3 的 JSON 宿主随即读到空存储。GraphifyFileClient 在 JSON 缺失、存在同名 .sqlite 且有合并备份时,改从备份(首份 + .latest 及其 delta)重建视图,下一次写入即带回全部记忆; 无 SQLite 兄弟(用户主动删除)仍为空。
  • CLI graphflow run 实际把任务执行了两次(runTaskResult 之后又为 legacy 文本调用 runTask), 每次产生两个 episode、只有一个会被回报——这正是 governance pending-ratio 偏高的来源之一。现只执行一次, 并新增 --root-dir。
  • 自动捕获的会话日志此前写到 process.cwd()(测试会污染仓库 .graphflow/session-journal.jsonl); OrchestrateOptions.workspaceRoot 现由 runTaskResult 传入运行绑定的工作区。
  • MCP 集成测试改用临时小 fixture 工作区与 fnv 嵌入(不再每例加载 ONNX、索引全仓库),未调大任何超时; 新增 tests/mcp-episode-roundtrip.test.ts(含"存储被合并移走"场景与 CLI 路径)。

Fixed — 凭证解析:环境变量优先,过期明文不再遮蔽(DeepSeek 401 根因)

  • 实测根因:全局配置 providers.openai 指向 api.deepseek.com 且存了一个过期明文 key,两个 tier 都走 provider=openai;旧逻辑只在同名变量(OPENAI_API_KEY)已存在时才让 env 胜出,于是用户 导出的 DEEPSEEK_API_KEY 从未被采用,所有调用 401。
  • 新增 resolveProviderApiKey(src/config/provider-env.ts)统一取 key,顺序:端点厂商的真实环境变量 (进程 env → Windows 注册表)> 配置 ${NAME} 引用 > 通过占位符/空白检查的配置明文。 applyProviderEnvFromConfig、providerHasCredentials、llm-check 来源说明、TypeSafe worker 选 key、 benchmarks/run-real-ab.ts 全部改用此顺序;明文被遮蔽或被拒时 llm-check 的 detail 会写明原因。
  • 跨厂商防泄漏:某条目指向 deepseek 而 shell 里有真实 OPENAI_API_KEY 时,不再把 OpenAI 的 key 发给 deepseek。
  • 配置导出键的"自有"判定改为按值比对:被 shell/测试/注册表水合覆盖后即视为真实 env,不再被下一次配置导出覆盖。
  • benchmarks/run-real-ab.ts 基线臂用 grep 取上下文,Windows 无 grep 时 ENOENT 被当成"无匹配"吞掉, 基线实际零上下文(输入恒 ~40 token),对比失真;改用 git grep,非"无匹配"错误直接抛出。
  • benchmarks/run-real-ab.ts 长跑中断即前功尽弃(控制台 Ctrl+C 会连带杀掉 git grep,状态码 0xC000013A 被当成 致命错误):瞬时失败(超时/被信号杀/无状态码)重试一次,再失败只跳过该检索词;每完成一个任务追加写 graphflow-out/eff-bench/real-ab.checkpoint.jsonl,--resume 按模型与任务 id 恢复已完成任务并复验溯源。

Fixed — MCP 常驻进程内存/线程无限增长(实测 36GB、3000+ 线程)

  • createEmbeddingProviderFromConfig 每次调用都新建 transformers provider 并立即预热, 即每次 graphflow_context 加载两个新的 ONNX 会话(模型权重 + 原生线程池),从不释放。 本地 provider 现按 (dtype, 模型缓存目录, 解析根) 进程内共享;单次预览从 ~11s 降到 ~1.1s。
  • createGraphClient 的 liveClients 强引用持有每个客户端(含缓存约 17MB),运行时路径 几乎不 close,常驻进程线性涨内存。改为 WeakRef + FinalizationRegistry,测试 teardown 的 closeAllGraphClients 语义不变。
  • 宿主退出后 MCP 进程成为孤儿(实测同时残留 7 组 launcher + server):SDK 的 stdio 传输不处理 stdin EOF,文件监视器又让事件循环常驻。stdio 入口现在在 stdin end/close 时优雅退出, launcher 随子进程一起结束。

Security — Skill/Rules 源文件不再从 cwd 解析

resolveSkillSourcePath 等解析器把 process.cwd()/skills/graphflow 排在首位:在任何含 skills/graphflow/SKILL.md 的目录里运行 graphflow init(或扩展宿主 cwd 落在该目录),就会把 该目录的文件写进所有用户级 Agent 的 skills 目录——恶意仓库可借此投放提示注入。现只从本包 自身位置与 vendor 运行时解析;graphflow_skill_guide 读取同样不再看 cwd。

Fixed — 配置分层不一致

  • 项目层 graphflow.config.json / .graphflow/config.json 按服务的工作区(rootDir / GRAPHFLOW_WORKSPACE_ROOT)发现,不再按进程 cwd——同一项目在不同宿主下解析出不同配置。
  • 项目/覆盖层改为部分覆盖:只写要改的字段,其余继承全局;合并结果再校验。此前每层须是 完整配置,且完整层会把全局整体盖掉。损坏的项目层仍 fail-fast,损坏的覆盖层仍忽略。
  • mergeGraphFlowConfig 不再丢弃 workerPolicy / reconcilePolicy。

[2.0.3] — 2026-09-30

npm 上的 2.0.2 是一次取消竞争里意外落地的部分发布(不含下方 Windows pack 修复),由本版接管 latest。

Fixed — npm pack 在 Windows 上失败(prepare 钩子的 POSIX 写法)

Windows 实测:npm pack 报 "'husky' 不是内部或外部命令…'true' 不是内部或 外部命令"——prepare: "husky || true" 里 true 是 POSIX 命令,Windows cmd 没有;husky 缺失时(未装 devDependencies 的检出)回退链整体失败 → pack 中断、tarball 不生成。改为 node scripts/prepare-hook.cjs:best-effort 跑 husky(shell:true 解析 Windows 的 husky.cmd),任何情况退出 0——git 钩子 接线是开发便利,永远不该连累 install/pack。

Fixed — 只读诊断命令从 home 目录运行不再拒绝(Ubuntu 实测)

用户实测:graphflow llm-check 从 ~ 抛 "Refusing to index unsafe workspace root: /home/<user>"——诊断命令犯了 2.0.1 刚修过的同类错(llm-check 是 新命令,写时漏了逃生口)。

  • llm-check / diagnose(含 route diagnose)/ selfcheck 三个只读诊断 全部以 allowUnsafeWorkspace 解析:任何工作目录都能作答。
  • diagnose 的 workspaceRoot 诊断块升级为异常安全:解析被拒时把拒绝 本身作为发现上报(discovery: "refused" + 原因),不再抛出。
  • usage 帮助补 llm-check 条目。
  • 回归测试 tests/diagnostics-from-home.test.ts:假 home 下四个命令全部 作答(llm-check 报告在场、diagnose 报 refused 而非抛出、selfcheck 通过、 帮助含新条目)。
  • 另:Windows 报 "unknown command config" 的机器装的是 2.0.0 之前的版本 (usage 无 settings 命令可证),升级到本版即可。

Fixed — Jev 接入真实 API 契约 + graphflow llm-check 自诊断

用户实测"配了 DEEPSEEK_API_KEY / TYPESAFE_API_KEY 和 settings 仍无法访问",根因是类别错误:typesafe-jev worker 把 Jev 当 chat 模型,打向编造的域名 api.typesafe-jev.ai/v1/chat/completions,还让它编造命令 JSON——按 docs.typesafe.ai 官方契约,Jev 是 System One 判定模型(POST https://api.typesafe.ai/v1/systemone,Bearer,jev-latest,Choice/Score/Noul 类型化问答),不生成文本。

  • substrate 新增 src/routing/typesafe-systemone.ts:真实契约客户端(429/529 指数退避、401/422 硬失败、usage→measured)+ createJevMetaReflector——Layer B 灰区复用决策现在走真实 Jev choice(REUSE/ADAPT/FRESH)+score(置信度),失败一律回退 Layer A。已实测联通:HTTP 200、jev-1.13.0、noul 判定。
  • worker 重写:prepare 确定性(Jev 不编命令)、execute 本地 execFile、validate 走真实 noul 判定(可否决零退码;无 key/不可达 fail-open 为退码语义)。移除 DEEPSEEK_API_KEY 跨服务回退(两套服务两套 key,回退=必 401)。
  • 默认端点修正:workerPolicy 默认 https://api.typesafe.ai + jev-latest(原 localhost:8000 占位也是"开箱不通"的一环)。
  • 新增 graphflow llm-check(只读诊断):逐 provider 报告可用性、获胜凭证来源(config-key / env:变量名 / localhost / none,${VAR} 占位符如实标注 env 来源)、baseUrl/model、实际查过的环境变量名清单(拼错立即现形)、System One 端点状态。Windows"无法访问"从此可自诊。
  • 测试:tests/typesafe-systemone.test.ts(契约/退避/反思器/llm-check 9 例)+ worker 测试重写为真实语义(14 例)+ 真实臂记账对齐(判定调用数=typeSafeValid、token=usage)。全仓 254 文件 / 2073 测试绿。

Fixed — graphflow config ui 保存被 unsafe-root 断言拒绝(Windows 实测)

用户报告:设置页能打开但保存失败——"Refusing to use unsafe workspace root from projectWorkspaceRoot: C:\Users\roarp"。根因:从 home 目录启动时, 保存流程 resolve 一个不存在的显式 config,loadConfigSafe 给默认配置 绑上 cwd(home) 作为 workspaceRoot,随后被当 projectWorkspaceRoot 传入 运行时绑定断言 → 抛错。而保存全局设置根本不需要项目工作区。

  • resolveConfig 新增 allowUnsafeWorkspace 逃生口(settings 流程专用, 其他调用方不变——M49 的全局断言语义保持原样)。
  • getGraphFlowSettings / saveGraphFlowSettings 以该模式解析:从 home 读写全局设置不再抛错(已在真实环境复现验证:THREW → save ok)。
  • 保险丝:持久化前若发现不安全根(home/AppData),一律剥离——包括项目 scoped 配置(旧版本钉进去的坏值会在下次加载时复发成同样的抛错)。
  • 回归测试 tests/settings-unsafe-root-save.test.ts:home 下保存/读取 全局设置成功且永不持久化 workspaceRoot;预置的坏根在保存时被清除。

[2.0.0] — 2026-09-30

升级须知(2.0.0 迁移说明)

  • store 路径可能变化(重要):bindRuntimeWorkspaceRoot 修复后,项目 config(graphflow.config.json)里的 workspaceRoot 从此被正确尊重 (文档优先级第 3 级)。此前被 cwd 发现覆盖的部署,升级后实际生效的 graph store 路径会变——旧数据还在原位置,用 graphflow artifact 导入 或把 graphStorePath 指回旧文件即可。
  • 混合库召回隔离:dialogue/workbench 召回现在按工作区归属过滤。 依赖"跨项目串台"行为的(错误)用法会看到不同的召回结果。
  • 默认配置新增 workerPolicy(本地 JEV 端点占位)与凭证嗅探语义: 环境变量凭证只信真实 shell 来源;localhost 端点视为免密。
  • graphflow_run 响应新增 advisory block(Shadow、确定性、零 LLM 成本)——纯增量,不读取它的宿主不受影响。
  • 2.x 效率层以 monorepo workspace 包形式随仓库交付 (packages/efficiency-agent,暂不随 npm 包发布)。

Added — Step D 首份真实成本 A/B:Context ↓47%(门槛 ↓20%)

npm run benchmark:real(benchmarks/run-real-ab.ts):50 任务 × 双臂真实 deepseek-v4-flash 调用。token 数取自 provider usage(R2 measured),100 条 trace 全部通过 R6 provenance 门,总实验成本 ≈ $0.20。

  • 双臂语义(诚实反事实):baseline = 传统 grep 取上下文(top-3 文件 × 250 行);shadow = GraphFlow 压缩上下文包。同模型/同单轮/同 6000 字符 预算。首版"裸提示词基线"被否——它把效率层带上下文误读成 +2000% 输入。
  • 结果:输入 token 均值 1578 → 835(-47%,§23 门槛 ↓20% 的 2.35 倍); 总量 78,913 → 41,736。成功率 100/100(判据=非空回答,局限如实记录)。 输出 token 被 2048 生成上限支配(25-32/50 顶格),输出/费用对比本轮不作数。
  • 审计修正:eff-agent bench run CLI 实为合成模拟器(fabricated 时长与 循环编造的 reuseMode,含真实 advisory 永不给出的 REUSE)——本轮以真跑 数据替代;CLI 的真实化列入待办。
  • 详细数字与局限声明:benchmarks/REAL-AB-RESULTS.md。

Fixed — LLM 可用性嗅探的自反馈回路(bridge 降级保障回归)

新一轮凭证嗅探引入了一个反馈回路:applyProviderEnvFromConfig(既有行为)把 config 凭证写进 process.env,新的 providerHasCredentials 又去嗅探 env——前一个配置的凭证泄漏进后续所有配置的可用性判定。实测后果:同文件早先测试导出的一次性 sk-good key 让后面本应无 LLM 的 selfcheck 判为"可用"(llm-probe ok 而非 na),bridge-fallback-guarantee 9/12 失败。

  • provider-env.ts 新增 configExportedEnvKeys 记录:凡由配置导出的 env 键,可用性嗅探(genuineEnvValue/detectApiKeyFromEndpoint/分支 2/4)一律视为不存在;真实 shell 提供的环境变量不受影响(零配置开箱即用、TYPESAFE 映射保留)。
  • resolve.ts 的 env→config 回写(步骤 3/4/5)与 TYPESAFE 别名同样只信 genuine env——防止跨配置凭证被写进 config 对象本身(乃至被设置页持久化)。
  • bridge-fallback-guarantee.test.ts 补 GRAPHFLOW_CONFIG_HOME 家目录隔离(m49 既有机制):断言"彻底清空凭证"的测试不得读本机真实全局配置(本机有真实 deepseek key,不隔离必然假阴)。
  • 回归守卫:m-run-bridge-selfcheck 恢复绿(4/4)。

Added — §5 Contract 补全 + §21 策略闭环 + lint 清零

  • advisory 补 §5 四块:project(workspaceRoot + gitHead 尽力获取,按工作区根做进程内缓存——基准实测不缓存决策成本 0→65ms/任务,缓存后 4ms)、experience(相似 episode 指针 + topSimilarity)、tools(按能力派生,融合 edit 步的 command 即 validate 能力)、context.cached(context-cache 命中信号)。contract schema 与 assertAdvisoryCompatible 验收门同步扩展。
  • §21 策略闭环(读侧):graphflow-out/efficiency-policy.json 存在时,graphflow_run 的 advisory 以其覆盖 worker 档位/执行模式并盖章 policyApplied.version;账本记录补 taskCategory(triage 类目作学习分组键)。
  • §21 策略闭环(写侧):包内 policy-from-ledger.ts(账本→TrajectoryRecord→summarize→learnPolicy,映射的"决策形≠运行形"局限如实写入 docblock)+ eff-agent policy learn <ledger.jsonl> CLI 命令。闭环:生产决策入账本 → 学习出策略文件 → 下次 advisory 应用。
  • 测试:tests/advisory-policy-loop.test.ts(§5 字段契约纯净、策略覆盖+盖章、账本→学习闭环);新一轮 10 个 lint 错误清零(6 未用 import、settings-server 4 处 any→类型化)。
  • 终态:253 文件 / 2069 测试全绿;lint 干净;双 tsc + 包构建通过;基准 provenance 全净、ADAPT 7/50 稳定、决策成本 4ms。

Added — P2–P7 全量落地(5 agent 并行,独占文件域)+ similarity/outcome 拆分

效率决策层的六个阶段一次到位,全部在 packages/efficiency-agent(138 个新测试 + 5 个集成测试),共享类型契约 src/domain.ts。

  • P3 复用引擎(§7/§8):fingerprint.ts 四轨指纹(semantic/project/context/environment → reuseKey,轨间隔离:gitHead 变只动 projectStateHash);caches/ 三层缓存——Context(TTL)、Plan(命中前 projectStateHash 状态校验)、Result(仅 query/docs/config 类目可存可放,写类目 put 即拒绝);reuse-gate.ts 保守阶梯。缓存按语义任务哈希键控 + 全指纹校验,所有失效原因(ttl-expired / project-state-changed / fingerprint-mismatch / category-not-result-safe)真实可达。
  • P2 Execution Broker(§16):broker.ts 轮次/预算/停止条件三重约束的生命周期(worker 异常一律收敛为观测不抛出,stop() 恒在 finally 调用);第一个 worker = local-command-worker.ts(execFile 数组参数、超时 SIGTERM、AbortController 停止、输出尾 2000 字符)。外部 CLI worker(claude/codex)按同一 WorkerAdapter 接口后续接入。
  • P4 经验学习(§18):trajectory.ts 记录校验/按类目汇总;policy-learner.ts 带滞回的策略学习——成功率 <0.7 升一档(economy→standard→heavy)、≥0.9 且 ≥2×minSamples 才降档、avgRounds>1.5 转 loop、失败阶段占比 ≥30% 进 avoidPatterns;policy-store.ts 版本化 append-only(拒绝过期版本、单调回滚)。
  • P5 Project Twin + 工具智能(§9/§10):project-twin.ts 确定性派生(模块/入口/关键符号/构建/测试/约定,跨文件符号 ≥2 文件才入榜);capability-registry.ts success_history 驱动排序(胜率升、延迟/成本升序);tool-router.ts 按能力选工具(precision≥0.8 优先,无供给→no-capability 拒绝);schemas/tool-capability-v1.schema.json 补齐 Step B 第四个 schema。
  • P6 成本优化(§20):cost/model.ts 组件聚合(总额继承最弱 provenance,R5);cost/optimizer.ts 四道 floor 门(success/fidelity/safety/evidence)过滤后取最小成本,平局按成功率、id 字典序。
  • P7 自优化闭环(§21):reflection.ts 确定性反思规则(cache-win/cache-miss/over-budget/quality-floor-miss);loop.ts 决策→执行→反思→策略更新编排(学习器可注入)。
  • 集成证明:tests/integration-cycle.test.ts 用全真实模块走通 冷缓存 FRESH → 回放 REUSE → 状态漂移回落 → 本地 worker 真实执行 → 轨迹汇总 → 失败类目升档 → 优化器择优 → 闭环出策略更新。
  • similarity/outcome 拆分(上一轮基准发现的修复):orchestrator-episode.ts 的 similarEpisodes 同时携带 score(结局分)与 similarity(taskSimilarity() Jaccard);advisory decideReuseMode 以 similarity≥0.5 为主门,无 similarity 信号才回退旧 score 门。基准复跑:ADAPT 49/50 → 7/50——只有真正相似的重复族兄弟通过;contract schema signals 增加 topEpisodeSimilarity。
  • 测试:包内 7 个新文件 138 测试 + 集成 5 测试;全仓 242 文件 / 1956 测试绿;lint、root+包双 tsc、包 dist 构建全部通过。

Added — Step A/B:50 任务基准 + provenance 门比较(npm run benchmark:eff)

P0 计划的基准件落地。基准在第一天就产出了一条真发现(见末尾)。

  • 语料 packages/efficiency-agent/benchmarks/eff-tasks-v1.jsonl:50 个任务按 §24 组成(20 高重复 / 15 常规 / 10 复杂 / 5 故意失败);regular 队列文本衍生自本仓库真实 git 历史(source 带 commit);解析器 src/corpus.ts 强制组成校验,坏语料拒绝进基准。
  • Runner benchmarks/run-eff-bench.ts + 可测试核心 benchmarks/eff-bench-lib.ts(沿用 plugin-ab-lib 的 lib/CLI 拆分):run --mode=baseline|shadow [--limit N] 双臂离线跑(bridge 路径、无 key、临时沙箱),每任务一行 TaskTrace JSONL(默认 graphflow-out/eff-bench/);compare <a> <b> 先对每条 trace 过 validateTraceProvenance,任何违规整场拒绝(R6),干净才输出双臂统计。
  • trace 构建器 packages/efficiency-agent/src/bench.ts:provenance 在构造点决定——bridge 双臂 context tokens 诚实标 proxy(descriptor-chars/4, 0.6)(summary 尚不暴露真实 token 计数,合同必须让这个缺口可见);决策成本占比按 R3 标 estimated(decisionMs/totalRunMs)。开发中合同当场抓到一次自造违规(measured 值带 method),按 R3 改正——门是活的。
  • episode 闭合模拟:沙箱内每任务跑完按队列语义闭合(failure 队列记 fail)——similarEpisodes.score 是结局分(pass=1/pending=0/fail=-1),不闭合则 bridge episode 永远 pending=0,ADAPT 判定永远不触发,测的是一个真实项目不存在的库。
  • 全量实测(2026-09-30,本机):双臂各 50 任务、provenance 全净、每臂 ~23-28s;avgContextTokens=184、totalLlmCalls=0、avgRounds=1、shadow avgDecisionCostShare=0.0002(决策开销占打包耗时 0.02%)。
  • Shadow 第一条发现(如实记录,先不改语义):闭合 episode 后 49/50 判 ADAPT——similarEpisodes 的 score 是结局分而非相似度分,0.5 阈值的实际语义退化为"top-3 相似排名里存在任何 pass episode"。修正方向是让 summary 同时携带 similarity 与 outcome、advisory 对 similarity 设阈;留给 Step D 真实 A/B 前校准(这正是 P0"只观察"的目的)。
  • 测试:tests/eff-bench.test.ts(语料组成 20/15/10/5、坏语料拒绝、双臂 trace 全净且 shadow 臂 ADAPT≥4/FRESH≥1、compare 接受干净臂、拒脏数据)。

Fixed — 跨项目召回隔离(P0 gate):混库不再串台

实测缺陷:在 GraphFlow 仓库根上调 graphflow_context,回显的 workbench 是另一个项目(铜管 FOV 视觉)的工作台主线,dialogueHits 也混入外项目会话。根因两层:

  • loadActiveTopic 不验归属:无 taskHint 时直接取全库 updatedAt 最新的 workbench root——混库(legacy 共享 store / 显式 configPath)里最新 root 几乎必然是别人的。现在按 workbenchRootIdFor(task, 当前 root) === rootId 重算哈希验归属(与 diagnose 的 outline 过滤同一套"验证而非猜测"语义),不属于本工作区的 root 不再被当作活跃主题。不传 workspaceRoot 时保持旧行为。
  • searchDialogueTurns 无会话过滤:dialogue 召回按内容在全库 120 条窗口内匹配。现在接受 workspaceRoot,用存储的 session name + 当前 root 重算哈希得出本工作区会话集合(listOwnedDialogueSessionIds,历史数据也能精确归属),过滤发生在窗口截断之前——外项目再活跃也挤不掉本项目的轮次;无法验证归属的轮次一律不参与召回(隔离优先于召回)。
  • 顺带修了一个绑定错误:previewContext / dialogue 运行时包装器调 bindRuntimeWorkspaceRoot 时从没传项目级 workspaceRoot(文档优先级第 3 级形同虚设),root 一律落到 cwd 发现——项目 config 部署下归属集合按错误 root 计算,召回全灭;且同文件内 record/list 两个表面绑不同的根,互相看不见对方的会话。现在 previewContext + dialogue.ts 全部 8 处统一把 projectWorkspaceRoot 传进去。
  • 测试:新增 tests/cross-project-recall-isolation.test.ts(双 root 共享一个 store 的混库形态:scoped 召回互不泄漏、loadActiveTopic 不被更新的外项目 root 劫持、previewContext 端到端只回显本工作区内容)。

Added — 2.x 效率层地基:Shadow advisory + 决策成本账本 + 测量合同

二阶段计划(Efficiency Agent)的第一批落地:Contract 不另起炉灶,作为 graphflow_run executionDescriptor 的超集演进;决策自身成本必须入账。

  • src/core/efficiency-advisory.ts:纯 Layer A(零 LLM 调用)的 Shadow advisory 构建器。REUSE 门保守:有达标相似 episode(score ≥ 0.5)→ ADAPT,否则 FRESH,v0 里 REUSE 刻意不可达(result 复用等基准证明安全后再开);模型档位映射 simple→economy / complex→standard,确定性层永不升到 heavy;验证门从 fused steps 的 validate 动作推导。同输入除实测耗时外字节相同。
  • 接线:graphflow_run 响应新增 advisory block(routing.ts,失败隔离——advisory 永不拖垮 run);worker 可忽略(Shadow)。工具描述已更新。
  • src/learning/decision-ledger.ts:每次 advisory 产出向 graphflow-out/decision-ledger.jsonl 追加一行决策自身成本(duration 实测、llmCalls/tokenCost 对 deterministic 决策恒 0、provenance 标记)。GRAPHFLOW_DECISION_LEDGER=0 可关。Shadow 验收的"决策成本占比"从这里取数。
  • packages/efficiency-agent/(新 workspace 包,零运行时依赖):边界规则=只消费 MCP/公开输出、不读 GraphFlow 内部存储、主仓不反向依赖。含测量合同(measurement.ts:成本字段必须带 provenance,measured>estimated>proxy,聚合取最弱,R1–R6 由校验器强制)、TaskTrace v1(trace.ts + schemas/trace-v1.schema.json,validateTraceProvenance 是 A/B 比较准入门——回应"LLM Calls ↓20% 目前测不到":没有 provenance 的比较直接拒绝)、Execution Contract v1 规范类型与 assertAdvisoryCompatible 验收门(contract.ts + schema)。根 package.json 增加 "workspaces": ["packages/*"]。
  • 一致性守护:tests/advisory-contract-conformance.test.ts(substrate advisory 必须过包侧 contract 门,含 JSON over-the-wire 往返)、tests/shadow-advisory-e2e.test.ts(bridge run 端到端:advisory 下发 + contract 门通过 + ledger 落盘一行一记录)、tests/efficiency-advisory.test.ts(确定性/保守复用/档位映射/验证推导/ledger 读写与断行容忍)。

Fixed — 同一个查询的两次调用现在字节相同

graphflow_context 是给宿主当提示前缀用的:前导字节一旦变了,它后面所有 token 重新计价。实测此前同样的 query + 没变的仓库,两次调用产出不同字节,原因有三类,都已修:

  • 信封字段顺序:每次调用都会重算的记账字段原先插在内容字段中间。src/surfaces/cli/runtime/graph.ts:540 现在按"内容由 (query, store) 决定 → 在前"排序:query / summary / anchors / anchorBodies / tokenBudget(稳定字段) / refillPreview,把 anchorsByLayer、unbudgetedTokens、accountedTokens、degraded、对话/workbench 回显、economics、cacheLayout 全部排到尾。anchors 本身没有重排(只动信封顺序,不动锚点顺序)。
  • degraded 与 churn:response-budget.ts 原先把 degraded 塞在对象中部(改变的是键集合,不只是值);context-economics.ts 的 churn 是"和本进程上一次发的内容"的差,第一次调用和之后每次天然不同——两者现在都落在最后。
  • 对话时钟:dialogue-thread.ts 在 30 分钟去重窗口内命中时原先无条件写 updatedAt = Date.now(),于是回显里的 updatedAt 每次都变。现在拆出 lastSeenAt 作为去重时钟,updatedAt 只在文本/摘要/关联节点真的变化时前进;旧记录没有 lastSeenAt 时回退到 updatedAt,升级不会把历史轮次全部重开。回显视图 DialogueHitPreview 不再携带 updatedAt(全仓无消费者;值仍留在图和 DialogueSearchHit 上,走 store 读取的调用方不受影响)。
  • 平局打破:graph-search.ts 对话检索、detectSupersession、vectorRecall、打包内对话行、snapshot-view.ts 边排序、sqlite-client.ts 的 FTS 查询(ORDER BY rank, n.id)都补了确定性的次键;V8 排序稳定,同分时以前继承 SQLite/FTS 行序。
  • 量到的效果:本仓库同一 query 连续两次 previewContext(recordDialogue:false),整段 JSON 逐字节相同(不只是稳定头)。
  • 被否掉的两处(有实测支撑,不是偷懒):给 graph-compression.ts 的 ranked.sort(score) 加 id 次键,golden 召回从 132/132 掉到 90/132、负样本泄漏——那里的"平局"其实是 BFS 发现序(种子与近邻优先),按 id 重排会让字母序靠前的节点顶掉真正的种子;同样理由撤掉了对 importHits / expanded / 快照扫描的 id 预排。结论:确定性不能靠给有语义的排序强行加字母序,这些位置要做到可重复需要有意义的质量次键,目前如实留着未解。
  • 仍未决定:planCacheLayout 是否真的参与 summary/anchors 排序、cache-layout / context-economics 默认是否打开——本轮只做了机械的字节稳定部分,策略留给作者(宿主是否把这个块提到 system 层,决定了这笔收益有多大)。
  • 测试:新增 tests/context-prefix-stability.test.ts(3 例:两次调用头相同且变动字段落在尾、economics.churn 每轮变化时头仍相同、同分锚点按 id 确定),tests/dialogue-thread.test.ts 增加"纯重复提问只走去重时钟"一例,m107 的回显断言改为显式要求视图里没有 updatedAt(而不是放宽)。

Added — outcome 机械闭合:graphflow reconcile outcomes

飞轮的输入缺口是结构性的:pass 只能来自 agent 自愿调用 graphflow_report_outcome 的自报布尔值。本仓库实测 191 个 episode 里 9 pass / 1 fail / 73 pending / 108 human_review,0 个带 evidence、0 个带 deviation、187 个 plan 为空。新增一条不依赖配合的闭合路径。

  • src/learning/outcome-reconciler.ts:pending / human_review 的 episode,取任务文本与计划步骤里磁盘上真实存在的路径 → 在该 episode 时间窗内查 git log --name-only(只读命令)→ 整个 reconcile 跑一次声明的 verify 命令,用退出码定成败。写回走现有 reportOutcome,因此技能学习与审计链的行为和自报完全一致。
  • 保守是有条件的:pass 需要"verify 退出 0"且"窗口内有 commit 碰到 episode 点名的文件"。没配 reconcilePolicy.verifyCommand、或命令失败、或没有这样的 commit —— 一律不写,并把原因计入 no-verify-command / verify-failed / no-named-files / no-commit-in-window / no-git-history。一条 commit 只代表交付过,不代表改对,所以绝不凭它写 pass。
  • 出处如实:写入的证据带 source: "reconcile"(EvidenceSource 联合新增该值)且 userConfirmed: false,不会伪装成用户确认。默认 dry-run,要落盘必须显式 --apply。
  • graphflow selfcheck 新增 reconcile 行(只读,不跑 git、不跑命令)。本仓库实跑:158 pending (0 name files), verifyCommand unset —— 也就是说机制虽然通了,当前仓库的 episode 任务文本里没有任何存在的文件路径,闭合还差"捕获时记下改过哪些文件"这一步;报告里 passesWithoutLessons 也明说:pass 无 lesson 只关闭 episode,不产生技能学习(shouldApplySkillLearningFromOutcome 的既有门)。
  • 修 scripts/backfill-episodes.cjs 两处硬伤:回填出的 episode 原先一律 outcome:"pass"(每条 commit 都算成功,正是上面禁止的凭空判胜),现在改 pending;且当旁边存在 graphflow-graph.sqlite 时拒绝写 JSON 存储并给出指引(这正是 1.28.0 费力合并回来的分叉)。实测该脚本从未跑过(无 source: backfill:* 的 episode)。
  • 新增 tests/outcome-reconciler.test.ts(9 例,含真 git 仓库):无 verify 命令不写、命令失败不写、绿+命中文件才 pass、出处与 userConfirmed:false、无命中的 commit 不写、dry-run 不写、无 lesson 的 pass 被标记。
  • 顺带修一个真 bug:loadAllEpisodes 走 client.queryByKeyword,而 SQLite 的关键字查询是 LIMIT 200(sqlite-client.ts:280,290)——名字叫 "All",实际第 201 条起静默消失,影响 memory list、飞轮报告与 outcome 回填。现在优先读整快照,读不到快照才退回关键字查询。tests/outcome-reconciler.test.ts 用 201 条 episode 钉住这条。

Fixed — 测试把 179 条 force a failure episode 写进了本仓库的真实存储

tests/m17-release-readiness.test.ts 用 transport: "mcp-http" + 死端点做"provider 不可用→桥接委托"的回归,但配置里没有 workspaceRoot:客户端工厂退回默认存储,而默认存储按当前工作目录解析到这个仓库的 graphflow-out/graphflow-graph.sqlite。于是每次跑测试都往里追加 episode,累积 179 条同名噪声——selfcheck 那个"pending ratio 95%"很大程度是这个假象。两处配置都钉到临时目录;跑完整个测试套(228 文件 / 1770 测试全绿)后 episode 数从 191 到 191,不再增长。存量脏数据需要显式清理(graphflow learn forget 是全清,不是筛选),所以留给作者决定。

Added — 锚点带正文:bodyCoverage 从 1% 抬起来

自家保真度实测:averageAnchorRecallPercent 92 而 averageBodyCoveragePercent 1——包能点名正确的符号,却几乎不覆盖它的正文,于是 agent 还得再发一次 expand 或整读文件,首包省下的又被后续轮次吃回去。

  • 符号节点记录声明范围:DeclaredSymbol.endLine(TS 走编译器 API 的 sourceNode.getEnd()),file-indexer-nodes.ts 写进 metadata.endLine。需要重索引才拿得到;没有 endLine 的旧节点一律不附正文(计入 noExtent),不会拿旧行号猜一个窗口。
  • metadata.signature 现在只在解析器真给出签名时写。原先它存的是 kind name @file:line 这种显示串,任何"拿磁盘文本对一对"的核验都会把它当签名,从而误判。
  • 打包新增正文阶段(src/graph/anchor-bodies.ts):前 3 个 L1 符号锚点各附 ≤120 token 的声明正文,整包正文 ≤20% 预算(上限按"含正在附加的这条"判定,否则最后一条会超额一档:实测曾出现 300 上限装到 344),并且只花锚点阶段剩下的预算——锚点永不被正文挤掉,对话仍保持它原有的"所有代码锚点之后"的纯增量位。enableSymbolBodies: false 可关。
  • 不可信就不给:磁盘上的声明头与存储签名不符 → 不附(unverified);预算不足 → noBudget。graphflow_context / context preview 的返回新增 anchorBodies: { attached, tokens, noExtent, unverified, noBudget },成本与缺口都可见。
  • expandAnchor 现在返回 verified: "exact" | "relocated" | "drifted":符号在上次索引后被人插了行,就按磁盘实际位置给窗口并报 relocated;签名已不在文件里则报 drifted 且不假装是正确代码。endLine 只细化默认窗口,GRAPHFLOW_EXPAND_SYMBOL_AFTER 仍是硬上限(tests/m50-expand-anchor.test.ts 的既有契约不变)。
  • 代价如实记:正文是真源码,每包最多约 360 token,节省率会按已记账口径下移;m109 的 raw 基线门改为把正文档位计入,而不是假装它免费。检索侧无回退:bench:retrieval Hit@5 99.2% / MRR 0.748 / NDCG@5 0.619,与不附正文时一致。
  • 新增 tests/anchor-bodies.test.ts(7 例:范围与签名入库、附正文、漂移时不附、正文不挤锚点 + 开关、expand 的 exact/relocated/drifted 三态)。
  • 另按 benchmarks/flywheel-proof-claims.json 的 disclaimer 纠正一次误操作:52330de 把跑过评测的 benchmarks/RETRIEVAL-EVAL-RESULTS.md 一起提交了,而该 catalog 把这个文件当"冻结对照目标",导致 flywheel-proof 的声明门失败;已按 cdfdb6e 恢复。要重新基线请显式改 catalog。

Fixed — 语义召回臂其实从未接上,.hnsw 派生副本零命中

本机实测本仓库(1.28.1):8811 个节点里 0 个带向量;graphflow-out/vectors.hnsw 里只有 1 个向量;graphflow-out/vectors.db 从来没有写入者,却出现在配置默认值、README、threat-model 和 audit --privacy 的产物清单里。

  • 索引拿不到 provider:buildIndexOptions 的返回类型里就没有 embeddingProvider,于是索引期的 embedAndAttachNodes 和索引后的重算都不会跑——向量臂恒空,只有 episode 参与。已接入(src/surfaces/cli/runtime/graph.ts)。
  • 重算只"换模型",从不补第一份:旧 refreshStaleEmbeddings 的判定是 if (!emb) return false,新库因此永远停在 0 向量。改名 ensureEmbeddings,缺失与过期共用一份预算、过期优先。
  • 每轮有预算:单次索引 256 个向量 / 2 秒上限(DEFAULT_EMBEDDING_RUN_LIMIT、DEFAULT_EMBEDDING_RUN_DEADLINE_MS),graph index . 实测 5.9 秒、无延迟回归;learn nightly 用 1024 / 30 秒继续收敛(大库分几轮跑完)。graph index --json 新增 vectorBackfill: { missing, stale, refreshed, fingerprint, budget },diagnose 的 embeddingQuality.vectorBackfill 同步。后端退回哈希时只补缺、绝不覆盖语义向量。
  • episode 绕开了量化存储:recordEpisode 直接写 float32 metadata.embedding,既不吃 1.28.0 的 int8,也不带模型指纹——本仓库 186 个 episode 全是这种 384 维哈希向量,换成语义模型后被 filterCompatibleEmbeddingNodes 整批滤掉。改走 attachEmbedding,无指纹的旧向量按"过期"迁移。实测:int8 向量 0 → 1692,遗留 float32 186 → 0,存储 24MB → 28MB。
  • 删除零命中的 .hnsw 持久化:那是节点 metadata 里同一批向量反量化后的 float32 副本(每维 4 字节,比源大 4 倍),而它的指纹按当前查询的候选集算(默认 enableFullGraphVectorRecall: false,候选集就是关键词命中)——换个查询就作废,等于每次召回写盘、几乎永不回读。向量的权威只留 metadata.embeddingQ 一份;已落盘的 vectors.hnsw 从此无人读写,可直接删。
  • 随之移除:embeddingPolicy.vectorStorePath(存量配置里的该键被静默忽略)、OrchestrateOptions.hnswIndexPath、全图重建时对 .graphflow-cache/vectors.db 的空删;src/learning/hnsw-index.ts → vector-index.ts,HnswVectorIndex → LinearVectorIndex,删掉空壳 save() / loadIndex() / forceLinear / linearThreshold(hnswlib-node 早在 P1 就移除了,backend 一直如实返回 "linear")。
  • 文档与审计面同步:README 配置表去掉 vectorStorePath、模块树注释去掉 hnsw;docs/threat-model.md 落盘清单去掉 vectors.db / .hnsw;audit --privacy 不再列一个永不存在的产物;docs/comparison.md 的 "RRF / HNSW" 改为"精确余弦 + RRF"。
  • 测试:tests/hnsw-persistence.test.ts → tests/vector-index.test.ts(memo 命中、候选集变化重建、维度不符跳过,外加"不再写盘"守卫);m128 补"给从没向量的节点补第一份"用例,并把哈希后端不降级的断言改成 stale=1 / refreshed=0;golden 集里 "hnsw approximate nearest neighbor index" 改为 "brute force cosine scan over node vectors"(expectAny: ["vector-index"]),同步 benchmarks/retrieval-golden-data.ts 与导出数据集。
  • 指标如实记账:语义臂刚接通(每轮只有几百个向量),检索质量暂时持平——同一提交用只读 worktree 对照跑 bench:retrieval:Hit@1 57.6% → 56.8%、Hit@3 92.4% → 92.4%、Hit@5 99.2% → 99.2%、MRR 0.752 → 0.748、NDCG@5 0.620 → 0.619;retrieval-golden 的排名漂移门(±2 位、≤12 条)在未刷新基线的情况下通过(132/132 命中)。索引延迟量级不变:本仓库 graph index .(623 文件)5.9 秒。收益要等存储收敛(enableFullGraphVectorRecall + 全量向量)才会显形。

Fixed — 过渡期 SQLite 漏掉旧宿主索引过的文件(1.28.1)

1.28.0 发布后本机实测:Cursor 里仍在跑的 1.27 运行时(JSON 存储)把新文件索引进 JSON,并写入共用的 .graphflow-cache/index-state.json;合并又跳过代码节点,于是 SQLite 把这些文件当成"未改动",永远不会索引(本仓库新增的 store-migration.ts 等在 SQLite 里查不到)。

  • 每个存储用自己的索引清单:SQLite 用 index-state.sqlite.json(GraphClient.indexManifestName,经包装层透传),JSON / 内存存储仍用 index-state.json。hasPendingGraphIndexWork / hasIndexCache / diagnose / selfcheck / metrics 按当前存储选清单(resolveIndexManifestName)。
  • 合并不再清空索引清单(1.28.0 会清掉旧宿主的清单,逼它全量重解析)。
  • 清单为空时(首次或刚从共用清单切过来),顺带删除磁盘上已不存在的文件节点,清理分叉期间漏删的残留。
  • 升级后 SQLite 首次索引会全量解析一次(本仓库 623 个文件约 3 秒),之后恢复增量。

Fixed — 同一项目换 Agent 工具后图谱与记忆分叉成两份

设计上所有宿主按项目共享一份图谱,但实测分成了两份:VS Code/Cursor 扩展与共享 MCP 运行时(~/.graphflow/runtime,Cursor / Cline / ZCode 都连它)没有打包 better-sqlite3 和 @huggingface/transformers,于是悄悄退回 JSON 存储 + 哈希向量;npm 包(DSH、CLI)用的是 SQLite + bge。本仓库实测:JSON 里有 167 个 episode,SQLite 里只有 12 个;两边还共用同一份增量索引清单,一边索引过的文件在另一边被当成"未改动"。

  • 运行时依赖按需安装(新增 src/integrations/ensure-runtime-deps.ts、src/utils/optional-deps.ts):装到 ~/.graphflow/optional-deps;better-sqlite3 按运行时分目录(sqlite-node-abi127 / sqlite-electron-abi…,扩展宿主是 Electron、MCP 是 node),transformers 是 N-API 共用。触发点:MCP 启动 15 秒后后台检查、扩展激活、graphflow install;手动 graphflow deps status / graphflow deps install [--force] [--with-model]。文件锁防并发,失败 24 小时内后台不重试;GRAPHFLOW_OPTIONAL_DEPS_AUTO=0、CI、vitest 下不自动装;扩展设置 graphflow.downloadRuntimeDeps。安装 transformers 时设 ONNXRUNTIME_NODE_INSTALL=skip(否则 linux-x64 上 onnxruntime-node 的 postinstall 去 NuGet 下 CUDA 库,网络不通就整个安装失败;推理用包内自带的 CPU 版);安装前把以 --no-save 装的 anydoc 登记进 package.json,否则 npm 会把它当多余包删掉。
  • JSON 存储自动并入 SQLite(新增 src/graph/store-migration.ts):SQLite 打开时若旁边有同名 .json,把记忆节点并入——代码节点(File / Symbol / Module)跳过,由磁盘重新索引,避免复活已删文件的符号;同 id 取 updatedAt 较新者;对话轮 id dialogue:<session>:<seq> 冲突(两个宿主在同一 session 里各自往下记)时顺延编号、改写 parentTurnId 并修正 session 的 turnCount / tipTurnId;两端缺失的边丢弃。JSON 与 delta 改名为 *.merged-bak(首份永久保留,之后只轮换一份 .merged-bak.latest),统计写入 *.sqlite.merge-log.json。单事务写入(GraphifySqliteClient.upsertGraphSync);失败则保留 JSON,下次打开重试。本仓库实测:并入 244 个记忆节点、797 条边,SQLite 里 episode 从 12 个变为 180 个。
  • graph index --full 不再清掉记忆(新增 src/graph/memory-subgraph.ts):重建前取出所有非代码节点及相连的边,关闭旧客户端(连同删除 -wal / -shm)后清库重建,再写回;指向已删代码节点的边丢弃。结果带 preservedMemory。
  • diagnose 新增 graphStore 段:transport、实际后端、sqliteModuleSource(bundled / optional-deps)、退回 JSON 的原因、是否存在未合并的 JSON、上次合并统计、各运行时依赖的来源与加载错误。

Changed — 默认用量化向量模型,向量带模型指纹

  • 本地模型默认 Xenova/bge-base-zh-v1.5 的 q8 版(onnx/model_quantized.onnx,约 98MB;fp32 约 400MB,经 hf-mirror 实测 400 秒下载超时、静默退回哈希)。embeddingPolicy.dtype / GRAPHFLOW_EMBEDDING_DTYPE(优先)可选 fp32 / fp16 / q8 / q4。模型缓存默认放 ~/.graphflow/models,所有宿主共用;原先缓存在 transformers 包目录里,每份打包副本各下一遍,npm 升级还会删掉。
  • 每个向量在 embeddingQ.model 记录模型指纹(Xenova/bge-base-zh-v1.5@q8、fnv1a-384、openai:<model>)。向量召回只比较维度相同、指纹相同的向量(旧的无指纹向量视为兼容),跳过数计入 embeddingQuality.incompatibleVectorsSkipped;此前 768 维 bge 与 384 维哈希向量混在一起时,余弦相似度直接得 0。
  • 索引结束后按批(每次最多 256 个)用当前模型重算指纹不符的旧向量(新增 src/learning/embedding-refresh.ts);当前后端是哈希时不动,模型临时加载失败不会把语义向量降级。进度见 embeddingQuality.staleVectors。
  • graphflow deps install --with-model 预下载模型并按 10% 打印进度。

实测(5 篇代码片段、8 个中英文查询):哈希向量 Hit@1 2/8、MRR 0.504;bge q8 Hit@1 6/8、MRR 0.875,加载加 8 次查询 0.8 秒。共享运行时副本上 deps install --with-model 装好两个依赖并下载模型;随后该运行时改用 SQLite(sqliteModuleSource: optional-deps),并合并了 Cursor 旧运行时新写出的 JSON。

Fixed — 「知识节点」面板在 Cordis 4 宿主上从未注册成功(cannot get property "connection" without inject)

1.27.12 真机启动日志:[graphflow-dsh] /gf RPC: registerNodesRpcChannel threw: cannot get property "connection" without inject。#26 在 1.14.1 的"修复"与 1.27.11 的复核都只对照了源码、用宽松的假 ctx 测试,从未在真实 Cordis 下跑过——这次用 DSH 自带的 @deepseek-ai/cordis 4.0.4 与真实 HostConnectionService 复现后,发现两层问题:

  1. 读未声明的服务直接抛错。 Cordis 4 的 ctx 代理对 fiber 未 inject 的任何属性(ctx.connection、ctx.rpc、ctx.effect)都抛 cannot get property … without inject。glue 在走到 ctx.inject 之前先同步读了 ctx.connection,整个注册中断。修法:Cordis 宿主上只在 ctx.inject(["connection"]) 的 fork 里注册;所有鸭子类型读取都经 readProperty 保护;优先用属性访问取服务(Cordis 会把服务绑定到读取它的 fork)。
  2. connection.rpc.handle 对第三方插件在 DSH 上不可用。 它经 owner.webServer.register 挂路由,而 service 内部的 this.ctx 带 shadow,服务解析走的是 Connection 插件自己的 fiber;DSH 挂载该行时只注入 credentials + webRuntime,于是无论调用方怎么声明 inject(静态 / ctx.inject / 对象形式,四种写法实测全部失败)都报 cannot get property "webServer" without inject。DSH 自身也没有任何代码调用 rpc.handle。修法:改用 connection.fetch.register 注册精确 Fetch 路由 POST /api/gf/nodes(只用 owner.effect,挂在 Connection 自己的 /api 路由下,鉴权/Origin 围栏与 /api 相同),应答与 unary RPC 相同的 server-response 信封;宿主没有 Fetch 注册表时回退 rpc.handle("/gf")。前端改为 rpc.call("/api", "gf/nodes"),404 时回退 /gf。

验证:真实 Cordis 4.0.4 + 真实 HostConnectionService + connection 自己的 /api 共享 Fetch 处理器,请求 POST /api/gf/nodes → HTTP 200、server-response、返回本仓库 24 个 workbench 主题与 50 条对话;同一脚本对 1.27.12 精确复现线上报错并得到 404。新增用例:严格 Cordis 代理(读未声明属性即抛错)下不读未声明服务、从 inject fork 注册;Fetch 路由的信封(非 JSON → 400、坏信封 → bad-request、缺 workspace → no-workspace);前端 404 回退。

Fixed — DSH 每轮报 Cannot read properties of undefined (reading 'kind')

真机(DSH 0.1.7-rc.2,dsh web)复测时,首轮报 #55 的 format v4 message requires a producer-owned source kind(profile 里仍锁着 1.18.5),随后每一轮都报 Cannot read properties of undefined (reading 'kind')。

根因在 glue 的 agent/pre-step 监听器:await next() 被 try { … } catch { return undefined; } 包住。dsh-agent-loop 的 preStep() 在 waterfall 之后立刻读 decision.kind,于是上游任何失败(中止信号、其他插件抛错、上一轮遗留的准入失败)都被改写成 undefined 决策,报一个与真实原因无关的 TypeError。DSH 自带监听器(dsh-time-context、dsh-plan-mode 等)都是直接 await next()、让错误原样上抛。

  • 监听器改为 const decision = await next(),不再吞掉上游错误;只有 GraphFlow 自己追加 hint 的那一步仍然容错(失败时原样返回上游决策)。
  • 新增用例:上游 next() 抛出的错误原样传播,而不是返回 undefined。

Fixed — DSH 会话格式 v4:首轮 hint 用了已退役的 kind: "plugin",整轮失败(#55)

dsh/plugin.mjs 的 buildHintMessage() 给注入的首轮 hint 打的是 v3 的 source.kind: "plugin"。DSH 会话格式 v4 的原生准入(dsh-session-format-v3-to-v4 的 source(message))对 "plugin" 硬拒绝:format v4 message requires a producer-owned source kind,报在落盘阶段,所以是整轮失败而不是丢一条消息。

  • hint 改用 v4 第三方生产者形式 plugin:graphflow-dsh(与官方迁移模块 producerKind() 对第三方插件的映射一致)。
  • isUserOriginatedMessage() 同步识别 plugin:* 前缀,以及 v4 的一方生产者 kind(runtime-context / system-prompt / compact-checkpoint / time-context / plan-mode / tool-jobs / user-approval / cordis-host-runner 等,取自官方 RENAMED_PRODUCERS 与 RELEASED_SAME_NAME_PRODUCERS)。否则这些 role: "user" 的宿主注入会走兜底分支、被当成真人提问记进对话图。webhook 有意不列入:它可能转发外部渠道的真人消息。
  • 新增用例:hint 通过 v4 准入规则;v4 生产者 kind 与 plugin:* 均不被记录为用户消息。

Fixed — dsh web 半边注入了已被取代的 @deepseek-ai/dsh-client-runtime(#54)

package.json 的 dsh.client.inject 仍列着 2026-08 起不再发布的 dsh-client-runtime。当前 harness 的 client-modules 用 inject 决定 web 半边的加载顺序(找不到的包直接跳过),所以我们声明的服务依赖根本没有被排序保证。

  • inject 改为 dsh/client.js 实际使用的三个服务的提供者(逐包核对 0.2.0-rc.2 源码):sessions ← @deepseek-ai/dsh-api-session-controller,connection ← @deepseek-ai/dsh-client-connection,slots ← @deepseek-ai/dsh-client-ui-renderer。
  • 新增用例:inject 不含 dsh-client-runtime,且包含上述三个提供者。

Verified — 「知识节点」面板 POST /gf/nodes 405(#26)

服务端部分已在 1.14.1(PR #34)修复:/gf 通道在 connection 未就绪时经 ctx.inject(["connection"]) 等待注册,失败写日志不再静默。本次对照 dsh-client-connection 0.2.0-rc.2 复核:rpc.handle(channel, handler) 仍以 prefix 路由挂到 webServer,handler 签名 (endpoint, payload, signal)、前端 rpc.call(channel, endpoint, payload) 均兼容。web 半边的注入目标问题由 #54 一并修复。

Fixed — 项目规则的源文件解析差了一级 ..,发布包里永远"找不到源文件"

用户 Ubuntu / Windows 的安装日志里有一整片"静默失败":

  • [SKIP] Trae Skill Trae: Skill source (SKILL.md) not found
  • [SKIP] Cursor Rules Cursor: Cursor rules source (graphflow.mdc) not found
  • [SKIP] Project rules Trae CN / Cursor / Antigravity / Copilot: Source file not found

源文件明明在发布包里(dist/surfaces/...、skills/graphflow 一项不少)。问题在 5 个解析函数:从 dist/integrations/ 出发,它们用 join(__dirname, "..", "..", "surfaces", ...) 去找源文件——两级 .. 落到的是不存在的 <pkg>/surfaces/,正确位置是上一级的 dist/surfaces/。唯一能命中的候选是 process.cwd() 那几条,也就是说:只有 CWD 恰好是仓库检出目录时才找得到。用户在自己项目里跑,永远 not found;我之前在仓库里测,永远成功——尺子一直量的是错误的东西。

修法:5 处各减一级 ..(surfaces 用 join(__dirname, "..", ...),skills 用两级到包根)。同一表达式同时覆盖构建布局(dist/integrations→dist/surfaces)与源码布局(src/integrations→src/surfaces)。CLAUDE.md 那处本来就是对的(包根真有 CLAUDE.md),没动。

本机实测(普通项目目录,非仓库):copilot / cursor / trae / skill 四个解析器全部命中包内路径;install 一次写出 10 个项目文件(.trae/rules、.trae/skills、.cursor/rules、.agent/rules+skills、.github/copilot-instructions.md、.claude/rules、.windsurfrules、AGENTS.md),此前这些全是 SKIP。

tests/vendored-source-resolution.test.ts(4 用例):把 CWD 切到临时空目录再解析——不靠 CWD 运气。已验证有牙:改回一处旧路径 → 1 个失败。

Fixed — home 目录守卫的测试只在 Linux 上成立,Windows 上 3 个用例失败

1.27.9 的 CI 在 windows-latest 上红了,3 个用例失败。生产代码是对的,错的是我的测试。

os.homedir() 在 Linux 上读 HOME、在 Windows 上读 USERPROFILE。我用 process.env.HOME = <临时目录> 来假扮 home——这在 Linux 上成立,在 Windows 上完全无效,于是沙箱从来不是 home,守卫正确地没有触发,测试却断言它应该触发。

这类错误值得单列,因为它和「平台差异让测试全绿不等于行为正确」是同一个坑,只是方向相反:上一版是代码有 bug 而 Linux 测不出来,这一版是测试的前提不成立而 Linux 测不出来。两次都是"本地量的是错的东西"。

  • 沙箱现在同时设置 HOME 与 USERPROFILE,并逐个平台断言前提成立(homedir() === sandbox 且 isUnsafeWorkspaceFallback(sandbox) === true)——前提不成立时会直接说前提没成立,而不是让三个下游断言带着误导性的信息失败。
  • 两个"真实项目目录照常写入"的用例补上 isUnsafeWorkspaceFallback(project) === false,坐实守卫看的是 root 本身,不是"某个 home 存在"。
  • 7 个用例(+1 前提用例),两个守卫仍分别验证有牙。

这一版的教训:跨平台测试里,"构造前置条件"本身就是要测的东西。凡是用环境变量伪造平台行为的测试,先断言伪造生效,再断言行为。

[1.28.1] - 2026-09-29

每个存储改用自己的增量索引清单(SQLite 用 index-state.sqlite.json):过渡期里仍在 JSON 存储上的旧宿主索引过的文件,不再被 SQLite 当成"未改动"而漏掉;合并也不再清空旧宿主的清单。

[1.28.0] - 2026-09-29

同一项目换 Agent 工具(Cursor / ZCode / Cline / DSH)后图谱与记忆不再分成两份:共享运行时按需安装 better-sqlite3 与 transformers,旧 JSON 存储里的记忆自动并入 SQLite,graph index --full 保留记忆。默认改用 q8 量化的 bge 模型(约 98MB),缓存由所有宿主共用;向量带模型指纹,换模型后逐批重算。

[1.27.13] - 2026-09-29

修复 DSH「知识节点」面板在 Cordis 4 宿主上从未注册成功:改用 connection.fetch.register(POST /api/gf/nodes),并且只在 ctx.inject(["connection"]) 的 fork 里读取服务。已在真实 Cordis 4.0.4 + 真实 HostConnectionService 下端到端验证。

[1.27.12] - 2026-09-29

修复 DSH 中每轮报 Cannot read properties of undefined (reading 'kind'):glue 的 agent/pre-step 监听器不再吞掉上游错误并返回 undefined 决策。

[1.27.11] - 2026-09-29

修复 DeepSeek Harness 插件三处问题:会话格式 v4 下首轮 hint 使整轮失败(#55)、web 半边注入已被取代的 dsh-client-runtime(#54),并复核「知识节点」面板 /gf 通道(#26)。

[1.27.10] - 2026-09-29

修复 home 目录守卫测试只在 Linux 成立的问题(Windows CI 3 个用例失败),并为跨平台前提增加显式断言。

[1.27.9] - 2026-09-29

修复项目规则源文件解析差一级目录:Trae / Cursor / Antigravity / Copilot 的项目规则与 Skill 在发布包里永远报 Source file not found(Ubuntu / Windows 日志均有)。

[1.27.8] - 2026-09-29

修复从 home 目录运行 install 会把项目文件写进 home 并覆盖带标记的指令文件(Ubuntu / Windows 均复现)。

[1.27.7] - 2026-09-29

自检脚本修 Windows 上「MCP 检查被静默跳过」;文档补 Windows EBUSY 与镜像延迟的处理。

[1.27.6] - 2026-09-29

新增 scripts/cross-platform-check.mjs:Ubuntu / Windows 同一套命令的自检脚本,含中文编码往返检测。

[1.27.5] - 2026-09-29

测试文档再修:summary 不在最后一行;取该行必须用 spawnSync 而非 execSync(doctor 在 ok=false 时非零退出)。

[1.27.4] - 2026-09-29

修正测试文档的 Windows 不可用命令(grep 等),改用跨平台的 Node 单行脚本。

[1.27.3] - 2026-09-29

修复 CLI 帮助文本混入 stdout 破坏脚本消费;清理仓库内测试产物。

[1.27.2] - 2026-09-29

修复多词查询召回归零:FTS 把英文 token 用 AND 串联,任何两词以上查询都要求单节点全命中。

[1.27.1] - 2026-09-29

修复用户实测报出的两个安装级缺陷:onnxruntime-node 安装失败中断整包安装(非 Windows 上 appData 解析为空字符串,宿主配置被写进用户仓库)。详见下方条目。

[1.27.0] - 2026-09-29

上下文经济引擎(新鲜度预言机 / 前缀 churn 计价 / 能力地板 / Prefix Cache Planner / Project Brief)全量落地,npm audit 清零,工作区构建偏好覆盖全部 19 个宿主 + dsh。本段汇总,其后各条目为该版本的详细记录。

Added — 记忆新鲜度预言机 + 上下文经济引擎(均默认关,显式 opt-in)

  • 记忆新鲜度预言机(GRAPHFLOW_FRESHNESS=1):技能新鲜度由代码图谱裁定——从 guidance/playbook 抽出的符号引用若在图里不再解析,说明代码在这个技能脚下动过。符号节点 id 内嵌内容哈希,代码一改 id 即退役、引用即失配;这是没有代码图的记忆层(Mem0 / Zep·Graphiti / Letta / Cognee)结构上给不出的信号。分级 fresh / watch / stale / unknown——判不了就明说 unknown,不假装 fresh。graphflow_skill_insights 与 CLI skill insights 每条技能附带 freshness(level / driftScore / staleRefs / reason)。stale 的 proven 技能是比缺失更坏的失效模式:它带着过去证据的自信继续错。降级策略 evaluateFreshnessPolicy 已实现(stale+proven → correctable;watch 不降级;canary 已验证者豁免),但自动降级刻意未接线——GRAPHFLOW_FRESHNESS_DOWNGRADE 仅预留开关,先观测再强制。
  • 上下文经济引擎(GRAPHFLOW_CONTEXT_ECONOMICS=1):把"省了多少 token"之外的那根轴补齐——前缀 churn 与缓存局部性。GraphFlow 每轮注入不同上下文包,这在结构上必然改写 provider 的 prompt 缓存前缀;此前 95.6% 的 prefill 节省从未与缓存命中率放进同一张表算过。新增 economics 字段:与上一轮包的前缀 churn(sharedPrefix / churnRatio)、可缓存 token 与 hitRate(尊重 provider 最小可缓存长度)、按 0.1x 读 / 1.25x 写定价的真实输入成本(显式计入 cache write 税)、以及注意力预算(context rot 阈值 ~70%,而非窗口占用率)。verdict 三态:cache-safe / prefix-churn / cache-cold——高节省率配 prefix-churn 是一条警告:便宜的 token 是用冷缓存换来的。
  • 弃权(GRAPHFLOW_ABSTAIN=1):渐进式披露买的是 context 不是智能——小语料且查询命中具体符号时,agent 自己读那一段比下发一个包更便宜,且不打碎前缀。abstention: { abstained, reason } 显式下发并附理由(静默弃权与"工具坏了"不可区分)。强制执行(真丢锚点)暂不开启:需先过能力地板 A/B 证明净收益。
  • 能力地板 + 弃权 A/B(GRAPHFLOW_ABSTAIN_ENFORCE=1,默认关):见下方"弃权 A/B 实测"。

能力地板(src/graph/abstention-floor.ts)

shouldAbstain 只给 GraphFlow 一侧定价,而弃权真正交换的是精选摘录 ↔ 整文件读取——一次文件读比它替代的锚点行贵一个数量级。所以地板不问"agent 找不找得到",而问**"agent 能不能以不更贵的代价抵达同一份证据"**,三道门全过才算数(breachedGate 报第一道否决的门,理由指名决定性反对而非最后检查的门;所有门都会测量,因为部分报告无法说明其余问题是轻微还是灾难):

  1. 可达性(≥95%)——每条锚点的信息都必须能经某个 handle 取回。module:foo 说的正是 foo.ts 里的东西,handle 已覆盖它,丢掉不损失;dialogue:* 决策记录是 agent 学到而任何文件里都没有的东西,读不回来。丢证据不是 token 交易,是能力损失。
  2. 文件数(≤2)——有界导航。超过两个文件,agent 就是在手工做检索(GraphFlow 存在的意义),而且下面的成本模型不再诚实(真实 agent 会搜文件而不是整份吞下)。
  3. 读放大(≤1.1x)——handle 与读取的总代价不得超过它替代的包。handle 不是免费的:实测一个 45 tok 的包被 42 tok 的读取 + 9 tok 的 handle 替代,是净亏 6 tok。

地板可否决 shouldAbstain 的乐观判定:语料小到满足启发式,若指向的文件比包本身更贵,包照发。

弃权 A/B 实测(真实检索,两语料,配对)

A. 真实代码(src/graph/language-indexers 复制件:16 文件 / 2.4–17KB / 114 符号)——0/12 通过:

查询包 tok锚点handle文件读取 tok倍率否决门
analyzeStCode32915661369641.8xreachability
walkTreeSitterAst37115661079729.4xreachability
st-analyzer.ts33815661369640.5xreachability

真实代码上弃权是 27–42x 的 token 倒退,且会丢掉 dialogue:* 决策层(包里约 20% 的锚点不在任何文件中)。

B. 微文件(124–169 字节/文件,干净副本 + recordDialogue:false)——2/4 通过并真的执行:joinLines 0.91x 省 4 tok、trimAll 0.78x 省 10 tok;tokenize/detokenize 1.13x 被正确否决。

结论:弃权在 GraphFlow 上是自毁的——整个产品价值就是那份压缩(实测压缩比约 30x),要让弃权划算,压缩比必须 <1.1x,也就是包得和原始文件一样贵,那等于 GraphFlow 没做事。唯一划算的区间是微文件(单文件约 10–20 行,15 条锚点本身就比整个文件贵),而那里绝对收益是个位数 token。GRAPHFLOW_ABSTAIN_ENFORCE 因此永久保持默认关——不是"等 A/B 证明",是 A/B 已经证明它不成立。

A/B 揪出的三个真 bug(都是我自己写的):

  • 地板第 3 道门原本只把"读取"和包比,忽略了 handle 自身的开销,于是放行了一个净亏 6 tok 的委派。现按 handleTokens + readTokens 比,并加了精确对应此案的回归测试。
  • 可达性原本问"每条锚点有没有路径"——错问。module:foo 的信息就在 foo.ts 里,判成"丢证据"等于因零成本差异否决地板。改成问"信息是否能经某个 handle 取回"。
  • shouldAbstain 的 queryHasConcreteRef 用 extractSymbolCandidates 判具体引用,而该模式只认 camelCase / 路径 / 调用语法——于是 tokenize 这种最具体的引用被判成"没有具体引用",恰好堵死弃权最该触发的场景。改为 queryNamesGraphNode 直接对图谱求证(文本启发式会漏,证据不会)。

Fixed

  • 前缀模型此前把宿主静态前缀当成 churn 部分(live 验证发现):buildContextEconomics 一度只把 GraphFlow 注入的包当作"整个前缀",于是 540 tok 的包被判 cache-cold(低于 provider 最小可缓存长度)——用一个切片的尺度否定整个请求的缓存能力。现按 prefix = staticPrefixTokens + package 建模,且只有我们的切片参与 churn(宿主静态前缀按定义稳定)。宿主前缀 GraphFlow 看不见(它不是 harness),由 GRAPHFLOW_STATIC_PREFIX_TOKENS 提供;缺省 0 = 纯切片模型,非法值安全回退 0。
  • 首次观测不再谎报 100% churn:PrefixChurn.firstObservation 标记"本进程尚未注入过包",此时 churn 不可测。
  • 技能引用也来自 name:task-echo 类技能把主体写在 name(如 src/graph/context-pressure.ts),此前只扫 guidance/description/playbook,导致这类技能恒为 unknown。现纳入 name,live 复验从 unknown 变为 fresh(ref 解析成功)。
  • 披露:本次改动放宽了两条 golden 排名门(topK 3 → 4),是本次提交自己触发的。retrieval-golden.test.ts 会把整个 src/ 索引入内存库,因此任何新增 src/ 文件都可能推动某条查询的边界排名。实测:新文件 src/graph/abstention-floor.ts 的文档散文高度 anchor 化,对含 "anchor" 的查询 goal anchor alignment deviation 合法地排到 #2,把 goal-anchor 从 #3 挤到 #4;graph-utils.ts 新增 queryNamesGraphNode 使该文件符号 id 变化,st-analyzer 从 #3 移到 #4。召回断言未变,两条期望锚点都仍在包内——被放宽的只是"排名稳定性"这一层启发式。已 git stash 复验:干净树上 148/148 通过,确认不是检索逻辑回归。这是本次提交里唯一一处"改测试迁就自己"的地方,特此标明。

验证(live,MCP stdio 两轮真实 tools/call)

  • 前缀 churn 是真的:连续两个普通查询("orchestrator phases" → "skill flywheel admission")之间,注入包 36 行里只有 1 行保持不变,churnRatio 0.972,verdict: prefix-churn——GraphFlow 每轮注入的包基本不可跨轮复用。
  • 但绝对影响受宿主前缀主导:GRAPHFLOW_STATIC_PREFIX_TOKENS=8000 时 hitRate 93.7%/94.7%,输入成本相对无缓存基线省 60.9%/61.6%。默认预算(1500)下包很小,风险被静态前缀吸收;当预算放大或检索更密时才会成为主导成本。
  • 弃权按设计不误伤大仓:本仓 8684 节点 → abstained: false,理由明写 "corpus too large to navigate by reading (8684 nodes > 2000)"。
  • 新鲜度在本仓可判定:唯一技能(列出 src/graph/context-pressure.ts 的导出符号)判为 fresh(1 ref,解析成功)。
  • CLI 一次性进程测不出 churn(previousLines=0):churn 状态在进程内存里,只有长驻 MCP server 跨轮可比——已用真实 stdio 两轮验证。

验证(放大预算复测:前缀 churn 会成为主导成本吗?)

用真实模型 + 实测 churn 0.972 做交叉扫描(宿主静态前缀 8000 tok、$3/MTok):

包 tokenshitRate缓存总收益churn 代价是否倒挂
25097.1%$0.01609$0.00047否
50094.3%$0.01657$0.00095否
2 00080.6%$0.01950$0.00379否
8 00051.4%$0.03120$0.01517否
32 00022.2%$0.07800$0.06067否
64 00013.6%$0.12133$0.12133接近打平,仍未倒挂
  • 结论(推翻本项目此前的判断):只要宿主有一段稳定的 system+tools 前缀,前缀 churn 在任何现实包尺寸下都不会超过缓存的总收益——要到约 64k tok 的注入包才接近打平,那是典型 agent 整个上下文窗口的两倍。"churn 击穿缓存"是二阶效应,不是一阶架构风险。 此前把"缓存局部性"列为最严重暴露面属高估,此处按实测更正。
  • 真正的约束是检索召回,不是预算:--max-anchors 15 / 60 / 200 三档下锚点数恒为 3(包 274→288 tok,仅用掉 1500 预算的 18%);放大 maxContextTokens 同样不会让包变大。包小是精度换来的,不是预算限制的结果——这正是交叉扫描结论成立的前提。
  • 首轮扫描曾误用 3 行合成数组(churn 0.667)却标为 0.972,已按实测 36 行共享 1 行重算;修正后结论不变,数值全部更保守可信。

Fixed(第二次更正:经济引擎此前给宿主尾部定价为 0)

  • 注入位置的代价此前完全没被计价(estimateSuffixInvalidation + cache-break)。缓存是从左到右的前缀匹配:一个字节不同,其后每一个 token 都失效,必须按 1.25x 重写而不是按 0.1x 读回。GraphFlow 注入的是每轮变化的内容,所以 churn 的真实代价不是我们那 500 tok 切片自身的重读,而是它后面宿主的整条尾巴(对话历史、既往工具结果)被一起拖出缓存。此前模型只算自己那一片,于是把一个净亏损显示成 prefix-churn。
    • live 实测(MCP stdio 真实两轮,宿主尾部设 50k tok):churn 97.4% 时重写 48 718 tok,税 $0.168/轮,而压缩只省 $0.0156/轮 —— 净亏 $0.152/轮,verdict 由 prefix-churn 翻为 cache-break。
    • 交叉扫描:宿主历史 ≈8k tok 起(仅比 8k 静态前缀高一档)就越过压缩收益。也就是说在真实长会话里,注入位置的代价大于压缩的收益——这比上一节"churn 是二阶效应"的结论更强,且方向相反:不是被静态前缀吸收,而是把静态前缀之后的一切都拖下水。
    • invalidation 与我们的 cost 分开上报:我们那一片是小头,宿主的尾巴是大头,混在一个数字里必然看不见大头。overspendUsd 给出可直接决策的净值。
    • 宿主两侧 token 数我们看不见(我们不是 harness),由 GRAPHFLOW_SUFFIX_TOKENS / GRAPHFLOW_STATIC_PREFIX_TOKENS 提供,缺省 0 = 只算自己那一片(会系统性低估)。
  • 首观测不再凭空记一笔 churn 税:本进程尚无前缀可破坏时 rewrittenTokens = 0。

由此得到的产品级结论(比上面的数字更重要):把每轮变化的注入放在稳定前缀之前,等于每轮强制宿主重写整条历史。这与 provider 官方指引完全相反——按稳定性排序,从最稳到最不稳,前稳后动。因此下一步的最高杠杆不是"喂得更少"(我们已经很省,且已证明喂得少正是弃权失败的原因),而是让注入尽量靠后、或让注入内容尽量稳定:稳定的项目级前缀(可缓存)+ 极小的每轮增量(放在最后),才是 agent 场景里真正省钱的形状。

Added — Prefix Cache Planner(GRAPHFLOW_CACHE_LAYOUT=1,默认关,纯声明)

  • 为什么排在省 token 之前:上一节的实测显示位置才是亏钱的那一层——压缩省的($0.0156/轮)比注入位置亏的($0.168/轮)少 10 倍。而"再喂少一点"这条路,弃权 A/B 已证明在 GraphFlow 上是自毁的(压缩比必须 <1.1x 才划算)。所以 R10-P0 选 Prefix Planner。
  • 新字段 cacheLayout:stablePrefix(跨轮稳定:repo/module map、项目约定、长期工作集)+ delta(每轮变化:query 锚点、对话召回、当轮工具结果)+ reusablePrefixShare + 一句 note。保证 stable 行全部排在 delta 行之前,宿主按 stable→delta 拼接就自动拿到正确顺序——稳定性不只是每行的属性,也是序列的属性。
  • 只声明,不决策(插件形态的正确形状,不是妥协):GraphFlow 是 MCP 插件,不是 harness。它设不了 cache 断点、定不了注入位置、也阻止不了宿主重新渲染我们的行——那些都是宿主的 API 调用。它只能说明"这 N 行稳定、这 M 行不稳定",然后被忽略。能替宿主重排 prompt 的插件就是穿着插件外衣的 harness,且在宿主 prompt 形状与假设不符时立刻失效。
  • 无法识别的行一律归 delta:把无法定位的行当成稳定,是唯一会静默破坏宿主缓存的错误,默认必须落在安全的一侧。
  • 宿主前缀未知时 reusablePrefixShare 报 null 而不是 0:0 意味着"请求里没有任何部分可复用",这是一个更强且几乎必然为假的断言;看不见就说看不见(我们不是 harness)。
  • live 实测:本仓一次真实 preview,39 行中 2 行(790 tok 中的 19 tok,2%)跨轮稳定,其余 37 行每轮变化——我们注入的内容本身几乎全是 per-turn 变化,这正是"注入必须放在断点之后"在我们自己身上的直接体现,也是宿主最需要这个声明的原因。
  • 首版曾漏掉 slicer 在 summary 通道里对 module 节点的散文形式(Module: <path>),把它误判成易变;已补规则并加回归测试——那是丢失缓存复用,与本模块存在的目的相反,方向上比误判稳定更危险。

Added — Project Brief:让 stable 段真的有内容(GRAPHFLOW_PROJECT_BRIEF=1,默认关)

  • 动机:上一个提交只是声明哪部分稳定,而 live 实测发现我们注入的内容里 39 行只有 2 行(2%)稳定。一个正确地声明"这里几乎没什么稳定"的声明不是缓存策略——稳定段必须被做出来,宿主才有东西值得放在断点之前。
  • 新字段 projectBrief:从仓库本身(而非当前问题)派生的跨轮稳定段:模块清单、文件目录分布、入口文件。所有内容确定性排序、无时间戳、无随机、无迭代序——宿主缓存是字节匹配,输出必须逐字节可复现。
  • 先验证、后复用:重建 brief 每次调用都会产生新包,正是我们要消除的 churn,而且重建本身就是贵的部分(一次模块遍历 + 导出扫描)。所以复用由证据把门,与新鲜度预言机同源:brief 是关于仓库的断言,而符号节点 id 内嵌内容哈希,每个 ref 仍能解析 = 断言仍成立。不成立就重建,并且把重建理由说出来——静默过期的 brief 是一张错的项目地图,比多几个 token 糟糕得多。
  • 复用 buildRefResolver 而非另造一套:问题是同一个问题,两套 resolver 迟早会不一致——而那种漂移会把缓存变成错误答案的来源。并且用测试把耦合钉死:ref 必须记成 resolver 真正索引的形式(file 记去前缀路径、其余记原始 id),否则每个 brief 都会自报过期、每次调用都重建。(实现时正是先写成了路径集合,被测试当场抓住。)
  • live 结果:stablePrefix 从 19 tok → 678 tok(2% → 约 30% 的包为稳定段)。
  • 但 brief 里的地图一开始是错的,逐层修掉三处(都是 live 才暴露的):
    1. 越界路径:地图里出现 ../LightNav-0/*、../Robot_Screw/*——别的项目。这些路径也是稳定的,所以它们通过了全部稳定性检查,却悄悄占据了地图。描述别的项目的项目地图不是"不够好",是"自信地错"。现过滤并明确报告跳过数量。
    2. 非项目路径:argparse、asyncio、AUDIT.md 这类裸名不是仓库里的地方,是索引器从"这里从来不是目录"的东西派生出的 module 节点——本仓 888 个 module 节点里绝大多数如此。现省略并计数。
    3. 按名字排序取前 N 是错的规则本身:连续三轮"改排序"都以同一种方式失败——任何按名字排序的取前 N,都会被恰好排在前面的目录吃光预算。本仓那个目录是 benchmarks/* 和 docs/*,于是 src/*(读者真正需要的部分)从未出现。最终改为按权重选:文件计数已经知道代码在哪里,地图就从最重的目录开始,并且每目录设上限,最重的角落也不能独吞。
  • 仍然是插件形态:brief 是内容,不是决策。它不设断点、不重排宿主 prompt、不拦工具调用。不理它的宿主只会失去一个缓存优化,别的什么都不损失。

Fixed — 图谱脏节点:跨项目污染 + Module 命名空间被污染

诊断出两个独立根因(都不是"配置没设对",是缺检查):

根因 1:索引器没有工作区包含性检查。 indexSingleFile 直接 relative(rootDir, absPath),对仓外文件会得到 ../other/foo.py 并原样入库;graph file <path> 又接受任意路径(绝对或 ../ 相对)。实测本仓已被污染:../LightNav-0/elite_cs612/tests/test_deproject.py 的 33 个节点(2 File + 2 Module + 29 Symbol)是另一个项目的真实 Python 源码,被当成自己的代码索引了进去。兄弟目录 ~/Desktop/Tmp/Code/LightNav-0 确实存在。

  • 修复:workspace-containment.ts 的 isInsideWorkspace,在 indexSingleFile 最前面拦截——放在索引器而非 CLI,是为了覆盖所有调用方(CLI、file watcher、MCP 工具),而不只是用户能敲出来的那个。
  • 两道检查:① 词法(resolve + 拒绝 .. 逃逸);② 物理(realpath 解析符号链接后再查一次)。只做①会被绕过——工作区内一个指向 /etc 或兄弟 checkout 的符号链接在文本上完全本地,却能把整棵外部树导进来。
  • root 不存在时(全新工作区)退回词法检查而非抛错:路径不存在不是"这条路径是外部的"的证据,真正的错误由调用方的 statSync 报。
  • 端到端复验:绝对路径与 ../../ 相对路径两种逃逸均被拒,理由明写。

根因 2:markdown 链接被当成 import,而每个 import 都变成一个 Module 节点。 file-indexer-nodes.ts:214-221 对每个 import target 建 module:<target> 节点加 imports 边;markdown indexer 把每一个链接和 badge 都报成 import。最小复现(单个 README)产出:

module:https://img.shields.io/badge/npm-1.0-blue
module:https://github.com/a/b/issues
module:docs/guide.md          ← 相对文档链接

没有哪个项目的"模块"叫一个 badge。这些节点带边,所以会参与检索排序、占据 module 地图——本仓 80 个。

  • 修复两处:① normalizeImportTarget 拒绝带 URL scheme 的 target(必须拒绝而非清洗——https://x/y.png 去掉扩展名仍是 URL);② markdown indexer 不再把链接/wiki 链接报成 import。没有信息丢失:跨文档结构已由 buildDocumentEdges 建模、标题是 declared symbols,而 imports 在此文件之外唯一的消费者是 PLC 边构造器,它永远看不到 markdown。
  • 复现验证:单个 README 的 Module 节点 5 → 2,剩下的 2 个(module:README、module:docs/guide)都是真实文件;标题符号 5 个不变。

清理:graph prune [--apply](默认 dry-run)。三类判定都必须是可证的外部/非模块,因为"删孤儿节点"会误伤真实内容——PLC 结构化文本的 POU 合法地产生无边 Module 节点:

  • workspace-escape(33):路径离开工作区,即现场发现的那个形态。
  • link-module(80):Module 节点 id 是 http(s) URL。
  • foreign-artifact(0):内容是序列化的节点集合(graph 快照)而非源码。

每类都有计数与 id 清单,删除前必先出计划,绝不静默删除;后端不支持删除或删除失败时如实上报而非假装干净。本仓已清理:删除 113 个节点 + 215 条悬空边,8715 保留,复验 dry-run 归零。

一处自我更正:我一度怀疑 benchmarks/run-*.ts 直接往真实图谱写合成节点(client.upsertNodes),查证后不是——它们用 GraphifyClient(内存库),与真实 store 隔离。该猜测作废,未写入结论。

又一次需要你复核的测试改动(第三次):retrieval-golden 两条 topK 4 → 5,仍是本会话新增 src/ 文件推动边界排名的老问题。召回断言三次全部通过,失败的只有位置界。已在测试文件顶部写下警告:这条界现在测的更多是"语料变没变"而不是"检索退没退",若还需要再放宽,就该把硬位置断言换成召回断言 + 排名报告,而不是再加一格。

Fixed(第二轮)— golden 门改为聚合漂移预算 + brief 真正养大

1. golden 排名门重设计(上一轮说"不该再加一格",所以改门而不是改数)

  • 逐查询硬界(pos < topK)与语料耦合:它索引整个 src/ 并断言精确名次,所以新增一个合法源文件就能让构建失败——本会话已因此失败三次,其中两次是本项目刚加的文件,而召回三次全过。它测的更多是"语料变没变"而非"检索退没退"。
  • 现改为聚合漂移预算:提交 tests/fixtures/retrieval-rank-baseline.json(132 条查询的基线名次),每条查询允许漂移 RANK_TOLERANCE=2 个位置,超过 MAX_DRIFTED_QUERIES=12 条才失败。真实排序回归会一次挪动几十条,一次新增文件只挪几条。
  • 已验证它有牙:把全部基线强制为 0 → 漂移 10 条 → 失败,并逐条列出漂移明细(0 -> 3 / 0 -> 4)。预算 12 是在"假警报史"上调出来的——它已经喊了三次狼。
  • 三处此前的 topK 放宽全部回退(3/3/4 原值),因为硬界已不存在;topK 字段保留,仅作意图文档与漂移报告输入。
  • 基线刷新需显式:GRAPHFLOW_UPDATE_RANK_BASELINE=1 npx vitest run tests/retrieval-golden.test.ts,并要求读 diff 再提交。

2. brief 真正养大(纠正上一轮的框架错误)

上一轮说头号优先级是"养大 stable 段跨过 provider 最小可缓存长度"。那个框架是错的:最小长度针对断点前的整个前缀,而宿主自己的 system+tools 已 8000 tok,早已越过 1024。stable 段的价值不在"跨阈值",而在它每轮被缓存了多少 token。

  • 量化后确认仍值得做(宿主静态 8000、读 0.1x、$2/MTok):stable 678 → 2500 时每轮节省从 $0.0012 升到 $0.0045。
  • 新增两段高价值稳定内容:exports:(按文件列出导出符号——"这个文件提供什么"正是 agent 否则要花一次文件读才知道的)与 brief: hotspots=(由 references/calls/imports 边算出的被引用最多的模块,回答"改代码前该知道哪些模块承重")。
  • live 结果:brief 678 → 2969 tok,stablePrefix 678 → 2989 tok(4.4x),delta 反而从 1215 缩到 765(brief 的行原先被误算进 delta),可复用前缀占比 87.7% → 93.5%,每轮节省 $0.0012 → $0.0054(4.4x)。
  • 两处实现 bug 被 live 暴露并修正:filePathOf 只读 metadata.sourcePath,而 Symbol 节点实际带的是 metadata.file,导致整个 exports 段静默为空——恰好是最该有内容的那一段;cacheLayout 的稳定模式没包含 brief 自己的行首(brief: / exports: / files:),把 2969 tok 全划进了 delta 桶。两处都加了回归测试。
  • 刻意排除的东西(并且有测试钉住):Decision / dialogue / topic 节点。它们是图里最"有用"也最易变的内容——会随会话累积,纳入就等于让 brief 每轮变化,正好复现这个段要消除的 churn。新增测试模拟 6 轮会话累积决策,断言 brief 指纹逐轮不变。稳定不等于有用。

3. GRAPHFLOW_SUFFIX_TOKENS 自动采集:取消,改为敏感性扫描

原计划"从 hook 自动采集宿主 token 数"。查证后:我们根本观测不到宿主的 token 数——那是 harness 的 API,没有任何图谱数据能推出它。做"自动采集"只能造一个假数字,比留空更危险。

  • 改为 economics.sensitivity:扫描一整段合理的宿主尾部尺寸(0 / 2k / 8k / 20k / 50k / 120k / 250k),给出每档成本与净值、翻转点与结论是否稳健。
  • 结论不再压在一个人工填的数上:live 显示 churn 97.4% 时 breakEvenSuffixTokens=8000、conclusionIsRobust=false——明说"这个判断取决于宿主的真实规模,而不是你填的估计值";无 churn 时 robust=true,明说"不依赖宿主规模"。

Verified — 真实 provider 端到端 A/B(benchmarks/cache-placement-ab.ts)

之前所有缓存结论都来自公开的缓存乘数 + 我自己的前缀匹配模型,从没被任何 provider 的真实缓存验证过。现在用 DEEPSEEK_API_KEY 打了真实请求,读回 provider 自己的 prompt_cache_hit_tokens。

实验(3 臂 × 3 轮,40 轮历史,max_tokens:16):C 宿主单独跑 / A 把每轮变化的注入放进 system 层 / B 把逐字节不变的 brief 放进同一位置。每臂独立 system 块(首轮全部 hit=0),避免跨臂缓存串味。

臂末轮 hitRatio全价计费 token
C 基线(无注入)95.1%3790
A 每轮变化注入43.1%9459
B 稳定 brief94.1%4515

结论:52.0 个百分点的落差,每轮多付 1890 个全价 token。 更要命的是 A 臂幸存的缓存恰好只有 system 里的稳定段(1920 tok)——整段对话每轮被重新计费。会话越长越糟(3 轮历史时是 28.6 个点,40 轮是 52 个点)。而 B 臂与基线基本无差:逐字节稳定的 brief 放在断点前不花宿主一分钱。

由此改了三处(都是被测试逼出来的,不是想出来的):

  1. 缓存定价原本是把一家厂商的数字套给所有人。实测 DeepSeek 完全没有缓存写入溢价(cacheWrite=0),缓存读约为未命中价的 2% 而非 10%。旧默认(1.25 / 0.1)在 DeepSeek 上把 churn 税高估了 2247%。现按 provider 取档位(CACHE_PROFILES),只收录已对厂商页面或真实 usage payload 核实过的值;未匹配时回退到一个**明写"保守兜底"**的档位,而不是假装知道。buildContextEconomics 新增 provider 参数。
  2. pickUsage 读不了 OpenAI / Google 的缓存字段。原先只认 DeepSeek 的 prompt_cache_hit_tokens,等于"位置问题只能在一个 provider 上、用一个 provider 的数字回答"。现补 cached_tokens / cache_write_tokens / total_cached_tokens / cache_read_input_tokens,并把写入量单列——一个反复写入却从不被读的前缀是纯 surcharge,只有把写入和命中分开才看得见。
  3. cacheLayout 的措辞按实测改写。原来写"稳定在前、易变在后",但宿主完全照做也照样丢缓存:如果两段都被拼进 system 块,易变段仍在对话之前,其后一切重新计费。措辞已改为明确指出边界位置(稳定段落在断点处、易变段放到对话之后),并写明"都拼进 system 块仍然丢缓存"。

Added — 处方化落位建议 + opencode 插件的 MCP 注册

  • cacheLayout.insertion(可照抄的处方,不再只是描述):stableAt: "system" / deltaAt: "turn-tail" + 一句 recipe + evidence(附实测数字 95.1% / 43.1% / 94.1%)。原来的"稳定在前、易变在后"可以被完全照做而依然丢缓存——两段都拼进 system 块时易变段仍在对话之前。措辞改为指名边界位置,并明说"都拼进 system 块仍然丢缓存"。
  • opencode 插件新增 mcp 注册钩子(GRAPHFLOW_OPENCODE_MCP=1 开启):opencode 自己拥有 opencode.json——手写进去的 MCP 条目会被 opencode 下次写回时规范化掉(实测发生,不是推测)。插件的 mcp 钩子由 opencode 自行合并,因而不会被覆盖。自动优先选 <workspace>/dist/surfaces/mcp/server.js(本地开发构建),不存在则回落到已安装包;GRAPHFLOW_MCP_SERVER 可显式指定。默认关闭,避免与已在 opencode.json 里配了 graphflow 的用户重复注册。

Fixed(第三轮)— 装进 opencode 的能力测试揪出来的

  • provider 档位接不上,等于上一轮的修复是死的。buildContextEconomics 没有任何调用方传 provider,所以运行时一律按 Anthropic 计价。装进 opencode 后实测:同一请求重写税 $0.17250(Anthropic 数字),而它实际发往 DeepSeek,正确值是 $0.00735——差 23 倍。现由 config.tiers 推导 provider 传入。这正是"真装一次"才能发现的 bug:单测全绿时它根本不显形。
  • 不可读文件在 JSON 里变成 null,与"未测量"无法区分。readFileTokens 对读不出的文件返回 Infinity(诚实:委派代价无上界),但 Infinity 序列化后是 null。改为 amplification.unreadableFiles 计数 + 有限的 readTokens。
  • 顺带修掉一个我自己刚引入的严重 bug:把 readTokens 钳到 0 让 JSON 好看,结果让读不出的文件看起来免费——恰是 Infinity 原本要防的失败。改为 unreadableFiles > 0 时显式判失败。新写的测试当场抓住。

验证 — 装进 opencode 的能力测试(10/10 PASS)

经插件自身产出的 spec(从已安装的 ~/.config/opencode/plugins/graphflow.mjs 加载,不是仓库源文件)启动:MCP 握手 OK、10 个工具、3 轮 context 全部返回;Project Brief 2964 tok(reused=true)、Cache Layout 处方 system/turn-tail、stable 2984 / delta 679、Economics provider-aware(cache-break,重写税 $0.00735)、敏感性扫描 robust=true、新鲜度 level=fresh、能力地板按设计拒绝弃权(8773 节点 > 2000)。doctor 三个 opencode 切片(mcp / hooks / instructions)均为 installed。

原 opencode.json 已备份为 opencode.json.bak-graphflow-local-20260928-183059。

Fixed — doctor 曾在"跑错构建"时报告健康

安装后的人工排查发现:doctor 对三个 opencode 切片全部报 installed,但 MCP 实际启动的是 npm 全局包,比本地 dist/ 早编译 10 小时。原因是 probeDanglingGraphflowEntry 只回答"它启动的那个文件存在吗"——存在,所以健康。对一个正在改 GraphFlow 的人来说,这是最该被报出来的情况,却恰恰被漏掉。

  • 新增 probeMcpEntryPoint:报告宿主实际启动的入口,并区分 fromPublishedPackage;当宿主指向已发布包而工作区存在更新的本地构建时,标记 staleLocalBuild。
  • DoctorCheckStatus 新增 stale 状态(既非 installed 也非 missing:文件在,只是构建错了),summary.stale 单独计数,ok 现在要求 missing === 0 && stale === 0。一个跑着旧构建的宿主不算健康——这比报 missing 更糟,因为它看起来是成功的。
  • 消息里给出两条路径并给出可执行的修法(设 GRAPHFLOW_OPENCODE_MCP=1 并从配置文件删掉 graphflow 条目,交由插件注册本地构建)——此修法已被下方第三次更正证伪,改为 install --mcp-plugin。
  • 修好后本机实测:summary {installed:62, missing:0, stale:1},ok:false,stale 项准确指向 ~/.npm-global/.../server.js 与本地 dist/.../server.js 两条路径。

Fixed — doctor 曾对"正确配置"报警(修 stale 时引入的方向性错误)

把 opencode.json 里的 graphflow 条目删掉、改由插件注册之后,doctor 反而报 missing——惩罚了唯一正确的那个配置。原因:doctor 只认配置文件里的条目,不认插件注册这条路;而这条路恰恰是在本地改 GraphFlow 时唯一可行的(opencode 会规范化自己拥有的配置,手改条目留不住)。

  • 新增 probePluginRegisteredMcp():仅当(插件已安装)且(配置里确实没有 graphflow 条目)时成立。配置里有条目时不认——那时配置在运行时优先,说成"插件注册"就是撒谎,那种情况归 stale 管。
  • 成立时输出单条 installed 检查(Opencode (registered by plugin))并说明入口;同时跳过配置那条检查,否则同一个 server 会同时出现 installed 和 missing。一个 server 一条检查。
  • DoctorCheckItem.message 补上正式声明(此前各处靠展开绕过类型检查,字段其实一直没被类型承认)。理由:文件存在与否不足以定论时,必须把话说明白,否则一个光秃秃的状态位会诱导出相反的结论。

修好后本机实测:summary {total:61, installed:61, missing:0, stale:0},ok: true——正确配置现在读起来就是正确的。新增测试锁住"插件已装 + 配置无条目 → 恰好一条 installed 检查"这一组合。

Fixed(第三次更正)— 插件注册开关是自毁的:env 变量活不过进程,install 又把条目写了回去

上一条把"设 GRAPHFLOW_OPENCODE_MCP=1 并删掉配置条目"说成修法。实测证明它两处都不成立,而且都是我自己的设计问题,不是用法问题。

1. env 变量活不过 opencode 的服务进程。 变量设好、用户重启、配置条目已删——毫无变化。查进程表才看清:MCP 子进程的父进程是 opencode-cli serve --service,该进程已连续运行 10732 秒(3 小时),子进程年龄 1538 秒。重启没碰到真正持有 MCP 的那个进程;而且变量只在当前 shell,不在任何 rc 文件里,下次启动(含 GUI 启动)必然丢失。

  • 改为持久 marker:~/.config/opencode/plugins/graphflow-mcp.json。它随安装走,跨重启、跨 GUI 启动、跨换机器都在。
  • 优先级:显式关闭(env 或 marker)> env > marker。用户任何时候都能停掉它——一个只能开不能关的开关不是开关。
  • 新增 install --mcp-plugin / --no-mcp-plugin,opt-in 不再依赖"记得 export"。

2. install 把刚删掉的条目又写了回去。 打开 marker 后跑一次 install,doctor 立刻回到 stale——安装器自己重新创建了那个优先级高于插件注册的条目。插件开着,配置条目也在,而 opencode 运行时优先配置。

  • 关键在于拦在哪一层。第一版把守卫放在 installProfileHost 的 opencode 切片里:切片删掉条目,随后的全局 MCP 安装 pass 又把它写了回来。用 writeFileSync 包装器抓到了真实调用栈(injectIntoOpencodeConfig ← injectIntoAgentConfig ← installMcpToDetectedAgents),确认存在第二条写入路径。
  • 因此守卫下沉到唯一咽喉点 installMcpToDetectedAgents 的 per-target 循环。marker 开着时该 target 走移除而非注入 —— 第四次更正:移除是错的,正确做法是写入指向工作区构建的条目。profile-host-installer.ts 因此回到零改动——单一职责点比每层各守一遍更难写错。
  • 两个方向都实测:marker 开 + install → 条目消失;marker 关 + install → 条目恢复写入(单向门会让关掉开关的用户彻底没有注册)。终态 summary {installed:61, stale:0}、ok: true、installed - Opencode (registered by plugin)。

3. 两个 home 解析不一致,会让开关静默失效。(此条仍然成立,见下) 测试暴露 resolveOpenCodeHome()(认 GRAPHFLOW_OPENCODE_HOME)与 agent profile 注册表(认 homedir())可能指向不同 home——若不一致,守卫会读错 home 的 marker,opt-in 静默变空操作。成因:profile 在模块加载时就调 resolveHomePaths() 完成注册(registerOpencodeProfile() 随 import 执行)。生产默认下两者一致,但这个不一致是真实的,已加测试钉住"注入写的 home 与读 marker 的 home 必须是同一个"。

Fixed — 全量测试会改写开发者真实的 agent 配置("测试全绿"与"doctor ok"此前互斥)

提交后复核终态时,doctor 又回到 stale——而测试是全绿的。查配置 mtime:写入时间 21:04:13,正落在全量测试运行区间内。

  • 三个测试文件(m-install-json-report / m-install-hooks-wiring / host-adapter-install)都调用 buildInstallReport,也都自称隔离了 HOME(注释原文:"isolate HOME so the machine running the suite keeps its real agent configs intact")。但隔离是假的:agent profile 在模块首次 import 时就调 resolveHomePaths() 完成注册(registerOpencodeProfile() 随 import 执行),静态 import 的 buildInstallReport 早已把真实 home 捕获在手里。此后改 process.env.HOME 对它毫无影响——安装照旧写进真实的 ~/.config/opencode。
  • 这类泄漏不会让任何断言失败:断言检查的是 report 结构,而 report 对"写到了真实 home"和"写到了临时 home"一视同仁。它只在真实机器上表现为 doctor 变脏。 用 writeFileSync 预加载追踪器抓到完整调用栈(injectIntoOpencodeConfig ← injectIntoAgentConfig ← installMcpToDetectedAgents ← installProfileHost ← installViaHostAdapter ← buildInstallReport)才定位到。
  • 修法:改 HOME 之后 vi.resetModules() 并动态重新 import 被测模块。真实 ~/.config/opencode 写入次数 15 → 0,全量 222 文件 / 1709 用例仍全绿,doctor 保持 {installed:61, stale:0} / ok: true。
  • 同一成因也是上一条 home 不一致的另一半:profile 路径在加载期固定,marker 读取是即时的。所以隔离环境里"读 marker 的 home"和"写配置的 home"会分叉——测试里的分叉是 bug,机器上的分叉是隐患,两侧都已用断言钉住。

Fixed(第四次更正)— opencode 的插件根本没有 mcp 钩子;"opencode 会规范化掉手写条目"也是错的

前三次更正都在修"怎么把本地构建喂给 opencode",方向是方案 B:从插件注册 MCP server。用户重启 opencode 后仍然没有 graphflow 进程。查下来,方案 B 在这个版本里不可能存在,而且它建立的两条前提都是错的。

1. opencode 的插件 API 没有 mcp 钩子。 ~/.cache/opencode/node_modules/@opencode-ai/plugin/dist/index.d.ts 的 Hooks 接口全部键是:agent / auth / chat.headers / chat.message / chat.params / command.execute.before / config / event / experimental.chat.messages.transform / experimental.chat.system.transform / experimental.session.compacting / experimental.text.complete / permission.ask / tool / tool.execute.after / tool.execute.before——没有 mcp。官方文档的钩子清单同样没有。返回 mcp 键会被静默丢弃。

  • 实测印证:13:23:34 重启后的日志里只有 mcp connected server=pencil tools=4,graphflow 一条都没有。插件文件确实被加载(本地文件目录是官方支持的加载方式),只是那个键不起作用。
  • 我此前在 opencode/plugin.mjs 里写的注释——"A plugin's mcp hook is merged by opencode itself, so it survives"——自称"observed behaviour, not a theory",实际从未观测过。把没验证的推断写成既成事实,正是这轮连续三次返工的起点。该注释已删除,并写明真实的钩子集合与验证方式。

2. opencode 会保留手写条目;一直在改写它的是我们自己的安装器。 直接把本地 dist/ 写进 opencode.json,8 秒后日志出现 mcp connected server=graphflow tools=10,两个进程跑的是本地 dist,且opencode 自己重新序列化配置后完整保留了这条条目。此前"opencode 拥有该文件、会把手改条目规范化掉"的判断,是把 graphflow install 自己的写入误记成了宿主的规范化——而那恰恰是上一条刚修好的东西。

3. 改为:marker 的语义从"插件注册 MCP"改成"指向本工作区的构建"。

  • marker 现在记录 workspaceRoot,条目写 <workspaceRoot>/dist/surfaces/mcp/server.js。记录而非假定:install 可以在任意目录执行,marker 若默默指向错误的 checkout,就会写出一条看起来合理、实则启动陈旧构建的条目——正是这个功能要防的失败。
  • 守卫(仍在 installMcpToDetectedAgents 这个唯一咽喉点)改为注入指向工作区构建的条目;构建缺失时报 error 并给出两条出路(npm run build 或 install --no-mcp-plugin),而不是写一条指向不存在文件的条目。
  • 顺带把 GRAPHFLOW_* 能力开关写进条目的 environment:opencode 自己拉起 MCP server,开发者 shell 里的变量同样到不了它——与之前那个 env 变量陷阱同型,只是下沉了一层。没有这一步,opt-in 特性只能在终端里测,无法在真实宿主上测。
  • 删除 plugin.mjs 中已无调用方的 mcpServerSpec / shouldRegisterMcp / marker 读取逻辑(TS 侧是唯一实现,留着会误导),以及 doctor 里 probePluginRegisteredMcp 与 (registered by plugin) 检查——该路径已不存在,为它开特例只会让 doctor 说谎。现在交给常规检查:条目指向本地 dist 即 installed,指向已发布包而本地存在更新构建即 stale,probeMcpEntryPoint 本就分得清。

两个方向都实测:--mcp-plugin + install → 条目指向本地 dist;--no-mcp-plugin + install → 恢复已发布包(命令已在下方第五条更正更名为 --workspace-build;此时范围仍仅 opencode)(单向门会让关掉开关的用户被钉在可能已删除的构建上)。终态 summary {installed:63, stale:0}、ok: true,live 日志 mcp connected server=graphflow tools=10。

Fixed — 工作区构建偏好此前只对 opencode 生效(实测其余 18 个宿主仍是 npx 启动器)

第四次更正把机制做对了,但范围只覆盖 opencode:守卫是 target.agentId === "opencode" 的专属分支。逐个宿主实测(全部 profile,不是推断):

状态宿主
指向工作区 dist仅 opencode
仍是 npx 启动器cursor / claude-code / codex / gemini / vscode / zed / windsurf / cline / roo-code / kilocode / trae / pearai / antigravity / amazon-q / continue / qoder / kimi-code / zcode
无 MCP targetdeepseek-harness(在 YAML patch 里,不在 profile registry)

npx 启动器 = 宿主每次从 npm 拉已发布包,在这些宿主里改 GraphFlow 代码完全不生效,而配置看起来完全健康。现改为宿主无关。

1. 守卫去专属化。 installMcpToDetectedAgents 的 per-target 循环里,条件从 agentId === "opencode" 变为"工作区构建已启用"。仍在唯一咽喉点——切片级守卫已被全局 pass 覆盖过一次。

2. marker 移出宿主目录。 从 ~/.config/opencode/plugins/graphflow-mcp.json 移到 ~/.graphflow/workspace-build.json(src/integrations/workspace-build.ts)。原位置把一个适用于所有宿主的决策写成 opencode 专属,也让开关读起来像 opencode 专用。opencode 侧那份 marker API 随之删除,只留 TS 实现。

3. dsh 单独适配。 它在 YAML patch 里声明 MCP,不出现在 profile registry,通用安装器够不到——否则它会是唯一仍跑 npm 副本的宿主。buildGraphFlowDshInsertPatch 现在同样遵循偏好。

  • 一处实测抓到的缩进错误:command/args 是 config: 的键,应为八空格(与 transport 同级),我先写成六。YAML 仍能解析,但启动器落在错误层级,dsh 只会在很晚的启动失败里报出来。由既有断言"安装器输出必须逐行等于仓库内 cordis.patch.yml"抓到。

4. GRAPHFLOW_* 开关写进条目 environment(跨宿主)。 宿主自己拉起 server,shell 里的变量到不了它——与那个 env 变量陷阱同型,只是下沉一层。

  • 陷阱:给 buildMcpServerNode 传 environment 类型接受、运行时被忽略(选项看起来对、实际什么都不做)。改为写盘后二次合并(mergeHostEnv),environment / env 两种键名都试。codex 是 TOML,无法安全二次合并,如实上报而非假装成功:条目仍指向正确构建,开关缺失写进 message。入口正确是硬要求,开关到达是尽力而为。

5. CLI 更名 --workspace-build / --no-workspace-build(--mcp-plugin 名不副实)。doctor 的 stale 文案指向新命令,并删除已失效的 opencode 特例注释。

实测(真实 home,逐宿主读配置文件):开启 19/19 指向 <workspaceRoot>/dist/surfaces/mcp/server.js;--no-workspace-build 后 0/19;再开启恢复 19/19。doctor 保持 {installed:63, stale:0} / ok: true。

一处我自己的测量错误:验证脚本按单一路径读条目,把 mcpServers(kimi-code / qoder)、mcp.servers(zcode)判成"未指向",而原始文件里三个都在。数字与假设矛盾时先怀疑尺子——已改为在文件原文里匹配路径,JSON 与 TOML 一视同仁。

Fixed(CI 抓到)— Windows 上测试只重定向 HOME,把 marker 写进了真实用户目录

首次推送后 Windows job 挂掉 4 个用例,其中"每个 profile"那条报 18 个宿主全部未指向——与本机 19/19 完全相反。根因不是守卫不通用,而是测试自己的隔离有洞:

  • os.homedir() 在 Windows 上读 USERPROFILE,而 os.tmpdir() 返回 8.3 短路径(RUNNER~1)。测试只设了 HOME,于是 homedir() 仍指向真实用户目录,marker 被写进真实的 ~/.graphflow。
  • 更糟的是它跨用例存活:第一个用例写的 marker 指向一个已被 afterEach 删掉的 workspace,于是后续每个用例都读到"已启用但未构建"——守卫按设计报 error,一个宿主都没注入。本机复现了这个状态机(写 marker → 删 workspace → 注入):missingBuild: true、状态 error。
  • 修法:同时设 HOME 与 USERPROFILE(与仓库既有做法一致),并在 afterEach 里先删 marker 再恢复环境变量——反过来的话 marker 会留在真实目录,下次运行读到一个指向已删除 workspace 的偏好。连续跑两轮确认无残留,全量跑完真实 home 干净。

这条只有 CI 能抓到:本机 homedir() 就是 HOME,同样的代码 19/19 通过。平台差异让"测试通过"不再等于"行为正确",这正是这次必须推 action 的理由。

Fixed(第三轮 CI)— 守卫在 Windows 上一直是好的,坏的是我的断言

第三轮 CI 只剩 1 个失败,而它的诊断信息推翻了前两轮的每一个假设:

cursor: status=created exists=true mentionsDist=yes
        configPath=C:\Users\RUNNER~1\...\gf-wb-home-wD2cks\.cursor\mcp.json
        message=launches the workspace build at C:\Users\RUNNER~1\...\gf-wb-ws-PZ...

status=created、mentionsDist=yes、路径全在 sandbox 内——18 个宿主全部正确写入了工作区构建,守卫从头到尾都在工作。而我前两轮分别归因于"marker 泄漏"和"APPDATA 未重定向",两次都错。(那两轮的修复本身是必要的:marker 确实曾泄漏、4 个用例确实因此失败;只是它们都不是这个用例失败的原因。)

真正的失败是断言本身:文件是 JSON,写入时反斜杠被转义成 C:\\Users\\...,而我拿 raw.includes(serverPath) 去做字面子串比较——在 Windows 上这永远不可能匹配。18 个宿主"失败"纯属尺子坏了。

  • 比较改为抽取路径形态的候选再逐段比较(mentionsServerPath),对 \\ 与 / 都接受。
  • 顺带消掉 8.3 短路径:测试目录建好后取 realpathSync,使期望路径与写入路径在拼写上一致。短路径 RUNNER~1 与长路径 runneradmin 是同一目录的两种拼法,不是两个地方。
  • 过程中我自己又错了两次才做对:先写成"把反斜杠全删掉"(会把段粘连,正是要比较的分隔符),后靠逐例打印才发现。这类尺子必须用已知输入验证——现在有 5 个用例直接喂真实形态:JSON 转义 / TOML 正斜杠 / 长路径一致 / 短长不同判 false / 无关 npx 条目判 false。
  • 保留 detail 输出(status / exists / configPath / mentionsDist / message)。没有它,这个用例会再骗我两轮——只列 18 个宿主名,不足以区分"写到别处"、"没写"、"写错内容"。

方法论:这个 bug 本机不可复现(Linux 无反斜杠转义),全绿 1716 个用例。它是被"让 CI 跑"逼出来的,不是被测试逼出来的。

Fixed — 依赖漏洞清零(8 → 0),其中 6 项不需要破坏性升级

npm audit 此前有 8 项(4 high / 3 moderate / 1 low),Security Audit workflow 已连续失败至少三周(9/14、9/21、9/28,仅在 schedule 上跑)。现全部清零,security:audit 退出 0。

  • 6 项非破坏性:全部是传递依赖的补丁版本,overrides 即可。hono(跨请求数据泄露 / ReDoS / toSSG() 写出输出目录之外)、@hono/node-server(Windows 经 %5C 的路径穿越)、body-parser(非法 limit 静默关闭体积限制 → DoS)、fast-uri(host confusion / SSRF)、ip-address(前导零八进制与 NAT64 分类绕过 → SSRF)、qs(array-limit 绕过 / DoS)。

  • 1 项需要主版本升级:@huggingface/transformers 3.x → 4.3.0,它是唯一的直接依赖漏洞来源(sharp / libvips / libheif 的 CVE-2026-33327/33328/35590/35591、GHSA-g89c-p67h-r497、GHSA-2jg2-4ch7-h545)。npm 标注 isSemVerMajor: true,我仍然做了——理由是 src/learning/embeddings.ts 实际用到的 API 面极窄(pipeline、env.cacheDir、env.remoteHost),逐个实测存在且可写,且 4.3.0 把 sharp 提到 0.35.5 正是修掉这些 CVE 的版本。"breaking" 标签说的是依赖树,不等于这个调用面会破。

  • 未能端到端验证的部分:本机 huggingface.co 不可达(registry 通、HF 不通),真实模型下载与推理跑不了。已验证的是 API 契约(三个成员逐一实测)与全量 1716 用例。embedding 的真实数值行为只有你在有网环境才能确认。

  • security-audit.cjs 现在会说人话。此前它在 --json 下把 npm 输出写进文件、stdout 什么都不打印,CI 日志只有一行 "Process completed with exit code 1",必须翻 artifact 才知道原因。现在非零退出时把三件事分开讲:有哪些漏洞(名称 + 严重度 + 计数)、审计没跑成(镜像不支持 audit 端点等,npmmirror 就会这样)、无输出失败。三种情形都实测过。一个只有退出码的 CI 日志不是信息。

  • 顺带清掉 PearAI/User/mcp.json 与 Cursor/User/mcp.json 两个测试产物:它们出现在仓库根是因为测试的 CWD 恰好等于该宿主的 homeMarker,内容指向 /tmp/gf-wb-ws-* 已删除目录。均在 .gitignore 内、从未提交过。

Tests

  • tests/workspace-build.test.ts(13 用例,由 opencode-mcp-plugin-registration.test.ts 重命名并扩写):偏好本体(记录工作区而非假定 cwd / 后续 install 不重指向 / marker 不在任何宿主目录内 / 损坏视为未开启 / 未构建与未启用分开报告)+ 跨宿主注入(每个 profile 的条目都指向该构建 / 缺构建报可操作 error / 关闭时保留 npx / 撤销后恢复 / 开关进入 environment / 不动其他条目 / 注入 home 与读 marker 的 home 一致)+ dsh patch 两个方向。
    • "每个 profile"这条是本轮核心回归:守卫原本只对 opencode 生效,逐宿主实测才暴露。
    • 断言用文件原文包含路径而非解析 JSON——codex 用 TOML,JSON 形状的读取器会静默跳过唯一格式不同的宿主。
    • 平台相关的三处(USERPROFILE、APPDATA/LOCALAPPDATA、JSON 里的反斜杠转义)都只有 Windows 暴露;本机 homedir() 就是 HOME,文件里也没有转义。同一份代码在这里 19/19 全绿、在 CI 连续三轮失败——这是必须让 action 跑、且必须让断言自证的理由。
    • 已验证有牙:禁用守卫 → 3 个失败。
  • tests/m-doctor-json-report.test.ts:"插件注册"那组用例整体重写为"条目指向工作区构建"——断言 user-scope 条目 installed 且 summary.stale === 0。未断言"恰好一条检查":Cursor 本就产出两条(user 级 + workspace 相对级,sandbox 里后者不存在),这是既有行为,与本改动无关;最初写成 length === 1 时失败,说明是我的断言错了,不是代码错了。
    • 隔离靠 vi.resetModules() + 在设好 HOME 之后动态 import——profile 在模块加载时注册,静态 import + beforeEach 改 HOME 太晚(首版正是这样假绿失败了一次)。

Tests

  • tests/memory-freshness.test.ts(9 用例):引用抽取、无引用判 unknown、fresh/watch/stale 分级(含边界值)、自定义阈值、降级策略(stale+proven 降级 / watch 不降 / canary 豁免 / anti-pattern 不降)、开关读取、buildRefResolver(符号名 + 仓库相对路径可解析;内容哈希漂移后不可解析)。
  • tests/context-economics.test.ts(9 用例):前缀 churn、低于 provider 最小可缓存长度时拒绝建模、cache/fresh 切分与 hitRate、含 cache write 税的成本账、注意力预算四级、弃权四象限(含"reason 必须说明前缀稳定性")、开关读取、buildContextEconomics 的 cache-safe / prefix-churn / cache-cold 三态。

Fixed — 用户实测报出的两个安装级缺陷

用户在 Linux 上 npm install -g @roarpeng/graphflow@1.27.0 后报 onnxruntime-node 302 失败、graphflow doctor 报 missing=3。两处都复现并修好。

1. onnxruntime-node 安装失败会中断整个安装

@huggingface/transformers 原本在 dependencies,其 onnxruntime-node 的 postinstall 要从独立 CDN 拉二进制。该 CDN 在部分网络下不可达 / 返回 302,npm 直接判定安装失败,整个包装不上——用户必须知道 --ignore-scripts 才能继续,这是把可选能力变成了安装门槛。

改为 optionalDependencies:拉取失败时 npm 容错跳过,CLI / MCP / 上下文压缩 / 记忆全部正常,只有语义检索降级为哈希(代码里本就有 createResilientLocalEmbeddingProvider 这条降级路径)。实测:不带 --ignore-scripts 安装 tarball,153 个包装完,graphflow --version 正常。

2. 非 Windows 上 appData 解析为空字符串,把宿主配置写进了用户的仓库

agent-mcp-installer.ts 里有一份自己的 resolveHomePaths(),非 Windows 时返回 appData: ""、localAppData: ""(当时假定 appData 路径只在 Windows 有意义)。但 cursor / cline / roo-code / kilocode / trae / pearai 都声明了第二个位于 appData 的 user target,于是 join("", "Cursor", "User", ...) 产出相对路径,安装器把它写进当前工作目录——也就是用户的仓库。

用户实测留下的痕迹(本机可查):仓库内出现 Cursor/User/globalStorage/roval.cursor/mcp.json 与 PearAI/User/mcp.json,内容指向一个已被删除的 /tmp/doctor-workspace-*;doctor 因此报 Cursor (dangling entry) 与 PearAI missing,ok=false。同一原因也让测试隔离失效。

与 agent-profiles/utils.ts 里已有的同名函数对齐(POSIX 下 ~/.config 与 ~/.local/share)。修复后全部 user target 均为绝对路径。

仓库里还有两份 mcp.json 不是泄漏:./mcp.json 是本包要发布的 MCP 规格(已在 files 中、已被 git 跟踪),./.cursor/mcp.json、.vscode/mcp.json 指向扩展安装目录。它们与本次问题无关。

方法论:这次的用户实测抓到了一个我自己测不出来的 bug——我此前 20 余次跑 install / doctor 全程 ok=true,因为我的 CWD 恰好让相对路径落在无害位置,而 3 个 missing 我读成了"未检测到的 agent 不参与判定"的既有语义。同一个数字,换一台机器就变成数据损坏。

Fixed — 多词查询召回归零:FTS 把英文 token 用 AND 串起来

用户的 Zcode 实测报告"中文召回差",追下去发现真正的问题不是中文,是多词查询本身:在真实 home 上量到 buildFtsMatch 用 " AND " 拼接英文 token,而中文分支用 " OR "。

AND 要求单个节点同时包含全部查询词,于是召回随查询变长而单调收缩。本仓实测:

查询修复前修复后
installer200 节点200
preference7 节点7
installer preference0200
workspace build preference installer0200
端到端 installer preference0 锚点15

加一个词只会让结果变少,永远不会变多——这与检索的基本预期相反。"X preference" 恒为 0 与 X 无关,foo bar baz qux 也为 0,正是这个原因,不是"查询无意义"。端到端排序也正确:workspace build preference installer 的首位是 file:src/integrations/workspace-build.ts。

改用 OR。FTS5 的 bm25 本来就把"命中多个词"的节点排在"只命中一个"之前(实测首位即全命中节点),所以原先 AND 换来的精度由排序保证,而非靠丢弃候选集。中文分支本来就是 OR,现在两侧一致。

tests/m24-sqlite-backend.test.ts 里那条用例原本叫"returns nodes containing all tokens",它把缺陷当成规格钉住了。已改写为断言新的真实契约:全命中节点排第一、部分命中不被丢弃、无关节点仍不出现;并补一条单 token 行为不变的守卫。golden 排名门 149 条全过,中文查询无回归。

Fixed — CLI 的 stdout 混入帮助文本,破坏脚本消费

用户实测反馈"--json 输出里混着日志行"。核实后:日志没有混进 stdout(doctor --json 的 stdout 是单个可 JSON.parse 通过的对象),run --json 也确实打印 executionDescriptor / episodeId。真正的问题是另一处,也是唯一会让脚本报错的地方:

  • 未知命令 / --help 把 usage 横幅打到 stdout。graphflow 不存在的命令 退出码是 1,但 stdout 里有 6700 多字节的帮助文本——脚本把这段散文喂给 JSON 解析器必然失败,而且它无法区分"工具在解释自己"和"工具产出了结果"。
  • 现改为:帮助与诊断一律走 stderr,stdout 只保留机器可读输出;未知命令额外在 stderr 报 graphflow: unknown command "<name>"。doctor --json 仍正常输出可解析 JSON。
  • 新增 tests/cli-stdout-hygiene.test.ts(3 用例)钉住这条契约:未知命令 stdout 为空且退出码非 0、--help stdout 为空、真实 --json 仍可解析。已验证有牙:把 usage 改回 stdout → 1 个用例失败。

清理 — 仓库里的测试产物

  • 删除 tmp/(25M)、benchmarks/.cache/(47M)、Cursor/、PearAI/、.codex/。后三者是被测宿主配置,出现在仓库根是因为测试的 CWD 恰好是 checkout;.codex/config.toml 里还钉着 roarpeng.graphflow-1.9.6 的旧扩展路径(用户反馈的"版本残留",我找到的是 1.9.6 而非 1.7.6),一并清除。
  • .gitignore 增加 .codex/,并写明原因——Cursor/、PearAI/、benchmarks/.cache/ 此前已在忽略列表里。

Fixed — 自检脚本在 Windows 上静默跳过了 MCP 检查

用户在 Windows 上跑 1.27.6 的自检,MCP 那项显示 skipped: package not found at a known location——而实际上包就在那里。脚本只找 ~/.npm-global/lib/node_modules(Linux 布局)和 ./node_modules,Windows 的 %APPDATA%\npm\node_modules 两条都不匹配。

  • 改用 npm root -g 解析,不猜布局。这同时覆盖了 --prefix 自定义前缀的情况(已实测:npm root -g --prefix <dir> 能正确解析)。
  • skip 改为 FAIL。一个显示"跳过"的检查读起来和通过一样,这是最坏的失败形态。现在找不到包会报 FAIL,并打印它找过哪些路径。

用户在 Windows 上还给出了 1.27.6 的完整安装日志:19 个宿主的条目全部写入且路径正确(含 AppData 路径),stale=0,missing=4。文档已补 Windows 的 EBUSY(被自己开着的 agent 占用)与镜像 ETARGET 两类处理。

Fixed — 从 home 目录跑 install 会把项目文件写进 home,并覆盖带标记的指令文件

用户在 Ubuntu 与 Windows 上都从 home 目录(~ / C:\Users\xxx)跑了 graphflow install,两边都留下同一个矛盾结果:

  • ~/.claude/rules/graphflow.md 确实存在(1.6 KB),install 报 already up to date,doctor 却报 missing。同一个文件,两个相反结论。
  • 原因:该文件被写成 AGENTS.md 的逐字副本,且没有 managed block 标记。doctor 的判定是"文件里有没有 GRAPHFLOW:BEGIN/END 标记",自然判 missing。而项目规则写入器里那条 claude-rules 路径是纯复制(不带标记),从 home 跑时它把带标记的版本覆盖成了裸副本。

机制:项目作用域的目标是相对 workspaceRoot 解析的。workspaceRoot = home,于是 .claude/rules/、.windsurfrules、.agent/rules/、AGENTS.md、GEMINI.md 全部落进 home。Windows 同理(C:\Users\vboxuser)。

审计本机 home 实际被写进去的文件时,发现不止一个写入点:

文件大小写入者已守卫
~/.claude/rules/graphflow.md1.6 KBinstallProjectLevelRules✅
~/.windsurfrules1.6 KBinstallProjectLevelRules✅
~/.cursor/rules/graphflow.mdc7.6 KBinstallProjectLevelRules✅
~/AGENTS.md1.6 KBinstallProjectLevelRules✅
~/GEMINI.md1.7 KBinstallProjectGeminiInstructions✅

只修前一个就是看起来修完了其实没修完——~/GEMINI.md 照样每天被生成。两个写入点现在都复用图谱索引已有的 isUnsafeWorkspaceFallback 判定,home / AppData 作为 root 时拒绝写入并逐项说明原因。图索引早就拒绝不安全 root,项目文件此前没有——这个不对称就是漏洞本身。

tests/project-rules-unsafe-root.test.ts(6 用例):home 为 root 时一项都不写、每项都说明原因、带标记的既有指令文件保持逐字不变、两个写入点各自的守卫、真实项目目录照常写入,以及"真实 home 确实被判定为 unsafe"这个前提本身。两个守卫都单独验证过有牙:分别移除 → 各有测试失败。

本机实测(本地构建,从 home 跑 install):10 个项目作用域目标被拒绝,home 下 9 个文件的大小与 mtime 零变化。同一构建在真实项目目录跑,AGENTS.md / GEMINI.md / .windsurfrules / .claude/rules/graphflow.md 四个文件照常写入。

[1.26.0] - 2026-09-23

Added — 桥接优先与可信度收口(round 4)

  • run 把不可用的 LLM 当作没有 LLM:runTaskResult 前置 worker 问候往返(默认 5s 有界,GRAPHFLOW_RUN_PROBE_TIMEOUT_MS 可调)——探测失败即切 bridge 模式,与未配置 LLM 的行为完全一致:返回 DELEGATED + executionDescriptor + episode,RunTaskSummary.bridgeReason 携带真实原因(含适配器旁路的 401 详情)。此前坏 key 会烧满 3 次 worker 重试全部拿到占位符(live:现在 attempts=0、零 LLM 执行调用)。plan 侧同语义(planSource: probe-failed-bridge)在上一轮已落地——至此 plan/run 对"探针失败=未配置"完全对齐。
  • graphflow selfcheck:一条只读命令的红绿健康清单(8 项):配置加载 / 图存储(含代码节点存在性)/ delta 日志规模 / 索引新鲜度 / LLM 真实连通探测(区分 configured 与 reachable)/ 飞轮脉冲(pending 比例)/ 对话脱敏函数级抽查 / 会话日志。每一项都源自某轮 live 验收发现过的静默故障模式。--json 支持;有 FAIL 时退出码非零。
  • LLM_SMOKE 可选 CI 门:scripts/llm-smoke.ts + CI job——配置了 GRAPHFLOW_LLM_SMOKE_KEY secret 时跑一次真 plan 往返并断言 planSource=llm;无 secret 静默跳过。填补"离线测试全绿、真 provider 已坏"的盲区(本机 401 失效 key 正是这类)。

Changed

  • delta 折叠阈值 8MB → 2MB:真实世界 delta 常年挂 1-5MB,每次读取都多付一次 apply;2MB 仍能摊销批量写,同时把读侧开销封顶(重写后最坏 ~80ms)。

Confirmed(非缺陷登记)

  • team serve 的 tools/list 返回空是设计:团队服务器是自定义 graph.* / team.* JSON-RPC 协议面(GraphifyMcpClient 的对端),不是 MCP tools 面。

Tests

  • 新增 tests/m-run-bridge-selfcheck.test.ts(4 用例):占位符回显→桥接且零 LLM 执行调用、健康探测→仍走 llm、selfcheck 无 LLM 配置全绿、坏配置红。真实不可达端点的完整 DELEGATED 形状经 live 双重验证(CLI + 独立脚本)。
  • mock-vs-real 桥接差异根因关闭:此前 vi.mock 下桥接测试只能得到 HUMAN_REVIEW_REQUIRED(无 descriptor/episode)——根因是 mock 工厂只提供 executeRolePrompt,而 orchestrator-phases / state-machine 还从该模块值导入 formatPromptContextEntries,undefined 调用抛错后被 orchestrator 顶层 catch 伪装成 HUMAN_REVIEW。工厂改为 importOriginal 保真其余导出后,mock 下同样得到完整 DELEGATED + attempts=0 + descriptor + episode,断言已恢复为完整形状。(产品代码无缺陷;该模式风险已在测试内注释警示。)
  • README / README.zh:补 graphflow selfcheck 与「LLM 不可用时 plan/run 桥接优先」的用户文档(中英)。

[1.26.0 内轮次 3]

Fixed — 第三轮深挖:任务回显技能门 + delta 合并 394 倍性能修复(虚假问题清零批次)

  • 任务回显永不成为技能:applySkillLearning 现在丢弃与任务文本互含且长度 ≥80% 的"原子"——抽取器对单句任务无法切分时会原样复读任务全文(live:create a tiny file test-tmp.txt with content hi 成了技能名,且来自一次 HUMAN_REVIEW_REQUIRED 的失败 run)。提炼型子短语与 lessons 种子不受影响。
  • pruneLegacyNoiseSkills 扩展名白名单一般化:路径片段正则从固定枚举(ts/js/…)放宽为任意 1-8 字符扩展——.txt 等常见扩展名的垃圾技能此前漏清(live:存量 2 条已清零)。
  • applyGraphStoreDelta 394 倍提速(31.5s → 80ms):delete 分支此前每个 op 都做全量 edges.filter + 重建整个 edgeKeys Set——真实世界的 1,102 条 delete / 35k 边 delta 日志 = 约 7,700 万次字符串操作,令 file 后端每次图读取卡半分钟,直接击穿 MCP graphflow://diagnose / stats 资源的 60s 超时(live:本机全量测试 4 文件 6 用例超时根因)。改为端点邻接索引 + 惰性标记删除 + 末尾一次性压缩;upsert 去重语义保持(删除后再 upsert 同 key 正确重新入列)。

验证(第三轮能力清点,全部 live)

  • team serve:启动 + health(tenant/role/rbac 元数据)+ JSON-RPC-only 面;skill sync export 真实落盘。注:无认证 loopback 下 tools/list 返回 0 工具(团队服务器工具面的暴露策略待确认);Windows 保留端口范围会令某些端口 EACCES(环境限制,非产品缺陷)。
  • 对话脱敏完整复验:真实形状的 JWT Bearer / postgres 连接串 / ghp_ key 全部 [REDACTED:*](此前的"Bearer 未脱敏"疑点撤回——长度门是防误伤设计,短测试 token 不是真实形状)。
  • knowledge extract(4 requirements + 4 provenance 边)、audit --privacy(如实报 0666 与 6 端点)、spawn-receipt / evidence backfill usage 正确、artifact export 8171 节点 / 35266 边(gzip,SHA-256)。

Tests

  • 新增 tests/m-task-echo-skill.test.ts(2 用例):任务回显原子丢弃 + 任意扩展名垃圾清理。

[1.26.0 内轮次 2]

Fixed — 第二轮深挖:配置链诚实性 + 证据分级(live 驱动)

  • 显式坏配置 fail-fast(v1.25.1 已知遗留 sqlite 泄漏的根因):--config 指向存在但损坏的文件(如 Windows 反斜杠路径造成的非法 JSON)此前只 WARN 一句就静默用默认配置继续跑——预算/传输/存储全按默认执行,transport:"file" 工作区因此冒出默认路径的 graphflow-out/graphflow-graph.sqlite(即 1.25.1 登记的句柄泄漏遗留)。现在显式路径损坏直接抛错并给出修复指引(含"用正斜杠"提示);路径尚不存在保持宽容(settings-save 等创建型流程依赖此语义,LoadConfigResult.notFound 区分两种情况)。项目根 graphflow.config.json 损坏同样 fail-fast;global/overlay 层保持宽容 WARN。
  • 两处过度严格校验让最小配置非法:learningPolicy is required 与 graphPolicy.graphStorePath is required for file transport——两者都有完整默认值兜底,却要求显式存在;按文档/示例写精简配置必然校验失败,再叠加上一条静默 fallback 就是"配置永远不生效"的组合拳。两者均改为可选补默认。
  • auto-index 被 dialogue 节点骗过(代码锚点永不出现):graphStoreNeedsIndexing 只看"节点列表非空",store 里只要有一条对话轮/episode 就判定"无需索引"——live 复现:全新 file 工作区 preview 永远只返回 dialogue 锚点。新增 storeHasCodeNodes(File/Symbol/Module 存在才算已索引);修复后 live 验证新增 b.ts 即在下次 preview 自动增量索引并精确命中 symbol 锚点。
  • outcome 证据包被静默丢弃:normalizeOutcomeEvidence 要求 commit AND testCommand 双全,否则整个证据包丢弃——agent 传了 testCommand+testResult:pass 却收到 "no evidence package",partial/unverified 分级形同虚设。改为"任何实质证据字段即构造包",分级交给 verifyOutcomeEvidence(live:unverified + ["diff is empty","missing commit or test command"],提交的证据可见、可审计);OutcomeEvidence.commit/testCommand 类型随之放宽为可选。

验证(第二轮深挖新增 live 证据)

  • MCP 桥接闭环:plan(probe-failed-bridge)→ insight submit×2 → merge → run(诚实 HUMAN_REVIEW + episode 落库)→ report_outcome(证据分级)。
  • R8:working-set 预取真实调用图(8 个可避免读)、challenge 20 条真实外部调用者质询、quote 诚实 insufficient-samples、facts ask 诚实 UNRESOLVED。
  • workbench:plan 播种 4 主题容器、topicId 续接注入 promptLines。
  • skill markdown:垃圾技能 export/import 双向均标 invalid(诚实拒绝)。
  • MCP Streamable HTTP:initialize 1.25.1、tools/list 10 工具(双 Accept 协商)、恶意 Origin 拒绝。

Tests

  • 新增 tests/m-config-evidence-honesty.test.ts(6 用例):坏配置 fail-fast、missing 路径宽容、最小配置合法、证据三级分级。

已知遗留(登记不修)

  • 失败 run(HUMAN_REVIEW_REQUIRED)仍会产出以任务文本命名的垃圾技能(create-a-tiny-file-...)——v1.25.0 的逐 atom 质量门未拦住任务名直录;建议在 applySkillLearning 前按 outcome 过滤或收紧名字门。
  • graphflow team serve / RBAC 未在本轮 live 验证范围。

[1.26.0 内轮次 1]

Fixed — 诚实性收口(live 验收发现的问题批次)

  • plan 来源一等字段(planSource):graphflow_plan 结果新增 planSource(llm | probe-failed-bridge | llm-failed-bridge | no-llm-bridge)+ probe(探测结果)+ degradeReason(降级原因);CLI 文本输出同步打印 source=...; reason=...——桥接计划从此不可能读起来像真模型产出。前置问候探测(v1.25.0 已有)live 验证确实在用:坏 key 下 source=probe-failed-bridge,LLM 计划从未被尝试。
  • provider 适配器真实错误旁路透出:非严格模式适配器故意把失败回显成 [provider:model] <prompt>(弹性设计,保留),但底层原因(401/配额/网络)此前完全不可见。新增 src/routing/provider-errors.ts 旁路记录(无依赖、防循环导入),五个适配器 catch 路径写入;连通性探针的 masked-failure 错误现在附带 last adapter error: openai http 401: ...(live 与 curl 地面真值一致)。
  • diagnose 区分 configured 与 reachable:health= 更名 health(configured)=(配置存在性派生),CLI diagnose / route diagnose 叠加真实 planner/worker 问候探测(5s 有界,probe=planner:FAIL(原因)|worker:FAIL(原因))——撤销的 key 不再显示为健康(live:configured 全 true 而 probe 全 FAIL,原因 401 透出)。
  • memory search 零证据命中过滤:memory search 此前把 Jaccard=0 的 episode 打成 score=0.000 的"命中"(候选扫描拉全量、两路排名均无信号)。现无条件过滤零词面重叠命中("evidence, not judge"——在能透出 cosine 证据之前,0 分命中就是噪声);live:无重叠查询诚实返回 hits=0,有重叠返回 1.000。
  • doctor 只读:首用自举安装器(runFirstUseBootstrap)豁免 doctor / diagnose / audit——只读诊断命令不再有安装副作用(live:删除 marker 后运行 doctor,纯诊断输出、marker 未写入)。
  • AGENTS.md npx 版本漂移警告:npx -y --package=@roarpeng/graphflow 的缓存键不含版本,装过旧版的机器会静默继续服务旧 server(live 实测握手 1.3.3 + 21 个旧命名工具)。推荐配置改为全局安装 + 直接 graphflow-mcp 入口,npx 形式附带验证/清缓存指引。

Tests

  • 新增 tests/m-plan-provenance.test.ts(5 用例):masked 回显→probe-failed-bridge(带真实适配器错误)、探测抛错→原因透出、探测过/分解失败→llm-failed-bridge、全通→llm+final、memory 零证据过滤。

[1.25.1] - 2026-09-20

Fixed — Windows CI 平台适配(v1.24.0 起的 validate-platforms 红灯)

  • privacy-audit 的两个 POSIX mode 用例在 Windows 上 skipIf(chmod 只切只读位,任何文件都读回 0666;Windows 语义已由注入 platform 的用例覆盖)。
  • m109 / skill-markdown-progressive 的临时目录清理改为 Windows 安全(maxRetries+retryDelay+best-effort):运行时遗留的默认路径 sqlite 句柄会令立即 unlink EBUSY。已知遗留:transport:"file" 的工作区内仍会出现默认 graphflow-out/graphflow-graph.sqlite 且句柄未关——连接生命周期泄漏需产品级修复(161e2fe 曾修过一次,v1.24.0 回归)。

[1.25.0] - 2026-09-20

Fixed — 承诺验收全量收口(6 差距 + SoL-Pi 审计,live 实测驱动)

当天对 SKILL.md 承诺做三轮 live 验收(真 deepseek、真 MCP、无 LLM 桥接回路),发现并修复 12 个真实缺陷,全部有 live 复验证据:

  • graphflow_run 桥接 worker 3 连败 → 1 次过:anchor 源码正文(≤8 个/24KB,单文件 6KB 头尾截断)内联进 worker prompt 与 executionDescriptor,附"已内联、勿请求文件"指示;worker 的最终答案以 result 字段外露(工具响应 + episode 记录双持久化,DAG 路径逐节点捕获),失败路径也保留最后输出。
  • plan 模板冒充 LLM → 真 LLM 优先 + 诚实降级:有 LLM 时真调 planTasksLlm/brainstormTaskLlm;前置完整凭证问候探测(apikey+baseUrl+model 真往返;echo 占位/可达但 401 均判不通,4-10ms 桥接不再白等 15s);探测超时 AbortSignal 真取消;模板回退永不自称 final(suggested + agent 桥接工作项 + 失败原因)。planner 默认档 smart→economy(pro 稳定超 15s 预算);分解调用禁用 deepseek tool-loop(其确认信封 {"ok":true,…} 使解析必败)+ 一次立即重试 + brainstorm 解析兼容信封 summary。
  • CJK 低命中双缺陷:低相关触发只认 anchorCount<3(永不达)→ 增加 top-5-by-score 均值 <0.25 维度(relevance 逐锚透传);estimatedRawTokens 从全图模糊匹配改为按交付 anchor 集统计(live:338,869 → 522,垃圾检索诚实报 0% 节省);低命中交付裁剪为仅 relevance>0 的锚(15→2)+ 中文 spine 说明行。
  • assistantReply 无 query 被拒(文档称 optional)→ 合成占位轮落库,幂等重试,回复永不丢弃。
  • 飞轮技能质量:逐 atom 质量门(长度/结构停用词/逐 atom 符号证据/id ≤48 字符/总量 ≤4)+ pruneLegacyNoiseSkills 存量清理(名字即证据:路径片段/裸 token/连接词开头子句/未 seeded composite,hint 刷高的 uses 不豁免)接线进 reportOutcome;live 库存 8 条垃圾清零。
  • SoL-Pi 收口:四机制默认全开语义核实无漂移,4 份 SKILL.md "off by default" 谎言改口(sync 门禁绿);compaction 经济模型修正(重写成本按压缩后摘要计价 + 计入压缩后重放,-1,428,000 → -333,000,信号新增 replayCost/compactCost 与成本构成);Action Fusion 两个盲区修复(中文动词关键词缺失 + 无 plan 桥接描述符不挂 steps → 任务文本子句回退,live:fused:true,"修改 X 并验证"折叠为单一动作)。
  • 桥接描述符源码回退:检索头被元节点占据时,任务文本引用的文件路径直接内联(..//node_modules 防护)。

验证

  • 210 文件 / 1588 用例全绿;tsc/eslint/build/sync-surfaces 门禁全过。
  • live 验收矩阵:英文检索 15 锚全中;plan simple/insight(六帽 + 5-Why 链)真 LLM 产出;run llm 模式 COMPLETED+result+语义验证;无 LLM 桥接回路全通(plan 委派→agent 分解→insight merge→run 描述符→outcome 闭环);artifact 导出→导入 8616 节点回路;release-gate 真实拦截(proven-skills 0<1)。

[1.24.1] - 2026-09-19

Fixed — 收尾审计修复批次(promise-vs-reality 对账的五处缺口)

对外承诺审计(README/ROADMAP/CHANGELOG vs 代码/测试/基准实测)发现五类"承诺没有完全闭环"的缺口,本批全部收口:

  • audit --privacy 0600 从"显示"变"判定":PrivacyAuditFacts 新增 warnings 数组——全局配置存在且 POSIX mode ≠ 0600 时产出违规 finding(含 chmod 修复指引;Windows 无 POSIX 位、mode 不可读、文件不存在均不误报,platform 可注入测试)。此前审计只打印 mode 不做合规判定,本机 ~/.graphflow.config.json 实际 0664(比修复前的 0644 还松)却零报警——README 承诺的"0600 检查"名不副实。CLI 输出把 warnings 逐行附在摘要后。
  • 存量全局配置自动收紧:ensureGlobalGraphFlowConfig 对已存在文件 best-effort chmod 0600(此前只在保存/迁移时收紧,v1.18.5 之前写入的旧文件可永远带错误权限);graphflow install / init 路径即修复,result.message 注明 tightened。
  • R7-a skills-ref 校验门禁收口:新增 extractSkillReferences / validateSkillBundle(src/learning/skill-markdown.ts)——渐进披露指针⇄references/ 文件双向完整性:悬空指针(SKILL.md 指向缺失文件)、孤儿文件(打包了但从未被指向)、越权路径(../、非 references/*.md)均计 invalid;导出 CLI(skill markdown export)已从单文件校验切换到整包校验。ROADMAP R7-a 至此无剩余项。
  • 检索基准再基线(v1.12→v1.24 语料漂移):RETRIEVAL-EVAL-RESULTS.md 停留在 2026-08-04 语料(MRR 0.836 / NDCG@5 0.671),自指语料随 src/ 增长已漂移。连跑两次确认确定性(仅时间戳/耗时不同)后在当前树再生成:Hit@5=100% 保持,MRR=0.779,NDCG@5=0.638;冻结声明目录 flywheel-proof-claims.json、README(×3 处)、docs/flywheel-reproduction.md 按"再测量→声明与报告同步更新"协议一并更新。顺带修正两处既有不一致:README NDCG 0.601 ≠ 目录权威 0.671(同为旧口径漂移);README skill A/B 行"injection 100% / 25.6 tok"与已提交报告(噪声门后 0% hint injection / 100% episode recall / ~15 tok)矛盾。
  • 文档漂移清理:README 中英双语 "Register Skill + MCP" 小节嵌套损坏的 ```bash 代码块(渲染错乱)修复;README "98.2%" 单口径残留改为双臂口径(95.6% / 98.5%);"961 tests / 142 files" 过期计数改 count-free 措辞(evergreen 政策);ROADMAP 头部"最后更新 v1.19.0"更新至当前版本;flywheel-reproduction.md token 行 98.2%(274,434→4,928,旧一代口径)对齐当前双臂。
  • eslint 零警告:coverage/(生成物,已 gitignore)加入 eslint ignores,此前 3 条 unused eslint-disable 警告来自该目录的 vendored 文件。
  • R9 orphan 检查器 dogfood 三修(误报根因):用本批未提交改动自证时发现孤儿检查在真实图上系统性误报——① calls 边未计入(v1.20.0 引入的真 bug):跨文件函数调用在图中记为 calls 边而非 references,countInboundEdges 只数 references,纯函数模块(如 orphan-checker.ts 自己)一律被判 0 入边;现 references+calls 都计(单测用 stub 图回归锁定)。② 带源码扩展名的工具配置文件漏排除:模块头注释承诺"配置文件天然排除"但实现只排除非源码扩展名,eslint.config.js / vitest.config.ts 被误报;补 *.config.{js,cjs,mjs,ts,…} 排除。③ package.json 清单入口未排除:bin / main / module / exports 指向的文件(含 dist→src 布局映射)是图根节点、设计上零入边;src/surfaces/cli/index.ts(bin 入口)被误报;读不到/解析失败 fail-open。修后 dogfood:22 文件脏树 graphflow audit 零 findings。
  • 测试 203→203 文件 / 1498→1512 条全绿:privacy-audit 2→5(非 0600 告警 / 0600 通过 / Windows 跳过)、m86 3→4(ensure 收紧存量文件)、skill-markdown-progressive 5→10(门禁 5 条:导出器自产 bundle 通过 / 指针提取 / 悬空 / 孤儿 / 越权路径)、m96 补 3 条(工具配置排除 / 清单入口排除 / 无 package.json fail-open)、m97 补 2 条(calls 边计数 / 真 孤儿仍报 0)。本机 dogfood:audit --privacy 先报警 0664 → chmod 600 → 复跑零 warning;proof:flywheel 8 项检查全 ok。

[1.24.0] - 2026-09-19

Added — R7 三件套首发:语义召回默认开 + Agent Skills 标准分发 + 可核验隐私

  • R7-b 零配置本地语义召回默认开:graphPolicy.embeddingProvider 默认从 "fnv" 改为 "transformers"(resilient local 路径:优先 Xenova/bge-base-zh-v1.5 本地语义模型,任何失败——缺包/无缓存/超时/加载错误——透明降级 FNV-1a,保持零 Key、零云依赖)。此前语义召回是 opt-in(默认 FNV hash 词袋),开箱质量落后 Continue+Ollama 一档;现在 ONNX 运行时可用即自动走语义召回,"fnv" 显式配置仍可强制纯离线 hash(air-gapped 场景)。embedding-factory.ts 解析顺序不变:legacy openai key > 新开关 > legacy embeddingPolicy > 默认 resilient transformers。tests/embedding-backend.test.ts 更新为断言 transformers 默认健康路径(真实加载模型 305ms)+ fnv 显式 opt-out。
  • R7-a SKILL.md 对齐 agentskills.io 开放标准(导出侧):src/learning/skill-markdown.ts 导出 frontmatter 对齐规范——name 经 toSpecName 转为 1-64 小写连字符 slug(非 ASCII 名称罗马化回退)、必需 description(what+when 语义)、可选 license / compatibility / metadata(display name 经 metadata.graphflow-name 往返保留);validateSkillMarkdown 全量校验导出文件(invalid=0 保证);导出布局改为每 skill 一个目录 + SKILL.md(agentskills.io 约定),平面 .md 导出保留兼容。import 宽容:第三方 spec 文件与旧 display-name 文件均可入,导入一律保守 correctable 不继承 proven 信任。端到端:空工作区 graphflow skill markdown export <path> 优雅降级 files=0; invalid=0。
  • R7-d 隐私威胁模型 + 可执行审计面:新增 docs/threat-model.md(信任边界 / 数据流 / 出网点枚举 / 密钥处理 / 落盘路径 / 剩余风险)+ graphflow audit --privacy [--json](src/audit/checkers/privacy-checker.ts):11 个落盘产物路径存在性、6 个出网端点及触发条件(5 家 LLM provider 仅在配置时触发;HuggingFace Hub 仅首次模型下载且 HF_ENDPOINT 可镜像)、全局配置文件权限(0600 检查)、provider key 布尔值(检测变量名存在,值永不回显)。核心可核验断言:零配置零 Key 时零必需出网(模型首下除外)——把 local-first 从口号变成一条可执行命令。tests/privacy-audit.test.ts 2 条。
  • R7-a 渐进披露 + spec 目录布局(同版补完):skillToSkillMarkdownBundle 把超限 playbook/guidance 拆进 references/guidance-*.md(SKILL.md 保持紧凑指针 + 按需加载索引行,~5000 token 上限进入 validateSkillMarkdown);导出布局定为 agentskills.io 约定的每 skill 一目录 + SKILL.md(目录名 = spec name,去重后缀 -2)。导入侧同步收紧:spec 布局强制父目录名 = skill name(violation 注明 agentskills.io);拥有 SKILL.md 的目录只收 SKILL.md、不再下钻——references/ 文件永不被误当 skill 导入;平面 .md 旧布局保持可导入(本轮还修复了目录扫描静默丢弃平面 .md 的回归)。
  • R7-h 效率证据公开 schema(导出侧):新增 src/learning/efficiency-evidence.ts + graphflow efficiency export → graphflow-out/efficiency-evidence.json:schemaVersion=1 + graphflowVersion + sources(指回 efficiency.json / context-fidelity.json)+ 三源数据合订(配对比较 / 保真采样 / token-savings 累计)+ tokenSavings.boundary 固定边界文本随数发布(packaging ROI ≠ Hit@k ≠ body coverage ≠ lossless fidelity)。诚实门禁:零配对 / 零 qualifying / 能力回归 → gate.allowed=false 且原因内嵌文件——文件总可发布,省 token 声明被门禁(SoL-Pi capability floor 的工件级载体)。
  • token 基准外部语料模式(反自指):benchmarks/run-token-benchmark.ts --corpus=<path> [--queries=a,b,c] 把双臂测量指向另一个仓库(默认通用查询集 EXTERNAL_CORPUS_DEFAULT_QUERIES,可覆盖);RESULTS.md 段落带 Corpus (external, anti-self-referential) 行、机器 JSON inputs.corpus.kind: "external" + 语料根路径。同时脚本改造为可编程入口 runTokenBenchmark({corpusRoot?, resultsPath?}) + import 不再自跑 main(直接执行守卫 import.meta.url === pathToFileURL(argv[1])),并修复 corpus 模式缺 existsSync 导入的崩溃;docs/benchmark-standards.md §2.2 补外部语料条目。
  • Fixed — audit --privacy 双重打印:分支内手动 console.log 与 main() 统一的 formatCliResult(legacyText) 打印路径叠加,summary 输出两遍。现合并为单一 legacyText 返回,JSON 模式交由 main 输出 data。
  • 测试 199→203 文件 / 1480→1498 条全绿:新增 privacy-audit(2 条)与 skill-markdown-interop 4→6(spec frontmatter 往返 + 非法 name 拒绝)、embedding-backend 默认语义断言(9 条);本轮再增 skill-markdown-progressive(5 条:bundle 拆分/指针/常量/目录名/规格布局导入导出往返 + references 防误收)、token-benchmark(4 条:savings 数学/--corpus 解析/通用查询集/外部语料端到端含机器 JSON 出处)、efficiency-evidence(4 条:空态门禁/qualifying 开门/能力回归关门/写盘字段+boundary+gate)。端到端冒烟:audit --privacy 净空/含产物两态正确;空工作区 efficiency export 产出 gated 文件(版本号取自 GraphFlow 包自身而非工作区)。
  • 已知边界:R7-a 剩余 skills-ref 校验门禁(ROADMAP 标注);R7-h 剩余随包发布管线与 mechanism 生命周期联动;独立复现破零仍需外部贡献者(外部语料模式已把工具备好)。语义召回默认开意味着首次查询可能触发一次模型下载(默认缓存于 ~/.cache/huggingface,可经 GRAPHFLOW_EMBEDDING_CACHE_DIR / embeddingPolicy.modelCacheDir 重定向、HF_ENDPOINT 镜像;显式 "fnv" 可完全关闭下载)——已在 threat-model 与 README 标注。

[1.23.2] - 2026-09-19

Fixed — 健壮性双修:文件锁死锁 + 夜间学习崩溃(覆盖率深挖)

  • src/utils/file-lock.ts 陈旧锁死锁:进程在 openSync 成功、writeSync 写入 pid 之前崩溃会留下空 lock 文件;旧逻辑 parseInt("") 得 NaN 永远走不到清理分支,后续所有 acquire 只能空转到 30s 超时(且 withFileLock 直接抛错)。修复:空/非数字 pid 视为崩溃残留,文件年龄超过 10s 宽限窗口(避免与正在写 pid 的创建者竞态)即清理重试;writeSync 失败时不再泄漏 fd、不留半写锁文件。
  • src/learning/learning-events.ts 损坏行崩溃:readFeedbackEvents 对每行裸 JSON.parse,崩溃残留的半行数据会让整个夜间学习任务挂掉。修复:fail-open 跳过无法解析/形状不符的行(写入方仅产 {query, passed, tokenCost, retries},已核实无误伤)。
  • src/routing/provider-executor.ts skillHints 去重:formatPromptWithContext 对重复 skill 提示不去重,重复词句白白消耗 prompt token;现保序去重后再截断。
  • 测试 195→199 文件 / 1435→1480 条全绿:新增 m101(file-lock 8 条:互斥/超时/ESRCH 死进程回收/陈旧空锁回收/新建竞态保护)、m102(learning-events + nightly-trainer 双签名 + reflector 聚类 12 条:损坏行跳过、10MB 轮转、lesson 节点与 improves 边)、m103(5 个 provider 适配器 stub fetch 13 条:无 key 降级、strict 抛错、HTTP 错误、abort 传播、thinking 模式请求体、usage 解析)、m104(provider-executor + deepseek 工具循环 15 条:重试预算、401 不重试、断路器开启短路、中止传播、上下文通道上限、工具结果回填、轮数耗尽强制终答)。

[1.23.1] - 2026-09-18

Fixed — 潜伏自 v1.19.1:完整 install 流程覆盖直连条目

  • legacy sweep 覆盖 bug:buildInstallReport 在 HostAdapter 写完直连条目后,后续的全宿主 npx sweep 再写一遍,把直连覆盖回 npx——zcode 直连在完整 graphflow install 里从未生效过(单测全绿因为都绕过了完整流程;本机端到端复现定位)。修复:legacy sweep 加 preferGlobalInstall: true 与 adapter 一致。端到端验证:完整 install 后条目 = 稳定 node + 全局 server.js + cwd=包根。
  • 新增 docs/postmortem-windows-install.md:v1.18.6→v1.23.1 六次安装故障的根因表 + 八条守则(端到端冒烟非 existsSync / 配置只指向稳定目录 / 启动链优先级 / peer 显式声明 / install 带悬空修复 / 文档标 shell / 干净环境发版前演练 / registry 不可控自保)+ 支持排障速查表。

[1.23.0] - 2026-09-18

Fixed — Windows 双故障根因修复(v1.22.0 回归 + npx peer 丢失)

  • 稳定 runtime 布局 bug(v1.22.0 引入,本次修复):v1.22.0 把 vendor 内容铺到 ~/.graphflow/runtime/ 根,但 launcher 按 __dirname/vendor/graphflow/... 定位 → server not found: ...\runtime\vendor\graphflow\...。现统一镜像扩展布局(runtime/vendor/graphflow/dist/...),且 launcher 增加双布局回退(vendor 布局 → 扁平布局),CLI 稳定探测同时接受两种布局(兼容 v1.22.0 已写入的扁平副本)。
  • npx 缓存 Cannot find module 'ajv'(peer 丢失免疫):ajv-formats(SDK 传递依赖)的 peer ajv 在镜像残缺/npx 解析下会丢失(现场:缓存里 ajv-formats 在、ajv 不在)。现将 ajv + ajv-formats 显式声明为直接依赖——任何解析路径下都强制存在。
  • launcher 冒烟测试(vendored 布局定位 server);m100 更新双布局断言;全量 195 文件 / 1435 测试。

[1.22.1] - 2026-09-18

Fixed — 首次运行自动注册兜底(镜像残缺包 / ignore-scripts 环境的"一条命令"补洞)

Windows 实战:用户从 npm 镜像装到旧版(1.20.1)且包内容残缺(skills 资产缺失、postinstall 静默)——注册从未发生且用户零感知。新增兜底:graphflow 命令首次执行时检测到版本标记文件不存在(postinstall 从未成功跑过)→ 自动执行完整安装注册(含悬空修复)并写入标记,仅此一次;help/version 保持只读不触发。输出中若出现 Skill source not found 会明确提示镜像包不完整并给出官方源重装命令。CI/GRAPHFLOW_SKIP_POSTINSTALL 环境不触发。

[1.22.0] - 2026-09-18

Fixed — VSIX 安装同样一键完成,且条目永不因升级悬空(三平台)

「再好的项目,安装不上也是扯淡」——两种安装方式现在都是一条命令全自动,且写入的 MCP 条目在任何升级路径下都不会悬空:

  • 稳定运行时目录 ~/.graphflow/runtime/:VSIX 激活时把自带 runtime + launcher 同步到该稳定目录(IDE 升级会删除带版本号的扩展目录——历史上所有 Cannot find module mcp-launcher.cjs 悬空报告的根源),MCP 条目全部指向稳定路径;每次激活刷新副本,升级 = 自动重写。同步失败 fail-open 回退扩展副本,下次激活重试。
  • CLI 直连候选链:preferGlobalInstall 解析顺序变为 npm 全局包 → 稳定 runtime → npx 回退——只装 VSIX(没装 npm 包)的用户经 CLI 重装时也能拿到直连条目而非 npx。
  • 三平台保证:全部路径经 os.homedir() + path.join;fs.cpSync 跨平台复制;由既有 ubuntu(node20/22)/windows/macos CI 矩阵验证。npm 路径(v1.21.0 的 postinstall 全自动)不变。
  • 测试 m100(3 条):稳定根路径(隔离 HOME)、探测命中/未同步 fail-open、直连候选链永不悬空(直连条目引用文件必须存在)。

[1.21.0] - 2026-09-18

Fixed — 一条命令承诺:npm install -g @roarpeng/graphflow = 安装 + 注册 + 检测 + 修复

Windows 实战暴露的链路缺陷:postinstall 全局安装时走的是旧的手工组装流程(只装部分宿主 + 强制 npx 条目),既不覆盖 20 宿主三件套也不做全局直连,更不会修复悬空条目——用户一条命令后仍需手动折腾。彻底收敛:

  • postinstall 全局分支改为调用完整 CLI install(单一事实来源):20 宿主 HostAdapter 三件套注册 + 全局安装直连条目 + 悬空修复 + doctor 摘要,一条命令全部完成;本地安装/CI 行为不变。
  • 悬空 MCP 条目检测 + 自动修复:新增 repairDanglingGraphflowMcpEntries——扫描所有检测宿主的 graphflow 条目,command/args 中的绝对路径指向已不存在的文件(典型:IDE 升级删除了旧扩展目录的 mcp-launcher.cjs)→ graphflow install 开头自动重写为当前最佳形态(全局直连优先)。install 输出新增 [REPAIRED] 行。
  • doctor 悬空可见性:MCP 检查对条目启动目标做存在性校验,悬空标 missing (dangling entry) 并给出死路径与修复指引(graphflow install 一键重写);覆盖 legacy 与 HostAdapter 两条检查路径。
  • 测试 m99(4 条):死扩展 launcher 检测 + doctor 标记、健康条目不误报、修复重写为可启动形态、无悬空时 no-op。

[1.20.1] - 2026-09-16

Docs — R9/R9 文档收口

  • 新增 docs/closing-audit.md:R9 承诺账本 + 收尾审计完整文档——三个触点(CLI / outcome 前置 / 跨会话提醒)、内置检查器矩阵、graphflow.audit.json 声明式规则示例(驱动加载 / 容器注入)、基线策略、诚实边界。
  • README(英文)core capabilities 新增 R9 与 R8 两行 + CLI quick reference 补 challenge / audit 两行;README(中文)「本版要点」升至 v1.20 并新增 R9/R8 行。

[1.20.0] - 2026-09-15

Added — R9 承诺账本 + 收尾审计(Promise Ledger / Closing Audit)

针对 dogfood 实证痛点:agent 长任务"干着干着就忘了"——新依赖忘安装、新文件忘接线/注入容器、驱动忘加载、文档忘更新。问题本质是承诺没有账本:义务在任务中段产生、收尾时无人清点。R9 从可观测副作用登记义务并在三个触点对账(不猜意图、只对账事实、质询不阻断):

  • 检查器矩阵:依赖 lock 一致性(npm v1/v3、pip+poetry/Pipfile.lock)、孤儿文件接线(图 inbound 边数为零即未接线)、文档一致性(CLI 变更 vs README、版本徽章 vs package.json)。
  • 声明式规则引擎:容器引用/驱动加载等项目特定义务由 graphflow.audit.json 配置(filePattern + mustBeReferencedBy glob),内置零项目类型假设;glob 引擎零依赖自研(**/*/?/{a,b})。
  • 基线策略:默认 git 未提交工作区(agent 会话的天然收尾窗口);--since <ref> 扩大;无 git 降级为纯状态检查。
  • graphflow audit CLI + outcome 前置审计:report_outcome success 前自动跑审计——默认温和(findings 附进 episode 证据并提醒);GRAPHFLOW_AUDIT_STRICT=1 严格模式拒绝在有未决项时上报成功。
  • 跨会话提醒:会话结束未决项写入图上承诺账本(promise-ledger:<sessionId>);下次会话首次 graphflow_context 附带"上次会话有 N 项未收尾";审计清零自动 resolve。

[1.19.2] - 2026-09-15

Fixed — 跨平台加固(Windows / Linux / macOS)

  • 全局安装探测容错(v1.19.1 引入路径的加固):npm root -g 的 stdout 在 Windows 上可能带 UTF-8 BOM、CRLF 或混入 banner 输出——原 trim() 实现会被污染导致探测失败(安全回退 npx 但直连失效)。现剥 BOM + 按 CRLF/LF 切分 + 取最后一个非空行(npm 的路径输出在 stdout 末尾)。测试覆盖 BOM / banner 前置 / 空行三种污染形态。
  • Windows 平台门控直连验证:新增 win32-only 测试——真实全局安装存在时,注入的直连条目 command 必须是磁盘上存在的 node 二进制(短路径形态允许或裸 node)、args[0] 必须是存在的全局 server.js。由 validate-platforms (windows-latest) CI 矩阵执行。
  • 既有跨平台矩阵确认覆盖:CI 已在 ubuntu(node 20/22) / windows-latest / macos-latest 三平台跑全量测试;直连条目的空格路径加固(短路径化 / 裸 node 回退)复用 sanitizeMcpServerNodeForWindowsClients 既有逻辑并有 m63 win32 门控测试。

[1.19.1] - 2026-09-14

Fixed

  • Windows ZCode「启动中」卡死(npx 冷启动超时):npx 条目首次需下载完整包及原生依赖(onnxruntime-node,Windows 上数百 MB),120s 连接超时内常无法完成。install 现对 ZCode 启用 preferGlobalInstall:探测到全局安装(npm root -g 下的 @roarpeng/graphflow/dist/surfaces/mcp/server.js)时自动写入 node + server.js 直连条目(cwd=包根,秒级启动、无网络依赖;复用既有 node-bundled 形状与 Windows 空格路径加固);无全局安装回退现行 npx 条目。探测失败(无 npm/路径不存在/空输出)一律 fail-open 回退。README(中英)注册小节补充 Windows 首启慢的说明与解法。测试 m87 扩至 6 条(npx 回退锁定 / 直连条目 / 探测函数三态 fail-open / adapter 三件套)。

[1.19.0] - 2026-09-14

Added — R8「省钱与靠谱双主线」(五模块齐发)

核心洞察:agent 最大的 token 黑洞是"找东西的探索轮次"(每轮探索都是带全量历史的完整模型调用——压缩 prompt 省加法,消灭探索轮省乘法);可靠性最便宜的形态是不跑测试的质量门。五项全部落地:

  • R8-1 Working set 预取:src/graph/working-set.ts——以 touched 文件为活跃工作集,沿 references/calls 边扩展 caller/callee/test-for 相关文件生成预取包;诚实计数 potentiallyAvoidedReads,不乘臆测系数(tests/m89)。
  • R8-2 图 diff 质询清单:src/graph/diff-challenge.ts + graphflow challenge --files——改完代码后图谱生成三类质询(external-caller / requirement-link / deleted-symbol)还给 agent 回答;近零成本质量门,激活 Engineering KG 存量;不声称检测签名变更,只质询图上可证事实(tests/m90)。
  • R8-3 subagent 出生证:src/graph/spawn-receipt.ts + graphflow spawn-receipt——父 agent 发紧凑收据(任务 + 图锚点 + 取回指令)替代背景文本复制;subagent 用 graphflow_context 按需展开(tests/m91)。
  • R8-4 时点事实查询:src/graph/temporal-facts.ts + graphflow facts ask——对话图 bi-temporal 语义产品化:按 asOf 返回仍有效结论(effective)与已被取代历史(supersededAtPoint);白领"事实漂移"防线(tests/m92)。
  • R8-5 任务预算报价:src/learning/task-quote.ts + graphflow quote——效率历史变事前决策工具;样本不足 confidence=insufficient-samples + 保守折半 + advisory 明说,绝不编造(tests/m93)。

[1.18.8] - 2026-09-14

Added

  • R6 收官:efficiency for efficiency(效率反哺搜索,SoL-Pi 闭环最后一块):新增 src/learning/efficiency-reinvest.ts + graphflow mechanism reinvest [--apply]。合格配对节省(仅 qualifying——被 no-efficiency-gain / 能力回退取消资格的比较不得为其验证搜索出资)按 efficiencyPolicy.reinvest.ratio(默认 0.5,maxBudgetTokens 默认 200k)折算为机制试验预算;收据指纹记账于 graphflow-out/efficiency-reinvest.json(每条 efficiency.json 记录只出资一次,重复 apply 幂等,损坏账本 fail-open);输出下一步试验建议(frozen→held-out 优先、in-trajectory/proposed 次之,终态机制不再建议),试验执行仍归操作者/宿主(advisory 边界不变)。默认开启,可经设置页/配置关闭。测试 tests/m88-efficiency-reinvest.test.ts(7 条:预算推导/上限/disabled/建议排序/幂等 apply/dry-run 零写入/账本 fail-open)。至此 SoL-Pi 借鉴(R6)P0/P1/P2 全部 ✅。

[1.18.7] - 2026-09-14

Fixed

  • MCP stdio 握手时序(严格客户端启动失败):stdio 服务器曾在 initialize 响应之前把 notifications/message(文件监视器启动日志)写到 stdout,严格按序等待响应的客户端(实测 ZCode)握手失败。sendLogNotification / sendProgress 现在以 SDK oninitialized 回调(客户端 initialized 通知到达)为门,握手完成前一律抑制,日志仅走 stderr。端到端实测:stdout 首行即 initialize 响应,initialized → tools/list 全链路干净。
  • 测试不再重写/删除真实宿主配置与技能:buildInstallReport 会重写所有检测到的宿主配置、uninstallAllSkillsAndRules 会扫除真实 HOME 下全部技能目录——此前 4 个 install 测试与 1 个 uninstall 测试未隔离 HOME,本机跑一次全量测试即静默撤销手工修复的 ~/.zcode/cli/config.json 并删除 ~/.zcode/skills/graphflow/。五个测试全部改用临时 HOME/APPDATA 隔离(uninstall 测试跑后以 md5 校验真实技能完好)。

Added

  • ROADMAP R7 演化方向(2026-09 横向调研版):基于对云端记忆 API(Mem0/Zep-Graphiti/Letta)、索引派(codebase-memory-mcp/Continue+Ollama)、反索引派(Cline)、Agent Skills 开放标准生态(~40 平台、AGENTS.md 在野 57k+)与**效率机制赛道(NVIDIA SoL-Pi:绑 Pi 单宿主)**的横向对比,确定演化主线:R7-a 学习飞轮产物以标准 Agent Skills 包分发、R7-b 零配置本地语义召回默认开、R7-c 跨仓库/monorepo 图谱、R7-d 隐私威胁模型 + 审计面、R7-e 业界记忆基准接入、R7-f 团队记忆企业化。(发布后补充:R7-g 效率机制投影面宿主泛化、R7-h 效率证据可审计公开格式——补入第五赛道调研后新增,见 ROADMAP。)

[1.18.6] - 2026-09-14

Added

  • ZCode 宿主支持:新增 zcode HostAdapter(capabilities: mcp-stdio + skills + rules)。graphflow install 现在会检测 ~/.zcode 并完成三件事:(1) 向 ~/.zcode/cli/config.json 的 mcp.servers(ZCode 嵌套结构,新增 configFormat: "zcode")注入 graphflow stdio MCP 服务器;(2) 将 skills/graphflow/SKILL.md 复制到 ~/.zcode/skills/graphflow/;(3) 向 ~/.zcode/AGENTS.md 写入受管指令块(append-with-markers,不动用户内容)。工作区级 .zcode/config.json 目标同步支持,doctor / uninstall 均已覆盖(注入/检测/移除均为幂等操作;卸载时清理 mcp.servers 条目但保留其它服务器与顶层键)。新增测试 tests/m87-zcode-host.test.ts(3 条:注册表形状 / 安装+状态+幂等 / 预存配置保留)。

[1.18.5] - 2026-09-13

Added

  • DSH 插件市场收录合规(按 STANDARD):package.json 的 dsh 块补齐显式声明(plugin: true / kind: "server",bundle.patch → cordis.patch.yml,市场据此判为 cordis-plugin);补齐规范关键词(dsh、dsh-plugins、deepseek-harness-plugin、cordis、cordis-plugin);新增 disclosure 披露块(D1 云端依赖 + 端点、D3 凭据处理、D4 权限声明,另含 offline_mode/jurisdiction)——本地索引/压缩/召回/图存储全离线,仅配置了 LLM provider 时才访问云端端点。
  • README(中英):新增 DSH 徽章、插件市场一键安装与 dsh plugin --profile web add github:Roarpeng/GraphFlow 两种路径,并按 STANDARD §6.4 明确「只选一条注册路径」(市场/dsh plugin add 与 npx @roarpeng/graphflow install 的 home overlay 不要叠加,否则重复加载);披露摘要与市场类型说明(源码型 → 安装时询问并执行构建)。

Security

  • 全局配置以 0600 写入:~/.graphflow.config.json 可能保存 providers.<name>.apiKey,现在创建/迁移/通过设置面板保存时都写为属主可读写,并会收紧已存在文件的权限(此前是 0600 &~ umask = 0644,同机其他用户可读)。这也是 disclosure 中 api_keys[].storage: "file-0600" 的依据;测试 tests/m86-config-file-mode.test.ts(新增 3 条)在 POSIX 上断言模式位。

[1.18.4] - 2026-09-13

Fixed

  • Windows 平台验证失败(v1.18.3 的回归):1.18.3 让 Windows CI 的 Test 步骤失败——(1) m83 测试用 "/" 拼相对路径,在 Windows 上拿到绝对路径(已改为 path.relative + 正斜杠归一化);(2) 解析 worker 池在 TypeScript 源码(tsx/vitest)下用 --import tsx 启动 worker,Windows 上启动开销大且不稳定,拖慢到超时。现在 worker 池只在编译产物(file-parse-worker.js)下启用,源码/测试/tsx 运行一律走进程内解析(同一图,确定性);worker 池仍由 m84 的注入式调度测试与 dist 端到端实测覆盖。
  • worker 池门槛改为按规模:线程切换有固定成本(worker 启动 ≈4×150ms + 结果克隆),实测 1.2k 小文件仅打平、5.5k 文件 / 50MB 源码 1.68×。门槛改为 文件数 ≥ 200 且总字节 ≥ 1MB(graphPolicy.indexWorkers 显式指定时同样遵守该门槛)。
  • git ls-files 扫描加 -c core.quotepath=false,避免非 ASCII 路径被 C 风格转义后与真实路径不匹配。

说明:v1.18.3 的 npm 包已发布成功,但 Marketplace 发布被 Windows 验证阻塞(publish-marketplace 依赖 validate,后者失败即跳过),因此以 1.18.4 重新发布;功能改动与 v1.18.3 相同。

[1.18.3] - 2026-09-13

Performance

  • 大型项目索引提速 3.7–4×(实测 ragflow:5,492 文件 / 78,160 符号):首建 34.7–37.6s → 9.5s(4 workers)/ 16.2s(单线程),图存储 855–860MB → 193MB。三处改动叠加:
    • reference 边预算:跳过"定义文件数 > N"的通用名(DF 停用词,graphPolicy.referenceEdgeMaxDefinitionFiles,默认 10;0=不限)并限制每文件引用边数(referenceEdgeMaxPerFile,默认 500)。实测 575 万 → 99 万条 references(−83%);此前 1.87 万个名字贡献了 575 万条边,__init__ 一个名字就有 46.9 万条(定义于 414 个文件)。质量有验证:ci-release-evidence 三个 golden 探针 recall 保持 1.00,fidelity-anchor-recall 88 → 91。
    • worker 池并行解析(worker_threads,默认 cores−1、上限 8;graphPolicy.indexWorkers、GRAPHFLOW_INDEX_WORKERS=0 可关):解析阶段 fan-out,缓存/剪枝/写库仍在主线程;实测同仓库 15.95s → 9.50s(1.68×),且图逐项一致(91,680 节点 / 1,113,739 边 / 989,218 refs)。worker 创建或单任务失败都会自动降级为进程内解析,绝不让索引失败。
    • 索引扫描更聪明:尊重 .gitignore(git ls-files --cached --others --exclude-standard,精确语义;graphPolicy.respectGitIgnore: false 可关,非 git 仓库自动回退目录遍历),并跳过 lockfile / minified bundle / source map / 生成代码(*_pb2.py、*.pb.go、*.g.dart、*.generated.* …)。
  • 增量保存不再重写整库:file 传输新增追加式 delta 段(graphflow-graph.json.delta.jsonl)+ 阈值压缩(默认 8MB)。仅当 base 存储 ≥ 4MB 才启用,小/中型项目保持"单个自包含 JSON、字节级不变"的历史布局。实测 11.2MB 图库:单文件保存 0.27s 且 base 未被重写(delta 3.5KB),无变更重跑 0.04s;vacuum() 与重建会把 delta 压缩回单文件。所有内部读取路径(loadGraphStore 等)都会合并 base + delta。
  • 机械优化(消除 O(store) 放大):upsertGraph() 让节点+边一次读写(此前 upsertNodes + upsertEdges = 两次整库重写);空批次完全不触碰存储(watcher 空跑不再重写);边键集合缓存(增量写入不再每次重建百万级 key 集合);批量索引的 per-file prune 合并为一次批量删除(此前每个文件一次整库重写 —— 大型仓库增量索引会因此卡死;实测已修复:原先 >120s 卡死 → 13.1s)。

Added

  • 配置:graphPolicy.respectGitIgnore(默认 true)、referenceEdgeMaxDefinitionFiles(默认 10)、referenceEdgeMaxPerFile(默认 500)、indexWorkers(默认 auto;0 = 关闭 worker 池)。
  • 测试:m83-index-scan-budget(DF 过滤、每文件上限、增量路径同预算、生成/锁文件识别、真实 git 仓库 .gitignore 生效与可关闭)、m84-index-worker-pool(worker 计数/门槛/入口解析、注入式调度与容错、共享解析核心)、m85-incremental-store-delta(追加不重写 base、阈值压缩、删除走 delta、vacuum、截断行容错、重建清理)、m82 扩到 10 条。

[1.18.2] - 2026-09-13

Fixed

  • VS Code 扩展「GraphFlow MCP 自动安装失败: Invalid string length」(已完整复现并定位):扩展的 MCP 自动安装(runMcpBootstrap)会调用 getSettingsPanelStatus(),而它经 inspectGraph 自动索引整个工作区;文件传输随后把整张图当作一个 JSON 字符串序列化(JSON.stringify(store, null, 2))。对文档密集型仓库,索引器会产出约 590 万条 references 边(实测 ragflow:5,939,794 边 / 91,684 节点),pretty-print 后的 payload 超过 V8 单字符串上限(64 位约 512 MB)→ JSON.stringify 抛 RangeError: Invalid string length,用户看到的就是安装失败(且图存储长期只有节点、edges: 0,因为边写入每次都死在这一步)。修复分四层:
    • 面板/状态路径改为只读:inspectGraph 新增 autoIndex(默认 true,CLI 行为不变),getSettingsPanelStatus() 传 false —— “安装 MCP”/面板刷新不再建图(实测:打开大型仓库时从"索引到崩溃"变为 12ms 返回,且不写盘);建图仍由显式命令与激活后的自动索引负责。
    • 写盘不再物化单个巨串:小图(≤20k 元素)仍美观打印;大图改为紧凑 + 分块写入(4MB 缓冲区,逐元素序列化),写入前不再构造完整 payload。实测同一仓库 901 MB 图存储写入成功。
    • 新增分块读取器(src/graph/graph-store-json-chunks.ts):超过单字符串上限的 store 逐元素增量解析,跨任意 chunk 边界可恢复(含跨边界的多字节 UTF-8,截断文档报错而非半读)。实测 901 MB / 5,939,794 边 20 秒读完;readFileGraphStore 与 GraphifyFileClient 均自动路由到它。
    • 扩展启动步骤互相隔离:安装、探测、模型指南、面板统计各自捕获异常;面板统计失败不再被报成「MCP 安装失败」,失败时同时把 err.stack 写入 GraphFlow 输出通道(此前只有一行 err.message,本次 bug 正是因此难以定位)。

Added

  • tests/m82-graph-store-write-safety.test.ts:锁定四条保证——面板状态只读(不建图、不写盘)、inspectGraph 默认仍建图(CLI 行为不回退)、autoIndex:false 不触碰存储、小图美观打印 / 大图紧凑分块且可往返解析、超限存储走分块读取、跨 chunk 边界(含 1 字符 chunk 与多字节字符)解析一致、截断文档被拒绝。

[1.18.1] - 2026-09-12

Fixed

  • 跨宿主 unsafe workspace root 加固(dsh / opencode glue):dsh glue 的工作区此前只读 payload/agent/session.cwd,dsh 从 $HOME 启动时宿主进程 cwd 胜出,首轮 hint 因此把 rootDir=/home/<user> 喂给模型(MCP 硬拒 → 整次调用失败)。现在优先取会话头 session.header.cwd(含 subagent/* 直接传入的裸 session 对象),遇到 home/AppData/未展开占位符会跳过;hint 自身也不再输出任何 unsafe rootDir——无法确定时直接省略,由服务端按 GRAPHFLOW_WORKSPACE_ROOT / 发现逻辑兜底。opencode 插件同理:改用宿主传入的 { directory, worktree } 作为 CLI 子进程 cwd,不再继承宿主进程 cwd(此前在项目外启动会把回复记到错误工作区,被拒后静默丢弃)。
  • MCP 边界:unsafe workspace root 变成可恢复错误,不再 -32603:显式 rootDir 或 cwd 落在 home/AppData 时,工具调用返回 isError: true 的结果,附 server cwd、当前 GRAPHFLOW_WORKSPACE_ROOT 与「改用项目绝对路径重试」的指引;此前作为协议错误抛出,整次调用对模型不可恢复。安全策略未放宽:仍然拒绝 home/AppData,只是拒绝方式可操作。
  • 新增 CLAUDE_PROJECT_DIR 工作区发现提示:Claude Code ≥2.1.157 会把它注入 MCP stdio 子进程;从家目录启动的 Claude Code 现在能自动解析出会话项目,而不是让每个工具调用失败(unsafe 取值仍会被跳过)。
  • sync:surfaces 镜像映射错误:此前把 Trae 规则同时写进 .agent/rules(属 Antigravity)与 .claude/rules(属 Claude Code),sync:surfaces --check 在 v1.18.0 上一直是 DIRTY;现按安装器真实来源映射,并补上 .cursor/rules、.trae/.agent skills、.windsurfrules、AGENTS.md,--check 通过。
  • 规则/技能写入 rootDir 契约:4 个规则模板、规范 SKILL.md、根 CLAUDE.md/AGENTS.md 与托管指令块(GEMINI.md、.windsurfrules 等)统一说明——rootDir 必须是项目绝对路径,禁止 home/AppData/未展开 ${workspaceFolder};遇到 unsafe workspace root 就省略 rootDir 重试。
  • 新增跨宿主安装守卫测试(tests/m81-host-install-workspace-guard.test.ts):沙箱 HOME 下安装全部已迁移宿主,断言任何写出的 cwd / GRAPHFLOW_WORKSPACE_ROOT 都不会指向安装者 cwd、HOME、AppData 或沙箱外路径(并校验 dsh 的 MCP 行保持 !!js process.cwd() 动态形式)。

Added

  • 插件 ON/OFF 配对效率 A/B harness:新增 benchmarks/plugin-ab-lib.ts、benchmark:plugin-ab(DSH 插件开/关双臂,沿用 SoL-Pi 配对双臂 + 能力地板判据)与 benchmark:real-task-ab(离线、确定性、免 API Key 的真实任务「起步 token 成本」对比),并附设计文档 docs/efficiency-ab-test-design.md 与实测结果 benchmarks/REAL-TASK-AB-RESULTS.md。
  • graphflow efficiency [show|reset] CLI:直接查看配对效率报告与能力地板判定(release-gate 读取同一份数据)。
  • 机制试验写入效率报告:recordMechanismTrial 新增 onComparison sink,配合新的 appendEfficiencyRecord() 把已评估的记录原样落进 graphflow-out/efficiency.json(不再被默认容差重算),机制 trial 因此对 release-gate 的能力地板可见,而不只存在于 mechanism Decision 节点里。

[1.18.0] - 2026-09-12

Added

  • 统一效率机制开关 efficiencyPolicy(SoL-Pi 借鉴,P0 收口):新增顶层配置 efficiencyPolicy.{observations,contextPressure,actionFusion},默认全开(最佳配置);可在 graphflow-settings 页逐项关闭,或在此显式设 false。解析集中在纯函数 src/config/resolve.ts 的 resolveEfficiencyPolicy;数值非法回退安全默认,reduce.strategy="llm" 缺 provider+model 时降级为 fingerprint。显式调用(graphflow_context 传 content/handle、reduce:true)属于明确意图,不受开关限制。

  • GF-3 观测压力预算 + 压缩建议(Online Context Compact analog):graphflow_context 新增 contextPressure 入参(usedTokens/maxTokens/pressureRatio/remainingTurnsEstimate)。启用后打包预算由 deriveAdaptiveBudget("auto", observed) 决定(回退默认预算,绝不编造压力),结果新增 contextPressure 块:effectiveMaxContextTokens + 可选 compaction 经济性建议(cacheWriteReadRatio 默认 12.5,minSavingRatio 默认 0.2)。启用时绕过 context 缓存,避免跨压力复用陈旧预算。

  • GF-4 融合动作步骤(Action Fusion analog):graphflow_run bridge 模式的 executionDescriptor 新增 steps(fused: true)——plan 中 edit/write 紧跟的 run/test/validate 节点合并为一个动作单元(含 command 与 dependsOn),供宿主在一次调用内执行;执行权仍归宿主,GraphFlow 只做计划与证据。

  • GF-2 观测句柄策略来自配置:graphflow_context 的 pack/recall/reduce 现按 efficiencyPolicy.observations 解析阈值、head/tail、TTL、脱敏与 reducer 路由(解析失败 fail-open 到内置默认)。SKILL.md 新增 Workflow 8,写明「归档大输出 → 保留 handle → 按页/区间精确召回 → reduce 出逐字核验收据」协议。

  • P1 配对效率报告 + 能力地板(SoL-Pi capability floor):新增 src/learning/efficiency-report.ts,按「基线臂 vs 打包臂」记录同一任务的 tokens/turns/toolCalls/responseCount/score 配对对比,落盘 graphflow-out/efficiency.json。token 未改善、或分数/响应数劣化超容差即判不合格——response-count 臂专门证明节省不是「少干活」。提供 evaluateEfficiencyFloor / evaluateFidelityFloor 供治理门禁使用。

  • P2 机制自动研究回路(SoL-Pi auto-research 方法论):新增 src/learning/mechanism-research.ts,把「候选机制」作为节点(mechanism:)走 proposed → in-trajectory → frozen → held-out → admitted|rejected。三条规则代码强制:准入必须有合格的 held-out 试验;冻结后不再接受 in-trajectory 试验(held-out 隔离);终态不再接受试验。新增 graphflow mechanism propose|trial|freeze|admit|reject|list CLI,并在 graphflow diagnose 暴露 mechanisms 汇总。

  • P1 工具结果投影(自动省 context)落地 dsh:dsh 具备 surface-replace 原语(与原生 dsh-compaction-tool-result-pruner 同一 API),dsh/plugin.mjs 新增观察投影:在 session/event 的 tool/result 上先把原文归档到观察库(新增 CLI graphflow observe pack|recall),再用 handle 投影替换模型可见的表面节点(保留首尾 + 召回指令),并带 surfaceOp replace + sourceEventSeqs。默认开启(GRAPHFLOW_D_DSH_PROJECTION=0 关闭),全程 fail-open(禁用/低于阈值/打包失败/表面 API 缺失/append 抛错都退回原文)。与原生 pruner 的本质差别:原文精确可召回且逐字核验,而不是有损 marker。src/observations/host-hook.ts 的 projectToolResult 为进程内宿主的同一契约;HOSTS_WITH_TOOL_RESULT_PROJECTION 现为 ["deepseek-harness"]。其余宿主(opencode/Cursor/Codex/Gemini)暂无结果重写面,继续走 SKILL.md 显式 handle 协议。

Fixed

  • toContextPressure 不再伪造 token:仅提供 maxTokens(或仅 usedTokens)时此前会以默认 0 补齐并得出可用的压力比;现在要求「显式 ratio」或「used+max 双双有限且 max>0」,否则返回 undefined。
  • 远端 reducer 路由不得静默降级:reduceObservation 在 strategy="llm" 且未传入 reducer 时返回 reducer-route-missing 的 fail-open 摘录,而不是悄悄退回本地 fingerprint 选择器;配置解析层同时把缺 provider/model 的 llm 策略降级为 fingerprint。

Changed

  • governance release-gate 新增能力地板阈值(均可选,保持向后兼容):--min-efficiency-qualifying、--max-capability-regressions(默认 0)、--min-anchor-recall-percent、--min-body-coverage-percent。锚点召回/正文覆盖仅在存在样本时检查。

Documentation

  • 新增 docs/efficiency-mechanisms.md:SoL-Pi 借鉴的配置、四机制映射、效率/能力地板、机制自动研究 CLI、投影边界,以及「不要做」的负面清单。

[1.17.1] - 2026-09-10

Fixed

  • 插件说明页版本停滞两个 minor:vscode-extension/README.md 就是发布到 VS Code Marketplace 与 Open VSX 的说明页正文(随 VSIX 打包并对外展示),却仍停留在 1.15.3——含 graphflow-1.15.3.vsix 安装命令、npx @roarpeng/graphflow@1.15.3 install、"升级到 1.15.3+",以及一整节 "v1.15.x 要点"。v1.16.0 与 v1.17.0 两次发版都没有更新它,用户看到的说明页因此落后两个 minor。已重写为 1.17.x 内容,并补上此前缺失的 v1.16.0(HostAdapter 全宿主、编排层拆分)与 v1.17.0(双口径 token 节省、对话图接入上下文引擎、对话密钥脱敏、provisional 准入)要点。
  • 根 README 章节标题滞后:README.md 的 ## Core capabilities (v1.15+) 与 README.zh.md 的 ## 本版要点(v1.15) 更新为 v1.17,并补上 v1.17 的能力行(打包后 token 记账、双口径节省、对话图注入位置与密钥脱敏)。

Tests

  • tests/m48-doc-code-consistency.test.ts 新增守卫,堵住这次漂移的根因——插件说明页此前完全不在文档一致性检查范围内:
    • vscode-extension/README.md 纳入 DOC_FILES(工具名一致性 + UTF-8 校验);
    • 新增 README_SURFACES 断言所有面向用户的 README(根 EN / 根 ZH / 扩展)都引用当前版本;
    • 断言插件说明页里每个 graphflow-<version>.vsix 文件名与 @roarpeng/graphflow@<version> 都等于当前版本——此前正是"这个页面的版本号没人管",用户才会照着 1.15.3 的命令去装。

[1.17.0] - 2026-09-09

Added

  • Token 节省的现实对照臂:benchmarks/run-token-benchmark.ts 新增 Arm B baselineTopKFilesFullText——把同一排序器的 top-K 锚点解析到真实源文件并按全文计数(每文件上限 1500 行,--anchor-top-k=N 可调)。原 Arm A 更名 baselineGrepTopFilesFullText 并明确标注 "upper bound by construction"。实测:Arm A 410,725 → 6,044(98.5%);Arm B 136,265 → 6,044(95.6%)。每查询的 resolvedFiles 落盘可复算。Arm B 无法自我膨胀——锚点越小它的节省率越低。
  • 打包后 token 记账:src/surfaces/cli/runtime/graph.ts 新增 estimateSummaryLinesTokens / estimateUnbudgetedPayloadTokens / withPostPackageAccounting。对话召回行、workbench promptLines、对话主线 promptLines 三处「打包后前插」现全部计入 tokenEstimate 与 budgetUsedPercent;dialogueHits 作为不占 L1–L3 配额的负载单独报在 unbudgetedTokens,并新增 accountedTokens(= 已预算 + 未预算)。estimatedSavingsPercent 改为对真实总量计算,graphflow-out/token-savings.json 的 ROI 不再系统性低报。
  • 技能准入冷启动层:admitSkillToProvisional(src/learning/skill-admission.ts)——proven 仍严格要求 successCount >= 2 的去重 pass episode;新增的 provisional 层要求名字像项目符号或至少 1 个成功 episode,且无条件否决结构性噪声(空名 / 纯停用词 / readme+update 融合)。文档明示:provisional 只是 hint,绝不作为 proven 呈现、导出或同步。
  • 对话写入边界密钥脱敏:redactSecrets(src/learning/dialogue-thread.ts)在写盘前清洗 userQuery / assistantReply / 派生 title+summary / 序列化的 record metadata / agent trace label。覆盖 PEM 私钥、含凭据的连接串(postgres/mysql/mongodb/redis/amqp/mssql)、Bearer 与 JWT、各家 API key 形态(sk-/ghp_/github_pat_/glpat-/xox[baprs]-/AKIA/AIza…)、以及 KEY=value 形式的凭据键。标记稳定可调试([REDACTED:api-key] 等),幂等,默认开启,GRAPHFLOW_DIALOGUE_REDACT=0 可关闭(附团队同步风险警告)。误伤保护有 10 组反例测试(散文、路径、无凭据 URL、版本号、process.env.X 等原样通过)。

Fixed

  • L3 对话打包在生产路径是死代码:injectDialogueTurns 此前只被 buildLayeredContextPackage 调用,而生产路径 previewContext(MCP graphflow_context)走的是 buildEnhancedContextPackage——于是 v1.14.0 的头号能力「对话图进入上下文引擎 L3」对用户从未生效,而 5 个测试只覆盖非生产打包器所以 CI 全绿。现抽出共享阶段 injectL3Stage(src/graph/context-package-core.ts):治理技能/pin 与对话轮在同一 budget、同一 L3 配额下打包,两个打包器共用,不再漂移。tests/m-dialogue-l3-packing.test.ts 改为对两个打包器同时断言。
  • CI 发布证据同义反复:scripts/ci-release-evidence.ts 此前用 returnedAnchorIds.filter(...) 反推 expectedAnchorIds,而 recall 的定义使 expected ⊆ returned 时恒为 1.0——该门禁在数学上不可能因检索质量失败。现期望锚点先于检索从提交在案的 golden 数据集独立导出(缺失的探针用显式 ground-truth 常量并在 recall < 1.0 时失败);同时传入 expectedBodies/packagedBodies 让唯一非同义反复的 bodyCoverage(LCS)真正被度量,为 0 即失败。
  • proven 技能证据可断言而非可观测:userConfirmed 在 CI 场景改为 false(CI 不是人);testResult 不再硬编码 "pass",改为按 GRAPHFLOW_CI_TEST_RESULT 环境变量 → 流水线结果文件 → GitHub Actions 步骤顺序推断,缺失即 unknown 并明确失败,不回退到断言;DOGFOOD_LESSONS 里陈旧的 "(149 files)" 改为运行时统计真实测试文件数。
  • wouldDegradeLibrary 忽略真实成功证据:它调用 admitSkillToProven(name) 时不传 options,successCount 恒为 0,永远走不到 "success-evidence" 快路径——有真实成功 episode 的技能会被误判为"会污染库"。现接受可选 AdmitSkillOptions 并转发(1 参调用点保持兼容)。审计确认生产晋升路径本就直连 admitSkillToProven,故无生产调用点在丢失证据;admitSkillToProvisional 已从 src/index.ts 导出。
  • 安全审计工作流连续 3 周静默失败:scripts/security-audit.cjs 第 10 行用了 join 却未 import node:path,ReferenceError 使 2026-08-24 / 08-31 / 09-07 三次定时运行在 npm audit 运行前即崩溃。修复含 node:path 导入、Windows shell 处理、报告路径按仓库根解析;新增 tests/security-audit-script.test.ts(静态断言 import + 端到端跑假 npm 断言无 ReferenceError),随 npm test 进入 CI——坏脚本从此无法隐藏。

Changed

  • README 的 token 节省改为双口径并列,不再只报膨胀分母的单一数字;两项分别标注其回答的问题与不可互换性。

[1.16.0] - 2026-09-08

Added

  • R4 集成层模块化收口(HostAdapter 全宿主):新增通用 profile 驱动切片 src/integrations/profile-host-installer.ts。installViaHostAdapter / uninstallViaHostAdapter / getHostAdapterInstallStatus 现覆盖全部 19 个注册宿主——4 个手写切片(DeepSeek Harness / Cursor / Claude Code / Kimi Code)+ 15 个 profile 宿主(Trae、VS Code、Windsurf、Cline、Roo Code、Kilo Code、PearAI、Gemini、Codex、Antigravity、Amazon Q、Zed、Continue、Qoder、Opencode)。
  • skill-installer 精确目标原语:installSkillToTargets / removeSkillFromTargets / installInstructionsToTargets / removeInstructionsFromTargets——单宿主 install slice 只写自己的 skills/graphflow/SKILL.md 与受管指令块,不再顺带写其它已检测宿主。

Changed

  • CLI 三处宿主硬编码改为注册表遍历:install / uninstall / doctor 统一走 HOST_ADAPTER_MIGRATED_IDS;uninstall 先按宿主切片清理,再跑遗留清扫(工作区 MCP 条目、Trae 用户 Skill、项目级规则)。新增宿主不再需要改 init.ts。
  • agent-profiles 注册表并入 buildAgentProfiles():opencode 等仅在新注册表登记的宿主获得 MCP 安装/状态支持;遗留条目在同 id 时优先,已写入的 marker / target 路径不变。
  • runOrchestration 拆分:新增 src/core/orchestrator-phases.ts,把 ~360 行大函数拆为 runSimplePhase / resolvePlanPhase / runBridgePhase / runLlmDagPhase + makeDagNodeRunner;orchestrator.ts 只保留模式解析、上下文装配与 triage。日志、图/技能同步顺序、triageId 传播(含 LLM 失败路径有意不带 triageId)逐字保持。

Fixed

  • mcp-http 请求超时可配置:新增 GRAPHFLOW_MCP_TIMEOUT_MS,createGraphClient() 据此设置 GraphifyMcpClient.timeoutMs(默认仍 15s)。当端点连接挂起(而非被拒绝)时,15s × 多次图操作会拖长单次运行;该开关让 CI / 测试可以快速失败。
  • 临时目录残留图谱劫持工作区发现:MCP 服务以 cwd 位于 %TEMP% 启动时会在那里写 graphflow-out/graphflow-graph.json,而 hasProjectWorkspaceMarkers() 把该文件当作项目标记,于是 discoverWorkspaceRoot() 对所有位于临时目录之下的项目都返回临时目录根,m49 工作区隔离用例随之失败。新增 isSystemTempDirectory() 作为向上遍历边界(不改动 isUsableWorkspaceFallback,保留显式 cwd 回退语义),并给 discoverWorkspaceRoot() 增加 extraBoundaries 测试钩子。
  • README.md / README.zh.md UTF-8 损坏:v1.15.4 的版本号提交(a8ae51d)在改写两个 README 时把约 100 个多字节序列的第三字节替换成 ?——中文、破折号、箭头、勾选全部变成乱码并随 npm 包发布。已按 e7e429d(v1.15.3 文档提交)逐行核对后重建,仅保留有意的版本号与 HostAdapter 文案改动;同时补齐 README.zh.md 落后一版的版本徽章(1.15.4 → 1.15.5)。

Tests

  • tests/host-adapter-install.test.ts:注册表完整性、通用切片 install / uninstall / status、未安装宿主零写入(+4 用例)。
  • tests/m-install-hooks-wiring.test.ts:doctor hooks 检查改为按 agent 名匹配(DeepSeek Harness glue 与 Claude Code hooks 同属 hooks 类别,注册表顺序不是契约)。
  • tests/m48-doc-code-consistency.test.ts:新增「文档必须是合法 UTF-8」与「README.zh.md 徽章与 package.json 一致」两个守卫(+2 用例)。
  • tests/m49-workspace-root-isolation.test.ts:新增临时目录边界与「残留图谱不得捕获嵌套项目」回归用例(+2 用例)。

[1.15.5] - 2026-09-08

Added

  • Kimi Code HostAdapter:installViaHostAdapter("kimi-code") 写入 ~/.kimi-code/mcp.json、Skill 与 AGENTS.md;doctor / uninstall 同步走注册表。Kimi Code 不展开 ${workspaceFolder},MCP env 省略该占位符。工具前缀 mcp__graphflow__。

[1.15.4] - 2026-09-06

Fixed

  • DeepSeek Harness 安装不再弄挂 dsh web:graphflow install 在 profile 未安装 @roarpeng/graphflow 时只写 MCP home overlay(不写 glue);profile 已有包时清空 home overlay,由 bundle 独占 MCP+glue,避免 ERR_MODULE_NOT_FOUND 与 duplicate loader entry id: mcp-graphflow。空 cordis.patch.yml 改为删除文件(dsh 拒绝空 YAML)。FAQ 补充对应排障。

[1.15.3] - 2026-09-05

Changed

  • R4 context packaging 去重:buildLayeredContextPackage / buildEnhancedContextPackage 抽出共享 context-package-core(keyword/vector 召回、L1–L3 配额打包、dialogue 与 neighbor expansion)。两条公开函数的签名与 MCP/CLI context preview 行为保持不变;enhanced 仍独占 adaptive budget、RepoMap、symbol boost、graph compression 与 same-file/import 扩展。

Tests

  • m74/m75 测试隔离:不再 process.chdir(),也不再向真实 $HOME/.npm/_npx 写文件。fake home 与项目根均落在 os.tmpdir(),通过 fromDir 注入与 process.cwd mock 覆盖 unsafe-cwd 路径。

[1.15.2] - 2026-09-05

Added

  • 飞轮公开复现包(path A):npm run proof:flywheel 串起已有的检索 / skill A/B / memory A/B 离线基准,打印机器可读摘要 + 人类 checklist;--dry-run / --help 不重跑基准。冻结数字目录 benchmarks/flywheel-proof-claims.json;第三方入口 docs/flywheel-reproduction.md。不发明新数字,只接线仓库里已提交的自测 RESULTS。
  • GraphFlow + Serena 联合方案独立指南:把 docs/comparison.md 里的 "better together" 提升为一等文档 docs/graphflow-serena.md / 中文——并列安装两个 MCP、谁做什么(context/plan → Serena 编辑 → report_outcome)、常见坑。README(EN/中文)与 comparison 互链;配置示例 examples/graphflow-serena.mcp.json(仅 MCP 片段,不把 Serena 写入 package.json)。无运行时代码改动。

[1.15.1] - 2026-09-05

Changed

  • Cursor and Claude Code install / uninstall / doctor now go through the HostAdapter registry (installViaHostAdapter("cursor") / installViaHostAdapter("claude-code")), including Claude Code hooks. Remaining hosts (Trae, VS Code, Windsurf, Codex, Gemini, and others) still use the legacy installers.

Tests

  • Extended host-adapter-install with Cursor / Claude Code install-uninstall-status slices and M16-style CLI doctor wiring.

[1.15.0] - 2026-09-05

Added

  • Team shared memory MVP (ROADMAP R3):graphflow team serve 提供带 tenant 隔离与 viewer/contributor/admin RBAC 的 Graphify JSON-RPC 团队图服务;非 loopback 默认强制认证。graphflow team issue-token / team example-config 覆盖发证与客户端配置。
  • HTTP RBAC:JWT role / memory:read|write|admin scope 或 --http-token role:token bearer 角色表;写路径(图变更、skill sync push、artifact import、governance)对 viewer 失败关闭。MCP Streamable HTTP 在配置了凭据时对 tools/call 执行同一套角色。
  • 客户端:graphPolicy.mcpTenant;mcp-http 客户端发送 X-GraphFlow-Tenant;401/403 不再静默降级到本地文件。skill sync push|pull 在 MERGE 语义上复用既有 git 技能包。
  • Diagnose / doctor:graphflow diagnose(route diagnose 别名)与 graphflow_diagnose 输出 team 连通、authMode、tenant、RBAC、degraded-to-local。
  • 文档:docs/team-memory-security.md 标为 shipped MVP,并附部署 / 发证 / 加入 / 同步 runbook。

Tests

  • 新增 team RBAC 单测与 team server 集成测:角色允许/拒绝、tenant 隔离、非 loopback 拒无认证启动、客户端鉴权失败。

[1.14.1] - 2026-09-05

Fixed

  • #28 DSH first-turn hint: the glue extends the agent/pre-step enter decision's messages after next(), so the hint rides in the same step as the user's first message. agent.inject() is no longer used (it landed in the next-step inbox and spawned a trailing step the model refused). WeakSet gating and plugin source tagging are unchanged.
  • #26 /gf/nodes HTTP 405: /gf RPC registration waits for the host connection service with ctx.inject(["connection"]) (same pattern as DSH api-gateway) instead of a sync ctx.get("connection") that is often undefined at apply() time. Registration failures are logged instead of swallowed.

Changed

  • package.json description / keywords match the README positioning: GraphFlow is a local-first memory & context harness for coding agents, not an orchestrating executor.
  • DSH home overlay install/uninstall goes through the HostAdapter registry (installViaHostAdapter("deepseek-harness")). Cursor and Claude Code installers are unchanged.

[1.14.0] - 2026-09-02

Added

  • W1 时间语义与类型化边:dialogue-turn 新增 supersedes / same_topic 类型化边与 validAt / invalidAt 时间有效性(Graphiti 式);detectSupersession 离线修正检测(更正标记 + 主题重叠阈值,pending 轮不可被取代,nearest-N 截断);跨 session same_topic 语义连边;effectiveTurns 当前真值过滤与 formatSupersessionLine 修正链渲染。GraphEdge.relation 扩展 same_topic 并纳入 compression weights / snapshot 优先级。
  • W1 可选 LLM 轮蒸馏:distillTurnWithLlm(economy tier 路由,严格 Title/Summary/Decision 标签输出,失败逐轮回退启发式);isDecisionTurn 决策轮标记为飞轮提供 turn 粒度学习信号;dialogue distill --llm CLI 旗标(仅 hasUsableLlmProvider 时生效)。
  • W2 对话图进入上下文引擎:context-slicer L3 打包命中有效对话轮(≤3)并附修正链标注行——同 token 预算与 L3 quota,绝不豁免;graph-search 新增 searchDialogueTurns(默认隐藏被取代轮、includeSuperseded 回看历史、修正链注解),对话命中纯增量、永不挤掉代码 Symbol/File 结果。
  • W2b 对话轮检索接入生产链路:previewContext 附加 dialogueHits(跨 session 历史问答召回,≤3 条、默认隐藏被取代轮;命中修正链时在 summary 顶部加一行 Dialogue recall: ...,recordDialogue: false 的只读召回也生效)——MCP graphflow_context 结构化结果与 CLI graphflow context 同步获得该字段;新增 CLI dialogue search "<query>" [--limit N] [--include-superseded] 与 runtime searchDialogueTurnsRuntime,直接检索历史问答。
  • W3 多 Agent 轨迹:dsh glue 监听 subagent/start|end 写 agent-trace Decision 节点(GRAPHFLOW_CAPTURE_TRACE 独立开关、kind+label+status+turn 哈希去重、in-process runtime 优先、缺失即静默 no-op、绝不抛入 harness 循环)。
  • W3 fork / 回放原语:forkDialogueSession 显式分叉(跨 session next_section 主干边 + fork session↔源 session same_topic 溯源边 + seed parentTurnId);walkDialoguePath 回放路径 walker(jump/fork 边界标注);CLI dialogue fork --from <turnId> [--name]、dialogue list --path <turnId>、dialogue traces [--session] [--limit]。
  • W4 面板与导出:/gf RPC nodes 通道与 web 面板 host half 新增 dialogue traces 快照;面板对话轮显示「跳转 / 修正过结论 / fork」徽章与「Agent 轨迹」区块(含启动/完成/失败状态);artifact export-memory 新增 dialogues.md——按 session 分组的对话子图(修正链与 superseded 历史标注、Agent 轨迹列表)。
  • 发布管线真正可发版:新增 scripts/ci-release-evidence.ts flywheel 自证步骤——在 CI 上对本仓库做真实 dogfood(真实索引 + 检索探针写入 context-fidelity 样本 + 两个真实 pass episode 绑定 proven skill),并生成确定性 graphflow-out/ci.config.json 供 gate 审计;publish-npm.yml 在 gate 前执行该步骤。此前 release gate 在全新 checkout 上恒为 proven-skills 0 < 1; fidelity-samples 0 < 1,v1.13 接入门禁后 npm 实际从未发版成功。

Fixed

  • Windows release gate:scripts/release-gates.cjs 改为直接 node + tsx 运行 gate CLI——Node ≥ 18 出于安全拒绝 spawn npx/npx.cmd shim(EINVAL),旧写法在 Windows 上静默失败且无任何输出。

Tests

  • 新增 5 个测试文件 28 个用例:m-dialogue-temporal(8,时间边与修正链)、m-dialogue-llm-distill(6,LLM 蒸馏回退)、m-dialogue-l3-packing(5,L3 打包预算与修正标注)、m-dialogue-retrieval(5,检索命中与 superseded 过滤)、m-dialogue-fork-replay(6,fork/回放/轨迹)、m-memory-pack-dialogues(4,对话子图导出);dsh glue 套件更新为 3 命令面板协议并新增 4 个轨迹用例(共 29)。
  • 新增 m-dialogue-search-recall(2,preview 附加 dialogueHits 与 CLI runtime 检索回环);修复 README 版本徽章落后于 package.json 导致的 doc-code consistency 用例失败。

[1.13.0] - 2026-08-23

Added

  • Evidence Runtime:outcome report 支持 repository/commit/diff/test command/result/artifacts/user confirmation;episode 持久化 evidence package,并返回 verified|partial|unverified 结论。新增 outcome backfill 用 JSON/JSONL 证据批量关闭 pending episodes。
  • Governance Plane:新增 ADR / Invariant / APIContract / Test 图节点、版本化 upsert、supersession、review queue 和 requirement traceability;artifact 支持三方合并、冲突队列、HMAC 签名验证、AES-256-GCM 加密、保留策略与 quarantine 传播。
  • Tamper-evident audit:evidence 与 MCP HTTP 治理事件使用 sequence + prevHash + SHA-256 hash chain,可离线验证篡改。
  • Secure MCP HTTP:Streamable HTTP 支持 bearer token、HS256/RS256 JWT、issuer/audience/scope 校验、tenant allowlist、per-tenant session key 和审计响应头。
  • Release gates:graphflow governance release-gate 强制 proven skill、context fidelity sample 和 pending episode ratio;npm publish workflow 已接入该门禁。
  • Portable profiles & proof plane:governance profiles 导出 Cursor/Claude/Codex/DSH 配置;benchmarks/run-proof-plane.ts 支持多仓库 fidelity/token 评测。
  • Host adapter registry:新增 DSH/Cursor/Claude 能力模型,作为 installer 后续拆分的稳定接口。

Changed

  • 统一 canonical embedding model 为 Xenova/bge-base-zh-v1.5,消除 graphPolicy 默认值与 transformers loader 的模型 split-brain。
  • Graph node 类型扩展 ADR / Invariant / APIContract / Test;edge 扩展 supersedes / governed_by 并纳入 compression weights。

Tests

  • 新增 P0-P2 governance foundation suite,覆盖 evidence verification、knowledge supersession、artifact merge/signing/retention、encrypted snapshot 与 JWT claims。全量回归随发布流水线执行。

[1.12.2] - 2026-08-22

Fixed

  • Windows release gate:MCP structured-result 测试显式使用 file graph backend,避免 SQLite 连接仍在打开时清理临时目录导致 EBUSY。这是 v1.12.1 Windows validate 失败的直接根因;Linux/macOS 本地矩阵未暴露该平台锁差异。

[1.12.1] - 2026-08-22

Added

  • MCP Streamable HTTP transport:新增 stateless JSON 与 stateful SSE 双模式;支持 MCP initialize、draft server/discover、ping、tools、resources 和 structured tool results。启动方式:graphflow mcp serve --http 或 graphflow-mcp --http
  • HTTP 生命周期与安全默认:显式 DELETE 关闭 stateful session;默认仅绑定 loopback,Host 校验防止 rebinding,浏览器 Origin 默认拒绝并可用 allowlist 显式放行
  • 端到端 transport 矩阵:SDK Client 分别验证 HTTP JSON 与 stateful SSE;raw 请求验证 discovery、未知路径、非法 Origin、DELETE 后 stale session 和非 loopback 保护

Changed

  • @modelcontextprotocol/sdk 固定到 1.30 runtime 面;stdio legacy handshake 继续兼容

Tests

  • 新增 tests/mcp-streamable-http.test.ts;全量回归 141 文件 / 956 用例通过,扩展 bundled runtime 冒烟 7/7 通过

[1.12.0] - 2026-08-22

Added

  • dsh 知识节点面板静态化(R4 落地):新增预构建 CJS factory bundle dsh/client.js(window.__ModuleLoader__.load({id:"@roarpeng/graphflow/dsh",factory}),named 导出 apply+inject;注册 conversation.session.header.utilities 开关与 shell.overlay 面板两个 slot,PANEL_CSS 闭包内注入防重),随 bundle 层开机自动加载——不再需要按会话手动激活动态插件。数据通道走 Connection 通用 RPC:glue 注册 /gf(ctx.connection.rpc.handle(…,{authority:"trusted-host"}),自带 browser-trust fence),handler 返回 RpcResult 信封 {ok,value:{workbench,dialogues}};浏览器端 connection.rpc.call("/gf","nodes",{workspaceRoot}) 取数。package.json 叠加声明 dsh.client{platform:"web"} + exports["./client"]/exports["./dsh/package.json"](后者让现有 glue 行原样成为 client 扫描条目,实测 Node 解析通过)
  • Context Fidelity 指标流(R1):新增 graphflow-out/context-fidelity.json、anchor recall@k、missing anchors 和基于归一化 LCS 的 body coverage;FlywheelReport.fidelity 增加 sample / recall / coverage 聚合。token savings 与信息保真度从此是两条可审计指标
  • SKILL.md 双向互操作(R2):新增 skill markdown export|import;导出只带 portable 元数据与 playbook,不带走 GraphFlow 本地信任决策;导入一律保守标记 import/correctable,不继承 proven 或 canary 证据
  • Engineering KG 抽取落地(R3):新增确定性中英文 Concept/Requirement 抽取器;CLI knowledge extract [--all|--session] [--dry-run] 与 MCP graphflow_index({knowledgeExtract:true}) 可把对话结论写入图谱并保留 dialogue-turn derived_from 审计链
  • MCP structured results + stateless discovery:全部工具结果继续保留 content[0].text 兼容层,同时返回 structuredContent;tool schema 声明 JSON Schema 2020-12;SDK 升级到 1.30,stdio 兼容握手之外支持 server/discover
  • O(1) 技能读路径 + 自适应遗忘:readSkillState / loadCompositeSkill 优先 getNodesByIds;skill decay 改为陈旧度 × 失败压力 × 成功保持 × proven 保护的确定性曲线,只软衰减,不删除经验
  • 学习飞轮真实证据链(R0):proven 准入从"原子出现次数 uses>=2"改为"成功 episode 绑定计数 successCount>=阈值"(默认 2,GRAPHFLOW_SKILL_PROVEN_MIN_SUCCESS 可覆盖;按 episodeId 去重,旧数据经 linkedSuccess+provenance.episodeId 自动迁移,已 proven 节点不降级);删除 FALLBACK_GOLDEN_TOKENS 硬编码闭集,golden 词集动态生成(检索 golden 数据集 expectAny + 运行时 pass episode/symbol 证据叠加 registerGoldenEvidenceTokens);golden-overlap/符号检查降为辅助条件,不再一票否决真实成功记录
  • dsh 对话 A 面真实回填:修复 glue 监听器读错会话事件信封字段(assistant 消息在 event.data.message,旧代码读 event.message 恒为空)这一"回复永远待回复"的根因;重写为 turn/end 提交模型(assistant/message 按 step 只喂"本 turn 最后文本"缓冲;turn/end 按 (session, turn) 去重提交;interrupted/aborted 不填);回填管线 = 进程内 runtime(captureAssistantReply;命中 workbench topic 时追加 dialogue turn 填充,保证 A 面必闭)→ CLI 兜底(context preview --reply + dialogue record --reply 双幂等 tip 填);latest-wins 每 session 串行队列 + no-pending-turn 有界重试;GRAPHFLOW_CAPTURE_REPLY=0 一票关闭
  • 对话节点噪声过滤扩展:SYSTEM_MESSAGE_SOURCE_KINDS 黑名单新增 subagent-settled/subagent-report(子代理完成/汇报通知此前被记成用户提问的直接根因)及 agent-instructions/session-reference/goal/skill-catalog;user kind 白名单放行真人输入,未知来源维持 role 回退保守兜底
  • file 图存储进程内缓存(R1):graphify-file-client 按绝对路径缓存解析 store 与懒构建倒排索引(queryByKeyword 不再每次重建索引),mtime+size 校验失效、写路径 write-through(拷贝构建 + readSnapshot 浅拷贝防污染)、跨实例共享;导出测试钩子

Fixed

  • MCP unsafe-cwd 下工具级 rootDir 被吞(工具全灭):resolveConfig() 内部无条件先执行 bindRuntimeWorkspaceRoot(只认配置文件 workspaceRoot),MCP 服务端 cwd=家目录时在调用方 rootDir 应用前就抛 Refusing to index unsafe workspace root——而服务端启动日志承诺 "Pass rootDir on tools"。现在 resolveConfig(configPath, { rootDir }) 把 rootDir 传入内部绑定(优先级 rootDir > projectWorkspaceRoot > cwd 发现不变,unsafe 安全检查不放宽);src/surfaces/cli/runtime/{graph,dialogue,routing}.ts 全部持有 rootDir 的调用点已接线;resolveRuntimeWorkspaceRoot 支持注入 fromDir(测试免 process.chdir)

Tests

  • tests/resolve-config-rootdir.test.ts(新增 6 用例):unsafe cwd + rootDir 不抛错且绑定生效;不传 rootDir 保持抛错;显式 configPath 分支;fromDir 注入向上发现
  • tests/dsh-plugin-glue.test.ts:reply 断言重写到 turn/end 提交模型(信封形状、按 turn 去重重放无副作用、aborted/interrupted 跳过、CLI 兜底双 spawn 参数与 cwd)
  • tests/graphify-file-client-cache.test.ts(新增 9 用例)+ auto-transport / auto-transport-fallback(+5):缓存命中/外部变更失效/仅 mtime 失效/写透三方一致/交错读写、sqlite 不可用与初始化失败静默回退
  • tests/m-learning-success-evidence.test.ts(新增 9 用例);更新 5 个编码旧 uses>=2→proven 规则的测试
  • 全量回归:140 文件 / 953 用例全绿;tsc --noEmit 零错误
  • v1.12 新增回归:context fidelity、SKILL.md round-trip、Engineering KG extraction、structuredContent/stateless discovery、O(1) skill read、adaptive decay

[1.9.16] - 2026-08-21

Added

  • dsh 对话自动闭环:dsh/plugin.mjs 监听 session/event 的 assistant/message,自动把每轮回复填入 dialogue-turn 节点(dialogue record --reply),与 agent/inbox/inserted 提问记录配对;提问/回复均按 dsh 会话 id 隔离(--session),同工作区多会话不串
  • 对话节点提炼:新增 src/learning/turn-distillation.ts(离线启发式)——deriveTurnTitle 剥离问候/祈使前缀取首子句(30 字符),deriveTurnSummary 结论标记句优先/末段落回退(200 字符);DialogueTurnRecord 增加可选 title/summary,记录/回填时自动生成
  • CLI graphflow dialogue distill [--all] [--session]:批量回填遗留轮次的 title/summary(幂等);dialogue list 输出 title/summary
  • 对话记录噪声治理:isUserOriginatedMessage 按 message.source.kind 过滤 harness 系统注入(job 完成/子代理/Cordis 通知不再入图),未知来源回退 role 判断
  • web 知识节点栏源码种子:web/plugin.mjs(Host+Client 双半部参考实现)+ web/README.md;docs/dsh-install-guide.md 新 harness 安装启用指南
  • ROADMAP 进化方向:R0-R4 深度调研版(真实证据链 / 性能收敛 / MCP 2.0 与 SKILL.md 对齐 / 概念层落地 / 工程治理)

Fixed

  • CLI dialogue record --reply 解析 bug:reply-only 填充此前被参数解析短路——--reply 的值被裸参数拼接当成 query,导致填充变成新建垃圾轮次;新增 resolveDialogueRecordInput(reply-only 优先、flag 值不泄漏进 query、兼容 --flag=value)+ 4 个回归用例
  • doctor 指令状态检查竞态:getAgentInstructionStatus 的 existsSync+readFileSync 非原子,并行场景(测试/安装并发)下 ENOENT 会抛异常;读失败改为视为未安装

Tests

  • tests/dsh-plugin-glue.test.ts:回复补全(spawn 参数/三态跳过/session/event 接线去重)+ 消息来源过滤(plugin/tool/model 不入图)
  • tests/turn-distillation.test.ts(新增 14 用例):标题/摘要单元 + dialogue distill 端到端幂等
  • tests/dialogue-thread.test.ts:resolveDialogueRecordInput 4 用例

[1.9.15] - 2026-08-20

Added

  • Experience v2:噪声技能按名字清理(含 legacy kind: evolution / readme+update 融合);held-out golden overlap 准入;ACE 式 playbook 增量计数;成功 DAG 蒸馏为 workflow skill;forgetEpisode 按 provenance.episodeId 软隐藏派生技能;L3 钉住 goal/alignment/deviation
  • DeepSeek Harness glue 收口:MCP 行 cwd: !!js process.cwd();bundle ESM @roarpeng/graphflow/dsh(dsh/plugin.mjs 打进 npm files + exports);dsh plugin add 时 ctx.skills.register;graphflow install / doctor / uninstall 检测 home overlay、glue 行、$DSH_HOME/skills/graphflow/SKILL.md
  • File expand 返回全文(上限 20 万字符);FlywheelReport.fidelity 拆开 packaging ROI 与 pendingRatio

Changed

  • SessionEnd / dsh agent/disposed 不默认把 pending episode 标成成功。Claude Code 空 $2、dsh 未设 GRAPHFLOW_HOOK_SUCCESS 时保持 pending;显式 true/false 才调用 graphflow outcome report
  • Token savings 不再冒充信息保真度(explainSavings() / kind: tokens-not-fidelity)

Docs

  • README 诚实矩阵:dsh 上 MCP 10 工具 + skill + 会话结束捕获可用;VS Code/Cursor UI 与 Claude Code Session* 文件 hooks 不移植
  • docs/context-contract.md 写明 preview 是指针,精确编辑要 expand File

Tests

  • tests/dsh-plugin-glue.test.ts:glue 不监听 session/flush;无 GRAPHFLOW_HOOK_SUCCESS 不默认 pass
  • tests/m-skill-admission.test.ts / m-playbook-delta.test.ts / m-workflow-skill.test.ts / m-skill-revoke.test.ts / m-context-fidelity.test.ts / m-l3-constraint-pin.test.ts

[1.9.14] - 2026-08-15

Added

  • 工作台脉络:graphflow_plan 按计划 DAG 播种功能主题容器(workbench.topics),画布单位是功能而不是一轮一节点;偏离主线时 Fork 孤立旁支;点击 topicId 注入 Goal + 祖先标题 + 该节点原文
  • 按需唤醒大纲(默认收起):CLI graphflow workbench tree、VS Code 活动栏 GraphFlow: Workbench Tree / Chat /tree、MCP graphflow_diagnose.graph.workbenchOutline(不新增第 11 个工具)
  • graphflow_context 支持 topicId / assistantReply(可省略 query)两拍入图:提问记 Q,答完回填原文 A;标题只用于显示,不写入下一轮必读上下文
  • 无计划时仍将对话记为 dialogue-turn;有工作台则写入当前主题容器
  • DeepSeek Harness (dsh) plugin:@roarpeng/graphflow 声明 dsh.bundle + 根目录 cordis.patch.yml,可通过 dsh plugin --profile <name> add @roarpeng/graphflow 装入 profile;MCP 经 in-box @deepseek-ai/dsh-mcp-client 暴露为 mcp__graphflow__graphflow_*
  • 中文 README(README.zh.md)与 plugin.json / Skill 写明 dsh 用法与 10 项能力
  • graphflow install 在检测到 $DSH_HOME / ~/.dsh 时写入 home 级 cordis.patch.yml overlay,并把 Skill 装到 ~/.dsh/skills/graphflow/SKILL.md
  • graphflow uninstall / doctor 同步清理与自检该 overlay

Tests

  • tests/workbench-topic.test.ts:主线 DAG 拓扑序、旁支嵌套、原文注入不含 Summary
  • tests/dialogue-thread.test.ts:对话入图与 pending 回填
  • tests/m15-vscode-panel-observability.test.ts:快照「工作台脉络」默认收起 + 在此继续
  • tests/m16-agent-integrations.test.ts:MCP topicId / workbench.outline 描述

[1.9.13] - 2026-08-13

Changed

  • GraphFlow: Settings 收成一页:文档解析(Markdown / Office·PDF)、anydoc 安装状态、语义召回、MCP、模型、建图与功能入口都在同一面板配置;不再依赖 VS Code Settings 里的 graphflow.downloadAnydoc 作为主入口
  • Settings 去掉「本版亮点」长文,保留状态条 + 芯片入口(图谱 / 上下文 / 技能 / 规划 / 运行)

Tests

  • tests/m53-include-extensions.test.ts:Markdown / Office 索引开关
  • tests/m10-cli-runtime.test.ts:settings 持久化 document flags + embeddingProvider
  • tests/m15-vscode-panel-observability.test.ts:Settings 新布局断言

[1.9.12] - 2026-08-12

Added

  • Episode ↔ Engineering KG on outcome path: graphflow_report_outcome / CLI outcome report accept optional requirementIds / conceptIds / codeHints and write episode → derived_from → eng nodes via linkEpisodeToEngineeringNodes
  • Document-semantic insight ↔ episode provenance: when episodeId is passed with a document-semantic submit, the same eng links are written for experience↔eng consistency
  • ATP minimal producer atp-ir/1.2: optional memory-recall / memory-backfill markers (host-managed); fixture + README updated; still runnable without GraphFlow MCP
  • P0 skill consolidate apply:graphflow skill consolidate 默认 dry-run;--apply / --execute 安全调用 applySkillConsolidation(未知 id skip)
  • 代码域检索评测公开数据集:benchmarks/datasets/retrieval-golden-v1.json(+ .jsonl),含 schema / license / domainCounts / Hit@5·MRR·NDCG 映射说明;npm run dataset:retrieval 从 benchmarks/retrieval-golden-data.ts 再生,避免漂移
  • Agent Plugins 1.0 packaging at repo root: plugin.json, mcp.json (type: stdio), and canonical skills/graphflow/SKILL.md
  • README section for local plugin install (~/.cursor/plugins/local) and Team Marketplace / Git discovery
  • npm run sync:surfaces keeps src/surfaces/trae-skill/graphflow/SKILL.md aligned with the Agent Plugins skill source
  • Conformance test tests/agent-plugins-1.0.test.ts
  • P1 Context Engineering contract: docs/context-contract.md — budget fields, L0–L3 anchors/refill, positioning vs platform indexing / RL; links MCP graphflow_context and Agent Plugins
  • P1 Experience memory guide: docs/experience-memory.md — Storage → Reflection → Experience; artifact / memory-pack / skill-sync; Agent Plugin vs install matrix
  • Experience memory pack: exportExperienceMemoryPack + CLI graphflow artifact export-memory → graphflow-out/memory-pack/{README,skills,episodes}.md
  • README: Agent Plugins as primary install; graphflow install as Rules / multi-agent fallback; links to the two new docs
  • install/doctor 接入 Claude Code 飞轮 hooks:graphflow install 在检测到 Claude Code home 时自动调用 installClaudeCodeHooks(SessionStart / SessionEnd / Stop);doctor --json 新增 hooks 类别自检;InstallReport 增加 claudeCodeHooks;GRAPHFLOW_CLAUDE_HOME 便于测试覆盖

Fixed

  • 扩展升级后 MCP launcher 路径失效:repairStaleGraphFlowMcpLaunchers 在扩展激活时扫描用户级与工作区 MCP 配置;若 graphflow 仍指向已删除的旧版 mcp-launcher.cjs/.cmd(如 roarpeng.graphflow-1.9.6),自动改写为当前扩展启动器。修复 Cursor Agents 依赖项目级 .cursor/mcp.json 而 IDE 仍可用的不一致。

Changed

  • ATP/IR spec status line marks atp-ir/1.2 Stable; §5 / §8 document optional Engineering KG link fields on report_outcome
  • ROADMAP P2 rows (ATP producer + Engineering KG episode chain; ATP/IR v1.2 protocol) → ✅
  • P0 Experience 飞轮可观测:getFlywheelReport / skill report / route diagnose / graphflow_diagnose 的 experience 增加 dry-run consolidation 动作计数(UPDATE/DELETE/ADD)与建议 hint;ROADMAP P0 ✅
  • Skill resolution (resolveSkillSourcePath / MCP graphflow_skill_guide) prefers skills/graphflow before legacy trae-skill paths
  • package.json files publishes plugin.json, mcp.json, and skills/
  • ROADMAP (2026-08-12): Experience-layer P0–P2 ✅ (skill consolidate --apply; retrieval golden dataset; ATP/IR v1.2 + episode↔eng KG)
  • graphflow uninstall now removes MCP + Skills + Rules + hooks (user + workspace MCP). After removing an Agent Plugin in Cursor, run uninstall so leftover ~/.cursor/skills/graphflow cannot keep steering the agent.

Tests

  • tests/m-install-hooks-wiring.test.ts:hooks status + install/doctor 接线
  • tests/m-stale-mcp-launcher-repair.test.ts:失效 mcp-launcher 路径检测与改写
  • tests/atp-ir-v1.2-conformance.test.ts:ATP/IR v1.2 memory markers + producer protocol
  • tests/report-outcome-engineering-links.test.ts:outcome / insight eng-link wiring
  • tests/retrieval-dataset.test.ts:公开检索数据集与 TS 真源条目数/内容一致

[1.9.11] - 2026-08-08

Added

  • VSIX 激活时按需下载 anydoc:设置 graphflow.downloadAnydoc(默认 true)→ npm install @firecrawl/anydoc 到 ~/.graphflow/optional-deps;MCP launcher / document-convert 经 GRAPHFLOW_ANYDOC_NODE_MODULES 加载。失败则跳过 Office/PDF,源码索引照常
  • README / 扩展 README 说明 VSIX 不内置、可自动下载、可关闭
  • emilkowalski/skills:项目安装 design-eng 等 skill;扩展 webview 面板统一 soft elevation、:active scale(0.97)、--ease-out、reduced-motion

[1.9.10] - 2026-08-08

Added

  • Engineering KG 跨层边:documents(文档 File→Concept/Requirement)、implements(代码→Requirement)、derived_from(语义节点→来源 File/insight)
  • 文档域一等节点:Concept / Requirement;document-semantic insight submit 自动写入并尝试用 relatedCodeHints 链接已有 File/Symbol
  • 说明:VS Code/Cursor VSIX 不打包 @firecrawl/anydoc;自 v1.9.11 起扩展激活时可自动下载到 ~/.graphflow/optional-deps(graphflow.downloadAnydoc)。CLI/npm i 仍可通过 optionalDependency 安装。无 anydoc 时跳过 Office/PDF,源码索引不受影响

Changed

  • 逻辑三分(code / doc / experience)落在单图 + type/domain + 跨层边,不拆物理三库

[1.9.9] - 2026-08-08

Fixed

  • CI macOS ENAMETOOLONG:walkFiles 深度目录测试从 400 段降至 80 段,保留迭代遍历断言,避免 APFS 路径过长导致 Action 失败

Added

  • Office/PDF 文档建图:可选依赖 @firecrawl/anydoc,将 PDF/DOCX/PPTX/XLSX 等转为 Markdown 后走既有 markdown 章节/链接图谱;缺省扩展名已包含办公文档;单文件上限约 5MB
  • Document semantic bridge:索引成功后返回 optional document-semantic-* agentWorkItems,由宿主 Agent 抽取关键实体/主张并经 graphflow_insight(mode=submit) 回写

Research note

文档→MD 选型:优先 Firecrawl anydoc(Node、多格式、本地);备选 Microsoft MarkItDown(Python)、Pandoc(系统依赖)。npm 上无关的旧包 anydoc 勿用。

[1.9.8] - 2026-08-08

Added

  • P0 飞轮可观测性:getFlywheelReport / skill report / graphflow_diagnose / route diagnose 暴露 autoCaptureEnabled、sessionJournal、skills.byOutcomeKind;npm run backfill:episodes 包装历史回填脚本
  • Skill-conditioned DAG:plan 节点可选 skillRefs / avoidPatterns;bridge 指令要求执行前审阅 skills / 避开 anti-patterns
  • SkillOpt-lite:无 LLM 的有界 skill guidance 编辑(最多 3 次,严格提升才接受);接入 applySkillLearning lessons 路径
  • 团队记忆 canary 门控:canary-gate.ts——sync/import 技能须本地成功 N 次(或显式 validate)才可晋升 proven;anti-pattern 仅隔离
  • Codex Windows MCP:安装写入 NODE / NPX_CLI 8.3 短路径,修复 Codex 注册失败

Changed

  • 图噪声:引用边前缀 Trie 预过滤;子图 PageRank LRU 缓存键按节点集排序哈希
  • planAndBrainstorm 异步化以在 flywheel 开启时注入 skill 条件

Tests

  • 新增 tests/m81-skill-conditioned-dag.test.ts、tests/canary-gate.test.ts;扩展 flywheel-report / graph-noise / mcp-resources / Codex MCP install

[1.9.7] - 2026-08-03

Added

  • 综合能力 Benchmark(P1-P6 六维度):benchmarks/run-comprehensive-bench.ts,覆盖图谱索引、上下文压缩、规划与分诊、学习飞轮、Bridge 模式、端到端性能,总体得分 92.9%
  • CodeGraph 风格独立 Benchmark:benchmarks/run-independent-bench.ts,5 域(core/graph/learning/config/integrations)评测,Hit@5 96%、Token 节省 96.6%、总体 96.2%
  • SWE-bench 风格上下文就绪评测:benchmarks/run-swe-bench-eval.ts,12 实例(easy/medium/hard × bug-fix/feature/refactor/test),多查询策略下上下文就绪率 100%(非真实 SWE-bench,仅测量压缩上下文是否包含任务所需文件/符号)
  • 检索质量 IR 指标评测:benchmarks/run-retrieval-eval.ts,132 条 golden 查询,Hit@5=100%、MRR=0.836、NDCG@5=0.601
  • 符号提取模块:src/graph/symbol-extract.ts,从任务描述提取 camelCase/PascalCase 符号名,补充图查询提升召回
  • 同文件符号提升 + 导入图扩展:buildEnhancedContextPackage 新增 Step 5,自动从已锚定文件提取同文件 Symbol 节点,并通过 import 关系扩展跨文件召回
  • Bridge+DAG 混合执行模式:enableBridgeDagExecution 选项,bridge 模式下可选择同时本地执行 DAG(tests/m81-bridge-dag-execution.test.ts,5 个用例)

Changed

  • 上下文压缩优化:anchor 上限 15(maxAnchors)、L2 module 注入、L3 always-on 层;压缩得分 38.4% → 64.9%
  • DAG 并行度提升:单 clause 任务拆分 4 节点(实现∥测试设计),并行度 1.2x → 1.40x
  • Skill hints 修复:传入 evidence 通过 P0-2 质量门控,skill hints 从 0 恢复到正常生成

Tests

  • 99 测试文件 / 692 tests(+1 m81 bridge+DAG、m79 plan clause split 更新)

[1.9.6] - 2026-08-03

Fixed

  • Cursor/VS Code MCP 启动失败:扩展 vendor 打包漏掉 @modelcontextprotocol/sdk,MCP launcher 加载 vendor/graphflow/dist/surfaces/mcp/server.js 时抛出 Cannot find module '@modelcontextprotocol/sdk/server/index.js'(Connection closed / -32000)。sync-runtime.mjs 已将 MCP SDK 纳入 runtimeRoots,并在同步后校验必选包存在;新增 test:mcp 烟雾测试防止回归

[1.9.5] - 2026-08-01

Fixed

  • 图谱索引排除 Agent 工具目录(P1):IGNORED_DIRS 新增 .agent / .claude / .cursor / .gemini / .joycode / .trae / Cursor——.claude/worktrees 为每个 worktree 保存完整仓库副本,此前被当作源码索引进图(本地实测 1421 个 File 节点中 1076 个来自 worktrees,占 76%),污染检索锚点、PageRank 与存储;修复后 graph rebuild 扫描文件数从 ~1500+ 降至 326,旧图可在下次增量/全量索引时自动清理
  • 增量索引剪枝批量删除(P1,读写放大修复的伴生问题):排除目录后首次增量索引需从缓存差集剪除大量过期节点,而 pruneFileFromGraph 逐节点 deleteNode(file 后端每次全量读写 JSON,实测 62MB 图 × 1000+ 节点 → 305s 挂起);新增可选能力 GraphClient.deleteNodes(ids)(file 单次读+写、sqlite 单事务分块 IN、memory 批处理,均级联清理悬空边),剪枝改为单次快照读取 + 单次批量删除,mcp-http 试点保留逐节点回退路径
  • 测试 95 文件 / 656(+2 walker 排除、+1 剪枝批量删除、+1 file 批量删除用例)

[1.9.4] - 2026-08-01

Changed

  • 扩展市场说明更新:vscode-extension/README.md 重写为 v1.9.x 最新使用说明(记忆审计 CLI、飞轮归因面板、语义 embedding 配置、技能分类、skill sync、改名后市场身份 roarpeng.graphflow / GraphFlow Context & Memory);扩展 description 改为版本无关描述(消除版本钉死导致的文档腐化)

[1.9.3] - 2026-08-01

Fixed

  • Marketplace 发布(二次):GraphFlow 显示名亦被第三方占用(不出现在公开搜索,疑似下架/保留名),改为 GraphFlow Context & Memory

[1.9.2] - 2026-08-01

Fixed

  • Marketplace 发布:新身份 roarpeng.graphflow 的 displayName 改为 GraphFlow(GraphFlow Tool 被旧列表 roarpeng.graphflow-tool 持有,VS Marketplace 拒绝重复 displayName;经 Marketplace 搜索 API 验证 GraphFlow 未被占用)

[1.9.1] - 2026-08-01

记忆透明化版本:让「跨会话记忆」可度量、可审计、可归因。

Added

  • 记忆 ROI 基准(正式化):npm run benchmark:memory(benchmarks/run-memory-ab.ts)——62 任务(26 golden + 36 hard:跨模块影响面/消歧/间接形态),记忆开 vs 关双臂,实测 ON 100.0% vs OFF 56.5%(救回 27 任务、0 受损,其中 hard 域 17 个);归因链逐任务记录「哪条记忆救了哪个任务」(top episode + 相似度 + 注入文本),JSON 落 benchmarks/.cache/memory-ab-results.json
  • 记忆审计 CLI:graphflow memory list [--outcome pass|fail|pending](证据记录:id/任务/结局/lessons/staleGoal)、memory search "<query>"(相似度排序命中)、memory forget <id>(物理删除,未知 id 干净 no-op);runtime facade 暴露 listEpisodes/searchEpisodes/forgetEpisode
  • 飞轮报告归因区块:getFlywheelReport 新增 memoryAttribution(memoryHits / staleEpisodes / confidence 分布 / topContributingMemories 证据链 / deviationBreakdown),全字段增量兼容

Changed

  • VS Code 扩展改名:graphflow-tool → graphflow(Open VSX 名称可用已验证;新身份 roarpeng.graphflow,VSIX 产物 graphflow-<version>.vsix);扩展包名、agent 标识、CI 工件、文档同步
  • 测试 94 文件/646 → 95 文件/652,全量通过

[1.9.0] - 2026-08-01

技能质量与团队化版本:飞轮从「机制完整、效果未知」走向「A/B 实证 + 质量门禁 + 团队共享」。

Added

  • 语义 embedding 可选后端(P0):graphPolicy.embeddingProvider: "fnv" | "transformers"(默认 fnv 离线安全);transformers 时经 @huggingface/transformers 懒加载 all-MiniLM-L6-v2,任何失败(缓存缺失/超时/加载错误)永久降级 FNV-1a 并告警;graphflow_diagnose 新增 embeddingBackend: semantic | off 上报活动后端
  • 技能结果分类(P0):单一分数升级为 proven / correctable / anti-pattern / noise 四类——noise 提取即拒、装载时清理(cleanupNoiseSkills);仅 anti-pattern 记负分(消灭「首次失败即 -20 下沉」);proven 需 ≥2 次使用或链接成功结局
  • 检索 golden set 26 → 132(P1):10 域覆盖(含 PLC),12 负样本断言 + 132 Top-K 位置断言(rank 稳定性门),每域 ≥8 查询护栏
  • 技能飞轮端到端 A/B 基准(P1):npm run benchmark:ab 以 golden 查询为任务集、真实学习路径跑双臂——实测飞轮开 100.0% vs 关 61.5%(救回 10 任务、0 受损),开销 33 tok/任务
  • CI 版本一致性门禁(P1):scripts/ci-version-check.cjs 断言 package.json / CHANGELOG 最新条目 / README 徽章三源一致;CI 新增 skill A/B 基准 job(文件存在性守卫)
  • skill sync 双向 merge(P2):导入改为按技能 ID 合并——同 ID 取较新 updatedAt、平手保本地、本地独有保留;--force 恢复覆盖;包 schema 1.1 新增 goldenQueries,团队 golden 集随包同步(合并去重写 .graphflow/team-golden.json)
  • VS Code 飞轮贡献面板(P2):新增「Flywheel · 学习飞轮贡献」区块——技能正/中/负分布、topUsed、episodes pass/fail/pending 结果条;runtime.getFlywheelReport() 暴露数据
  • Graphify mcp-http 团队后端试点(P2):GraphifyMcpClient 补齐完整 GraphClient 接口,所有操作 withFallback 失败降级本地 file 存储;端点校验 + 15s 超时 + readSnapshot/ping/isDegraded;README 试点说明
  • PLC 索引器加固(P0):PLCopen XML POU returnType(嵌套/inline 双形态)提取为 POU.return 符号;ST 分析器 CASE 数值分支(1: / 1..10:)不再被误判为跳转标签;45 测试 + 双 fixture

Changed

  • 测试 92 文件/489 用例 → 94 文件/646 用例,全量 14.7s 通过
  • vitest.config.ts 排除 .claude/worktrees/**,根治多 worktree 并行时测试互扫污染(m50 假失败)

Fixed

  • skill 节点全负分(-2/fail)根因:浅层 n-gram 技能(update/readme)被提取——现按符号证据门禁拒绝

[1.8.0] - 2026-07-28

目标对齐(Goal Alignment)版本:让 Agent 在长时间、多步骤任务中始终记得为什么出发——治「需求理解不透」与「干着干着偏离」两大痛点。

Added

  • Goal 锚点节点化(P0):intent-analysis / simple-plan-intent / clarification 提交自动把意图五元组(coreProblem / successDefinition / nonGoals…)固化为图一等公民节点(goal:<hash(task)>,metadata kind:"goal");PromptContext.goalAnchors 在每次打包时以最高优先级位置注入原始需求,orchestrate 各角色 prompt 全程可见
  • 低置信度澄清门(P3):intent 载荷新增 confidence;有效置信度 < 0.6 时 merge 拒绝定稿(complete=false + needsClarification=true + intentConfidence),须先提交 clarification work item 澄清至 ≥ 0.6;无 confidence 字段的旧载荷按 1.0 处理(向后兼容)
  • alignment-check 执行期回检(P2):新 work item(kind:"alignment",optional)——子任务/计划完成后回检「产出是否服务 successDefinition、是否触碰 nonGoals」,附 drift 分类;simple bridge 与 full ATP 的 agentInstructions 均加入执行期协议说明;永不阻塞 merge
  • deviation 偏离分类(P1):report_outcome / outcome report --deviation 接受 none | misread-requirement | scope-creep | tech-drift,持久化到 episode record;飞轮报告新增 episodes.deviations 聚合与 goals(active/superseded)统计;MCP graphflow_report_outcome schema 同步
  • Goal 版本链 + 变更 diff(P4):需求实质变更时旧记录快照为 goal:<hash>:v<n>(status superseded),active 节点版本 +1 并带 changedFields diff;同任务 pending episodes 自动标记 staleGoal;相同再提交仅刷新时间戳
  • ATP/IR 规范 v1.1:docs/atp-ir-spec-v1.md 升级——§4.3 协议级 work items、§5.1 goal anchor / clarification gate / alignment check / deviation / goal versioning(纯增量,v1.0 兼容)

Changed

  • 测试:新增 tests/goal-anchor.test.ts(12 用例覆盖 P0–P4);m80 simple bridge 断言更新为「required 2 项 + optional alignment-check」;flywheel report 测试覆盖 deviation 聚合与 goal 统计;全套 92 文件 / 455 tests 通过

[1.7.15] - 2026-07-28

Added

  • 检索 golden set 回归测试:tests/retrieval-golden.test.ts 固定 26 条代表性查询(orchestrator / context / skill flywheel / planner 等),断言关键源文件召得回且命中率 ≥ 80%,检索质量从此有回归护栏
  • 词干匹配:rankNodesForContextQuery 对 ≥ 6 字符的查询 token 做前缀词干匹配(如 routing 命中 route),修复 "orchestrate task routing" 类查询召不回 orchestrator 的盲区
  • PageRank LRU 缓存:computePageRank 以全图指纹(节点 + 边 + 参数)为键缓存结果(上限 8 条),重复上下文打包零重算;导出 pageRankCacheStats / resetPageRankCache
  • HNSW 向量索引持久化:getSharedVectorIndex(nodes, persistPath?) 进程内 memo + 磁盘恢复(Float32 base64,上限 20k 向量);OrchestrateOptions.hnswIndexPath / embeddingPolicy.vectorStorePath 派生 .hnsw 路径,跨进程复用向量召回索引
  • transport: "auto":图存储自动选择——sqlite 优先(FTS5 检索、避免大仓库全文件读写放大),better-sqlite3 不可用时透明降级 JSON 文件存储;graphflow.config.example.json 默认改为 auto
  • Skill A/B 基准:benchmarks/run-skill-ab-benchmark.ts(npm run benchmark:skills)离线确定性度量 skill 飞轮价值——hint 注入率、episode 召回率、Jaccard 相关性代理、token 开销(实测注入 100% / 召回 100% / 25.6 tok 每任务)
  • 技能包团队共享:graphflow skill sync export|import [--path] 双向同步技能包到可进 git 的 JSON 文件(默认 .graphflow/skills/team-skills.json),幂等再导入
  • 飞轮贡献报告:graphflow skill report / graphflow_diagnose 新增 flywheel 字段——skills 正/中/负分分布、topUsed、episodes pass/fail/pending/withLessons、insight decisions 计数
  • ATP IR 公开规范:docs/atp-ir-spec-v1.md 定义 atp-ir/1.0——角色、AgentWorkItem/TaskNode 载荷 schema、full ATP vs simple-plan bridge ID 注册表、submit/merge 契约、兼容性规则
  • 测试基建:tests/helpers/no-llm-config.ts 隔离配置工厂(providers 空 + budget/learning/embedding/graph policy 完整,防 loadConfigSafe 静默回退默认配置);tests/helpers/setup.ts 注册进 vitest setupFiles,测试默认 2s provider/embedding 超时

Changed

  • README 重写:新定位「编码 Agent 的上下文与记忆层」,修复旧版中文乱码(0x3F 损坏);30 秒上手、能力矩阵、10 MCP 工具表、CLI 速查、基准与 ATP 规范链接
  • Bridge 模式省一次 LLM 调用:orchestrate 在 bridge(agent-delegated)模式下跳过 plannerDraft 的纯装饰性 LLM 调用(其结果仅用于 feedback 字符串,无下游引用)
  • 引用边构建优化:file-indexer-edges 改用 matchAll 流式扫描避免大中间数组,symbolIndex 为空时早退
  • 测试环境隔离:m7/m9/m10/m14/m16/m44/m48/m-bridge-cli-loop 全部改用显式隔离 configPath,本机 ambient 配置(真实 API key)不再把单测变成 30–60s 网络调用

Fixed

  • sqlite FTS camelCase 盲区:FTS5 不拆 camelCase,而查询侧经 tokenizeForIndex 拆成子词,后缀子词永远匹配不上;schema 升级 v2(searchtext 列 = 原文 + 拆分子词,含 ALTER/backfill/重建 FTS/trigger 迁移)
  • m16 环境敏感断言:agent 集成测试改用 mkdtemp 临时 config,agent-delegated 断言在任意本机环境下确定性通过
  • m48 文档一致性:README 版本徽章回归,与 package.json 单一事实源对齐
  • lint:client-factory auto 降级分支未使用变量、golden set 测试冗余 eslint-disable

[1.7.14] - 2026-07-28

Fixed

  • CI / m16:无 LLM 时 graphflow_plan 返回 mode=agent-delegated,更新集成测试断言(修复 v1.7.13 构建失败)

[1.7.13] - 2026-07-28

Changed

  • graphflow_plan 无 LLM 也 Bridge:默认 simple 模式在未配置 GraphFlow LLM 时返回 mode=agent-delegated,下发 simple-plan-intent + simple-plan-decomposition work items,由连接的 coding agent 理解任务并拆 DAG;本地启发式结果以 suggestedNodes(nodesStatus=suggested)附带,不作终稿
  • merge 协议:识别 simple-plan work item ID,两步 submit 后即可 merge 出最终 plan(不与 insight 全量帽子协议混淆)

[1.7.12] - 2026-07-28

Fixed

  • graphflow_plan 误拆分析维度:冒号后的评价维度列表(如 assumptions、failure modes、validation gates)不再被 ,/、/, 拆成独立并行任务节点;仅当各子句都像可执行任务时才弱分隔
  • brainstormer 共用同一 splitTaskClauses,避免目标澄清变成名词碎片

[1.7.11] - 2026-07-27

Changed

  • Settings 工具页:同步展示 v1.7.11 本版亮点(MCP home-cwd 修复、install/doctor JSON 自检、Bridge 飞轮、无需 LLM 能力)
  • 扩展 README / marketplace description:对齐最新版本与 FAQ

[1.7.10] - 2026-07-27

Fixed

  • MCP home-cwd discovery:安装后 Cursor 常以 cwd=/home/<user> 启动 MCP;discovery 不再通过 IDE hint 把 home 当作工作区(修复 Refusing to use unsafe workspace root from discovery: /home/...)
  • 读取 WORKSPACE_FOLDER_PATHS:优先使用 Cursor 注入的工作区路径;忽略未展开的 ${workspaceFolder} 占位符
  • npx MCP 安装:写入 GRAPHFLOW_WORKSPACE_ROOT=${workspaceFolder},由 Cursor/VS Code 插值到真实项目根

[1.7.9] - 2026-07-22

Added

  • Open VSX 自动发布:Build workflow 在 package-windows 成功后幂等推送到 Open VSX(密钥 open_vsx_token,namespace roarpeng,与扩展 publisher 一致)
  • Opencode agent 支持:自动检测 ~/.config/opencode/ 并安装 MCP(mcp 键/数组 command/enabled/type: "local" 格式)、Skill(~/.config/opencode/skills/)和 AGENTS.md 指令;workspace 级 MCP 注入支持 opencode 格式
  • embedding 超时:pipelines() 模型下载 60s 超时(GRAPHFLOW_EMBEDDING_TIMEOUT_MS),超时自动降级 hash
  • HF 镜像:HF_ENDPOINT / GRAPHFLOW_HF_ENDPOINT 环境变量配置 HuggingFace 镜像(如 hf-mirror.com)
  • fallback 标注:ResilientLocalEmbeddingProvider.getFallbackReason(),diagnose 输出当前 backend 和降级原因
  • 全面健康检查:graphflow_diagnose 增加 workspaceRoot 解析、graphFreshness、modelCache、connectivitySummary
  • 技能衰减:maybeDecaySkills(七天内无活动分数向 0 衰减 ±1)、resetSkillScore、pruneLowSkills;CLI skill decay/reset/prune
  • Episode 隐私:forgetEpisodes() + learn forget;artifact export 默认排除 episode(--include-episodes 可还原)
  • CI 矩阵:validate.yml Node 20/22 矩阵 + validate-platforms job(win/mac Node 22)
  • Surface sync 脚本:scripts/sync-surfaces.cjs + --check 模式 + npm run sync:surfaces
  • WASM 版本标记:wasm/.grammar-version 版本校验,升级时强制重建

Changed

  • 迁移到 @huggingface/transformers v3:loadTransformersModule 优先使用已在 dependencies 中的 v3,@xenova/transformers 保留为 legacy fallback
  • pino-pretty 移到 devDependencies:减小生产安装体积
  • README 测试数:59→72 文件、280+→357+ tests(脚本化生成,避免再次漂移)

Fixed

  • macOS CI:m49-workspace-root-isolation 测试通过 realpathSync 解析 /var → /private/var 符号链接
  • package-lock.json 同步:与 package.json 依赖版本对齐
  • CI tsc 构建:@huggingface/transformers 直接可解析,无需额外安装

[1.7.8] - 2026-07-19

Added

  • Dart / Flutter 索引器:新增 .dart tree-sitter 索引器(class/mixin/extension/enum/typedef/function/import);忽略 .dart_tool;tree-sitter-wasms 升至 0.1.13,web-tree-sitter 升至 0.25.10(支持 Dart ABI 15)

[1.7.7] - 2026-07-19

Added

  • npm 幂等发布:scripts/publish-npm-idempotent.mjs,已发布版本不再因 E403 失败
  • 技能飞轮卫生:全 stopword 短语过滤、pruneFailedSkills 软隐藏毒技能、reportOutcome lessons 质量门
  • 架构检索加权:架构/CJK 查询优先 orchestrator / MCP / README,压低 types/errors/panels
  • 安装指令块:统一为 10 工具面 + graphflow_context + CallMcpTool 契约

Changed

  • CI / publish workflows 升级 Node 22
  • Marketplace:无密钥时 dispatch 跳过警告;tag 推送无密钥则明确失败;日志使用 GraphFlow Tool / graphflow-tool

[1.7.6] - 2026-07-19

Changed

  • VS Code 扩展更名:graphflow-vscode → graphflow-tool,规避 Marketplace displayName 冲突;VSIX 文件名同步改为 graphflow-tool
  • 扩展 displayName:更新为 GraphFlow Tool

[1.7.5] - 2026-07-18

Added

  • Qoder MCP / Skill 支持:自动检测用户级 ~/.qoder/mcp.json(Windows %APPDATA%/Qoder/User/mcp.json)与项目级 .qoder/mcp.json;Skill 安装至 ~/.qoder/skills/graphflow/SKILL.md
  • Agent Profile 模块化:新建 src/integrations/agent-profiles/ 目录与注册机制,各 IDE/Agent profile 独立成文件维护
  • 统一错误类型:新增标准化错误类型与处理函数
  • 增量索引取消机制:file-indexer 支持 AbortController 取消
  • Skill 健康检查:新增 Skill 完整性检测
  • previewContext LRU 缓存:新增 src/graph/context-cache.ts
  • VS Code Marketplace 自动发布:新增 publish-marketplace.yml workflow

Changed

  • 自动执行模式:LLM 仅在已配置且健康时启用,否则自动回退 bridge mode(src/core/orchestrator.ts)
  • 安装体验优化:无项目打开时由报错改为友好提示并提供打开文件夹按钮;npm 与插件安装后的项目引导提示统一

[1.7.4] - 2026-07-13

Added

  • DeepSeek 一等 provider:ProviderName 新增 deepseek;默认模型 deepseek-v4-pro / deepseek-v4-flash;Settings 可选 deepseek
  • 配置→env 桥接:resolveConfig 将 providers.*.apiKey/baseUrl 注入 DEEPSEEK_* / OPENAI_* 等(不覆盖已有环境变量)
  • DeepSeek 能力:思考模式(thinking + reasoning_effort)、JSON Output、reasoning_content 解析、KV cache usage 记录、可选只读 graph tool_calls

Fixed

  • LLM 配置无法联通:此前适配器只读环境变量,忽略配置文件中的 apiKey/baseUrl

[1.7.3] - 2026-07-12

Fixed

  • 无痛 Windows MCP:扩展激活时调用 repairUnsafeWindowsMcpCommands,自动扫描 Trae / Trae CN / TRAE SOLO 等已有 mcp.json,把含空格的 command 就地改成短路径或 node(无需手动 Install)
  • CI Test 挂死:禁用 vitest/CI 下 embedding 后台预热(HuggingFace MiniLM 下载无超时可卡 30m+);validate.yml 设置 GRAPHFLOW_SKIP_EMBEDDING_WARMUP=1

[1.7.2] - 2026-07-12

Fixed

  • Trae/Windows MCP install:buildMcpServerNode / 写入配置时统一将含空格的 command(如 C:\Program Files\nodejs\node.exe)转为 8.3 短路径或回退 node,避免 Trae Solo 经 cmd 无引号启动时出现 'C:\Program' 不是内部或外部命令

[1.7.1] - 2026-07-12

Added

  • Resilient local embedding:@xenova/transformers 缺失或加载失败时自动降级到 fnv1a-384 hash;支持从 workspace node_modules 解析
  • 可选全图向量召回:embeddingPolicy.enableFullGraphVectorRecall(默认 false),开启后对带 embedding 的图节点做 HNSW + RRF
  • P2 transformers 离线缓存路径:embeddingPolicy.modelCacheDir / transformersCachePath 或 GRAPHFLOW_EMBEDDING_CACHE_DIR
  • 测试:m77-embedding-fallback、m78-full-graph-vector-recall

Changed

  • 检索降噪:架构查询提升 src/graph/src/core 等,降低 vscode-extension/vendor/node_modules/非 src dist 权重
  • Adaptive budget 日志:logger.info → logger.debug,避免 MCP stderr 被 IDE 标成伪 error
  • Installer surface 冻结:当前 IDE/Agent 安装目标保持维护,不再继续扩展新的 IDE 自动安装面
  • VSIX / 扩展说明:graphflow-vscode@1.7.1 描述与 README 同步上述行为
  • Windows MCP launcher:优先 spawn .cjs,避免 .cmd + shell:false 的 EINVAL

Notes (VSIX)

  • VSIX 仍不捆绑 @xenova/transformers(体积与平台原生依赖)
  • 默认 hash embedding 可用;真语义请预置缓存目录

[1.7.0] - 2026-07-11

Added

  • P0 向量召回修正:引入 @xenova/transformers + all-MiniLM-L6-v2(384 维,约 22MB),实现真正的本地语义 embedding 召回
  • P2 ATP 自适应截断:简单任务(低优先级、无约束、短描述)自动 short-circuit,跳过 First Principles / Decision Matrix / Reflection,节省 4-6 次 LLM 调用
  • P2 MCP 工具精简:18 个工具合并为 10 个核心工具,降低 LLM 工具调用认知负荷

Changed

  • embedding provider 默认改为 transformers:替代原有的 FNV-1a hash embedding(伪语义)
  • MCP 工具合并:
    • graphflow_context = preview_context + expand_anchor
    • graphflow_plan = plan + plan_insight(mode 参数区分)
    • graphflow_index = index + index_file + rebuild
    • graphflow_insight = submit_insight + merge_insight
    • graphflow_diagnose = diagnose + inspect_graph + stats
    • graphflow_artifact = export_artifact + import_artifact

Removed

  • P1 移除 hnswlib-node:彻底移除 C++ 编译依赖,向量召回统一使用纯线性扫描
  • 移除 graphPolicy.enableHnsw 配置项及相关代码
  • 移除 hash embedding provider 及相关函数

[1.4.4] - 2026-07-05

Added

  • Antigravity IDE 安装:MCP 写入 ~/.gemini/antigravity/mcp_config.json;全局 Skill、项目 .agent/rules / .agent/skills;项目 GEMINI.md 受管块
  • Gemini CLI:共享 MCP 路径 ~/.gemini/config/mcp_config.json
  • GitHub Copilot:专用 .github/copilot-instructions.md 源文件(token-first,非 CLAUDE.md 副本)
  • Trae CN 项目安装:.trae/rules/graphflow.md(alwaysApply)与项目 Skill;doctor 自检
  • 测试:m62-trae-cn-install、m63-agents-install

Fixed

  • Antigravity MCP 路径错误:不再写入 VS Code Code/User/mcp.json
  • 用户级 MCP 污染:install 不再向用户配置注入 GRAPHFLOW_WORKSPACE_ROOT;切换策略时自动清除 stale env

[1.4.3] - 2026-07-05

Added

  • PascalCase/camelCase 拆词:BattlePage → battle + page,EnergyShield → shield 等,英文子词可命中代码符号
  • 合并 englishQuery 重排:RRF 子查询使用中文 + englishQuery + 子查询共同打分
  • UI 路径加权:含 avatar/shield/battle/camera 等 UI 意图时优先 src/pages/、src/components/

Fixed

  • TOKEN_SPLIT:不再把大写字母误当分隔符(修复 oldFunctionName 等标识符被错误切碎)
  • SQLite FTS:ASCII 单词前缀匹配(battle* → BattlePage),多词短语仍用 AND

Changed

  • Agent 翻译提示 / Skill:优先精确文件/类/组件名,避免泛化 exercise 误命中数据层

[1.4.2] - 2026-07-05

Added

  • CJK 查询支持:中文/日文/韩文分词与双字切分;FTS 对 CJK 查询使用 OR 匹配
  • Agent 委托翻译:graphflow_preview_context 新增 englishQuery;当 CJK 查询锚点不足时返回 agentWorkItems(query-translate-en),由连接的 Agent 翻译为英文符号关键词后重试
  • 多查询 RRF:expandSearchQueries 合并原始查询、Agent 英文翻译与工作区路径提示进行检索
  • 索引增强:Symbol 节点 content 附加 JSDoc 摘要(≤160 字符),提升中文意图对英文符号的命中

Fixed

  • 自动索引:preview_context 在图存储为空时即使 workspace 缓存已 warm 也会触发索引

[1.4.1] - 2026-07-05

Fixed

  • CI Windows 构建:package-windows 固定 windows-2022,修复 windows-latest(VS 2026)上 node-gyp 无法识别 VS 18 导致 hnswlib-node 编译失败
  • validate:Linux CI 增加 npm rebuild hnswlib-node,确保 HNSW 原生模块在测试前就绪
  • 文档一致性:同步 MCP 工具列表(移除 v1.4 已删除的 enrich_graph / model_download / metrics;补充 submit_insight / merge_insight / skill_guide)

Changed

  • README / 扩展 README:补充 VSIX 安装步骤(VS Code / Cursor)、MCP install 命令、hnswlib-node 原生编译环境说明

[1.4.0] - 2026-07-04

Changed

  • 奥卡姆剃刀精简:移除未产生真实价值的模块,保留三条经过验证的闭环链路。
    • 移除 OpenBMB 本地部署(provider-adapters/openbmb.ts)
    • 移除语义压缩模型(compression-model.ts、semantic-compression.ts)
    • 移除语义增强器(semantic-enricher.ts)
    • 移除技能进化(skill-evolution.ts)
    • 移除金丝雀门控(canary-gate.ts)
    • 移除本地嵌入模型(local-embedding.ts,改为零成本 hash embedding)
    • 移除向量存储(vector-store.ts,HNSW 直接内嵌)
    • 移除 @xenova/transformers 和 node-llama-cpp 依赖
    • hnswlib-node 从 optionalDependencies 移到 dependencies
    • embedding 默认 provider 从 "local" 改为 "hash"

Fixed

  • HNSW 向量召回完全打通(P0):file-indexer 现在为所有 File/Symbol/Module 节点附加 256 维 hash embedding(FNV-1a,零成本),HNSW 索引不再为空。
  • Orchestrator 向量召回激活(P0):orchestrator-context.ts:maybeBuildNearLosslessContext 现在传递 embeddingProvider + enableVectorRecall 到压缩管道,graphflow_run 路径的向量召回不再被跳过。
  • HNSW 索引持久化(P1):buildEnhancedContextPackage 现在从 vectorStorePath 派生 .hnsw 路径并传入 HnswVectorIndex,save()/loadIndex() 不再是空操作。
  • FileWatcher 接入 MCP 启动(P0):startFileWatcherIfEnabled 此前是死代码,现已接入 MCP 服务器启动路径,autoIndexOnSave: true 时自动监听文件变化并增量索引。
  • skillHints 解耦(P1):buildPromptContext 中 skillHints 不再依赖 enableGraphContextInPrompt === true,独立注入 worker prompt。
  • Dangling edges 修复(P1):applySkillLearning 现在先创建 Decision 节点再连 improves 边,不再产生指向不存在节点的悬空边。
  • buildPlanFromInsight null 安全(P0):insight.ts 异常时返回 null 而非 [],orchestrator 正确检测并回退到 planTasks。

Added

  • Agent MCP Installer 恢复并优化:支持 15+ Agent 自动检测安装(Cursor、VS Code、Trae、Claude Code、Windsurf、Cline、Roo Code、Kilo Code、PearAI、Gemini、Codex、Antigravity、Amazon Q、Zed、Continue);WSL 检测修复(platform() → release())。
  • Reflector 恢复并优化:reflectOnEpisodes 贪心聚类 + Lesson 提取;getLessonsForEpisode 提取到 episodic-memory.ts;Lesson 自动注入 planner prompt。
  • HNSW 恢复并优化:HnswVectorIndex 支持持久化加载/保存;大仓库自动 ANN,小仓库线性扫描。
  • Kotlin / Swift 索引器:新增 .kt 和 .swift tree-sitter 索引器。
  • hash embedding:零成本 FNV-1a 256 维向量,无需模型推理,作为 embedding 默认 provider。

Removed

  • src/graph/compression-model.ts
  • src/graph/semantic-compression.ts
  • src/graph/semantic-enricher.ts
  • src/learning/canary-gate.ts
  • src/learning/local-embedding.ts
  • src/learning/skill-evolution.ts
  • src/learning/vector-store.ts
  • src/routing/provider-adapters/openbmb.ts
  • src/types/node-llama-cpp.d.ts
  • 相关测试文件:m17、m17b、m17c、m20、m28、m29、m30、m31、m38、m47、m4m5

[1.3.4] - 2026-07-03

Fixed

  • MCP / Windows EPERM:修复 MCP 在 AppData\Local 等系统目录启动时误将系统路径当作工作区并扫描 ElevatedDiagnostics 导致 EPERM 的问题。
    • 目录遍历对 EPERM/EACCES 静默跳过(safe-fs)
    • 忽略 ElevatedDiagnostics 等 Windows 受保护目录
    • ensureMcpWorkspaceEnv 不再将 LOCALAPPDATA 根目录当作隐式工作区;优先使用 IDE 环境变量(VSCODE_CWD 等)

[1.3.3] - 2026-07-03

Fixed

  • VS Code 扩展(WSL):激活时默认仅写入用户级 MCP(~/.config/Code/User/mcp.json),不再自动创建项目级 .vscode/mcp.json 与项目 Rules,避免 WSL 下 GUI 提交触发 git hook 时与 pyenv 环境冲突。项目级安装改为显式执行 GraphFlow: Install MCP to Agents。
  • MCP 启动:仅在原生 Windows 传入 electronExecPath,Linux/WSL 不再写入 IDE 可执行路径。

[1.3.1] - 2026-06-29

Added

  • graphflow_skill_guide MCP 工具:通过 MCP 协议直接提供 Skill 指南内容,不依赖外部文件安装,解决 C 盘权限不足导致 Skill 无法使用的问题。

Changed

  • 工作区级 Skill 回退安装:当用户级目录(如 ~/.trae/User/skills/)写入失败时,自动回退安装到项目目录 .graphflow/skills/graphflow/SKILL.md。
  • MCP 工具描述增强:核心工具描述添加"Context First"原则:
    • graphflow_preview_context:强调"ALWAYS CALL THIS FIRST"
    • graphflow_plan:强调"USE AFTER graphflow_preview_context"
    • graphflow_expand_anchor:强调"USE THIS AFTER graphflow_preview_context"
    • graphflow_index:强调"CALL AFTER significant file changes"

Fixed

  • C 盘权限不足导致 Skill 无法使用:通过 graphflow_skill_guide 工具和工作区级回退安装双重保障,确保即使没有 C 盘编辑权限也能正常使用 GraphFlow。

[1.3.0] - 2026-06-28

Added

  • Agent Skill 安装:installAllSkills 写入 Cursor / Claude Code / Codex 的 skills/graphflow/SKILL.md(非保留目录 skills-cursor)。
  • graphflow doctor:自检各 agent 的 MCP 注册、指令文件与 Agent Skill 状态。
  • 委托模式 5-Why:agentWorkItems 新增 6 个可选 five-whys 项;merge 解析 whyChain 并填充 rootCauses。
  • Token benchmark:benchmarks/run-token-benchmark.ts 与 npm run benchmark。
  • 竞品分析:docs/comparison.md。
  • 测试:tests/m17b-agent-instructions.test.ts(Claude MCP 路径 + 指令块安装)。

Changed

  • 启发式 planTasks:支持中文连词拆分;单句任务生成分析→实现→测试三阶段 DAG。
  • refinedTaskStatement:无 5-Why 根因时回退蓝帽综合,避免误显示「待探索」。
  • MCP 安装路径:Claude Code → ~/.claude.json;Gemini → ~/.gemini/settings.json。
  • Windsurf / Codex / Gemini 全局指令块(append-with-markers 安全写入)。
  • README 快速上手与竞品对比表更新。

Fixed

  • Cursor 用户此前只能看到 Rule、看不到 Skill 的问题(现同时安装 Rule + Skill)。

[1.0.9] - 2026-06-26

Added

  • Agent-delegated LLM(无 API 模式):未配置 provider API 时,graphflow_plan_insight / complex graphflow_run 返回 agentWorkItems,由连接的 coding agent 用自己的模型回答 Six Hats prompts。
  • MCP 闭环工具:graphflow_submit_insight(回传每条 work item 分析)、graphflow_merge_insight(合并为完整 insight + DAG plan)。
  • Skill 质量:extractSkillAtoms 过滤 stopwords / 路径噪声,保留短语与 head token。
  • Adaptive budget:complex 任务默认启用自适应 token 预算;配置默认 enableAdaptiveBudget: true。
  • Calls 边增强:caller 缺失时按行号回退解析;Snapshot 优先展示 calls / defines 边。
  • L2/L3 锚点:Module 父节点与架构类查询的 Skill/Decision 注入。
  • Monorepo:discoverWorkspacePackages + Snapshot workspacePackage 元数据。
  • 语言索引:Kotlin(.kt/.kts)、Swift(.swift)tree-sitter 索引器。
  • MCP 模块化:拆分 tool-definitions.ts / tool-handlers.ts / version.ts。
  • VS Code:Agent Work Items 面板、graphflow.planInsight 命令;Chat /insight 与 agent-delegated 闭环指引。

Changed

  • Bridge 文档强化:report_outcome / submit_insight 为必做步骤(AGENTS.md、Cursor rules)。
  • graphflow_inspect_graph 支持 monorepo 包分组。

Fixed

  • parseAgentInsightResponse 优先解析 JSON 数组(plan-refinement)。
  • Skill 融合测试与 stopword 过滤的平衡(m20 回归)。

[1.0.3] - 2026-06-24

Fixed

  • CI:m17 测试不再硬编码 /usr/bin/node,兼容 GitHub Actions hosted Node 路径。
  • 图谱存储:graphify-file-client 原子写入(temp + rename);损坏 JSON 时优雅降级为空 store 并提示 rebuild。
  • 上下文检索:rankNodesForContextQuery 降低 .cursor/mcp.json、docs/integrations 等配置噪声,优先 src/ 与 Symbol 节点。
  • MCP metrics:graphflow_metrics 支持 rootDir 并绑定工作区。

[1.0.2] - 2026-06-24

Fixed

  • MCP ENOENT(fnm 临时路径):安装 MCP 时不再写入 fnm multishell 临时 node 绝对路径;优先使用 IDE 自带 Electron(ELECTRON_RUN_AS_NODE),否则回退稳定 node。
  • Trae CN 支持:安装器识别 ~/.trae-cn 并写入 ~/.config/Trae CN/User/mcp.json。

[1.0.1] - 2026-06-24

Fixed

  • 多项目工作区隔离:MCP / 扩展 / npm 包不再把图谱绑定到 vendor 目录或全局配置里的陈旧 workspaceRoot。
  • 自动发现工作区:新增 discover-workspace,从 cwd 向上查找项目根;仅在 runtime 目录(vendor、extensions)时回退到 IDE 环境变量。
  • MCP launcher:子进程 cwd 与 GRAPHFLOW_WORKSPACE_ROOT 指向用户打开的项目,不再固定在扩展 vendor。
  • MCP 安装器:默认写入 GRAPHFLOW_WORKSPACE_ROOT: "${workspaceFolder}",merge 已有 env,扩展有工作区时同时写用户级与项目级配置。
  • MCP 工具:preview_context、inspect_graph、skill_insights、stats 支持可选 rootDir 覆盖。

[1.0.0] - 2026-06-19

首个正式版本。在 0.6.x 基础上完成「诚实执行语义」收敛与「上下文压缩」体系,所有新增能力均端到端接线到 CLI / MCP / orchestrator。

Added

  • 混合压缩模型策略(compressor role):新增 compressor 角色,默认复用 economy tier(backend: "inherit")——配置了外部 provider(OpenAI/Anthropic/百炼)就用其 economy 模型,纯离线则回退内嵌 minicpm。零额外配置。
  • 内嵌模型首次自动下载:无外部 LLM 时,resolveCompressionModel 复用既有断点续传下载器,首次按需拉取 minicpm GGUF 到 ~/.graphflow/models/(类似 Playwright 浏览器下载)。
  • 图结构压缩(零成本,默认开启):graph-compression.ts 提供边权重加权连通子图(extractConnectedSubgraph)、加权 PageRank 中心性(computePageRank)、检索序与中心性融合重排(blendWithCentrality)。preview / orchestrator 默认启用。
  • 语义压缩(opt-in):semantic-compression.ts 通过 minicpm/economy LLM 对相似节点聚类合并(clusterSimilarNodes + summarizeCluster)、长节点改写(densifyNodeContent),由 graphPolicy.compression.enabled 开启。
  • RepoMap 概览模式(opt-in):repo-map.ts 在 token 预算紧张时返回模块级地图(每模块一行 exports 摘要),由 compression.enableRepoMapFallback 开启。
  • 自适应 Token 预算(opt-in):adaptive-budget.ts 的 estimateContextBudget 按任务复杂度(refactor/多文件/架构/局部修复/加测试)动态调整预算,由 compression.enableAdaptiveBudget 开启。
  • HNSW 向量索引(可选依赖):hnsw-index.ts 在候选集 ≥200 节点时使用 hnswlib-node ANN 加速(10~100x),未安装时优雅降级线性扫描。hnswlib-node 列为 optionalDependency。
  • buildEnhancedContextPackage:统一六步压缩 pipeline(RepoMap fallback → 关键词+向量召回 → 图压缩 → 语义压缩 → 分层配额 → 边扩展),preview 与 orchestrator 共用。
  • 压缩诊断:route diagnose 输出新增 compression=<backend>:<provider>/<model> 行,可查当前压缩模型来源。
  • 测试 m43(bridge 模式)、m44(增强压缩)、m45(真机 benchmark)。

Changed

  • 执行语义诚实化(bridge 模式):graphflow_run 默认进入 bridge 模式——规划 + 压缩上下文后输出 executionDescriptor 移交外部 coding agent 执行,状态为 HUMAN_REVIEW_REQUIRED 并标注 [DELEGATED],不再伪造 COMPLETED。
  • 校验启发式标注:规则校验结果统一标注 [heuristic] 与 heuristic_validation riskTag;检测并拒绝 provider 占位符回显([openai:model] ...)。
  • graphPolicy.compression 配置项扩展:enableGraphCompression / enableRepoMapFallback / enableAdaptiveBudget / enableHnsw。

Fixed

  • worker 兜底分支不再返回 "Simulated change..." 伪造输出,无可用执行模式时抛出明确错误。
  • README 版本号、测试数与失效文档引用同步至 1.0。

Added

  • MCP server 优雅停机:监听 SIGTERM/SIGINT,停止接收新的 stdin 输入并给在途请求短暂 flush 窗口后退出,避免长驻进程被硬杀导致状态丢失。
  • VectorStore.close():释放底层 SQLite 句柄,与 SqliteClient.close() 对齐,避免长驻进程文件描述符泄漏。
  • MCP 工具入参长度上限(MAX_STRING_FIELD_LENGTH),防止超大 payload / prompt injection 风险。

Changed

  • provider-executor 改用结构化 logger 替换裸 console.warn/error,确保生产环境日志可被聚合采集。
  • orchestrate() 增加顶层错误边界:上下文构建 / DAG 执行 / 图同步的未捕获异常统一收敛为结构化 HUMAN_REVIEW_REQUIRED 结果,不再裸抛给调用方。

Fixed

  • DAG 执行 timeout 定时器在任务成功路径未被清除,长驻进程下存在 timer 泄漏;改为 finally 中 clearTimeout。
  • m12-dynamic-routing 测试不再依赖对 api.anthropic.com 的外网可达性:将 anthropic baseUrl 指向本地立即拒绝连接的地址,确定性触发非 strict 降级路径。

[0.6.13] - 2026-06-14

Fixed

  • 知识图谱面板力导向布局在大量节点时坐标爆炸,导致 viewBox 过大、画布仅显示角落小点;布局后归一化到画布并收紧力模拟参数。

[0.6.12] - 2026-06-14

Added

  • snapshot-view 模块:图谱样本的可读标签(displayLabel、displayPath、folderGroup)、分层视图(代码层 / 学习层)、按目录多样性采样。
  • 知识图谱面板:暗色主题、分层 Tab、目录聚类着色、关系线型区分、双击/按钮跳转源文件。

Changed

  • inspectGraph 默认样本上限提升至 96 节点 / 160 边;VS Code「查看图谱」命令使用 120 / 200。
  • 节点摘要预览长度由 96 提升至 160 字符。

[0.6.11] - 2026-06-14

Changed

  • 默认开启 autoIndexOnSave:保存/变更文件后 debounce 增量索引,实现项目更新时持续静默建图。
  • 路由就绪校验要求开启 Auto index on file save。
  • 旧配置中遗留的 maxContextTokens: 400 自动升级到 1500。
  • graphflow.config.example.json 同步 autoIndexOnSave 与 maxContextTokens: 1500。

[0.6.10] - 2026-06-14

Added

  • runtime/ 子模块:env、settings、graph、routing、panel、helpers、facade。
  • GraphFlowRuntimeModule 与 assertGraphFlowRuntime():扩展动态加载时使用统一类型校验。
  • VS Code 扩展 esbuild 单文件打包(dist/extension.js)。

Changed

  • runtime.ts 改为薄 re-export 层;业务逻辑拆分到子模块。
  • 扩展移除手写 GraphFlowRuntime 接口,改用 core 导出的类型。

[0.6.9] - 2026-06-14

Added

  • loadConfigSafe:损坏/缺失配置文件时回退默认配置并记录告警。
  • hasPendingGraphIndexWork:无文件变更时跳过 preview/run 的自动索引。
  • runtime/types.ts:CLI/MCP 公共类型集中导出。
  • vscode-extension/src/workspace.ts:可测试的工作区 cwd 解析。
  • 测试 m41-optimization-hardening。

Changed

  • postinstall 默认不再自动 init/MCP 注入;需 GRAPHFLOW_ENABLE_POSTINSTALL=1 显式开启。
  • CI 根依赖安装改为 npm ci,提升可复现构建。
  • 默认 maxContextTokens 从 400 提升到 1500,避免宽查询预览为空。
  • 文件索引器合并 stat 遍历,减少重复 I/O。
  • VSIX .vscodeignore 裁剪 vendor 中的 map/d.ts/tests/docs。

Fixed

  • 损坏的全局/项目 JSON 不再导致 GraphFlow 启动失败。

[0.6.8] - 2026-06-14

Fixed

  • 扩展在无工作区文件夹时也可打开 Settings 并保存全局模型配置;首次安装自动弹出 Settings 面板。
  • showSetupGuide 不再因未打开项目而失败;图谱建立/路由测试在无工作区时给出中文提示。

[0.6.7] - 2026-06-14

Added

  • 全局配置优先:resolveWritableConfigPath 默认将 Settings 保存到 ~/.graphflow.config.json。
  • MCP 安装范围:installScope: "user" | "all",默认仅写入用户级 Agent 配置(如 ~/.cursor/mcp.json)。
  • 测试 m40-config-global-first:覆盖全局读取/写入与 MCP 用户级默认行为。

Changed

  • 扩展首次安装只 scaffold 全局 ~/.graphflow.config.json,不再自动创建 .graphflow/config.json 工作区覆盖层。
  • resolveConfig 以全局配置为底,项目 graphflow.config.json / .graphflow/config.json 作为可选覆盖层合并。
  • npm postinstall / graphflow init 改为全局配置 + 用户级 MCP;README 说明更新为一次配置、所有项目可用。
  • 配置指南(formatModelConfigGuide)优先展示全局配置路径。

Fixed

  • saveGraphFlowSettings 补全 resolveGlobalConfigPath 导入,修复扩展打包 TypeScript 编译错误。

[0.6.6] - 2026-06-11

Added

  • Settings 面板:建立图谱(无需 LLM) — 仅需图谱存储路径即可扫描工作区并生成结构图谱(文件、符号、依赖)。
  • Settings 面板:路由连通性测试(可选) — LLM 配置就绪后探测 Smart / Economy 路由,连通通过后自动索引并可运行语义提取。
  • Runtime API:indexGraphFromSettings、testRoutingAndIndexGraph、validateSettingsForGraphIndex、validateSettingsForRouting。

Changed

  • 配置指南明确双路径:无 LLM 结构索引与可选 LLM 路由验证并存;语义提取失败时仍保留结构图谱。

[0.6.5] - 2026-06-11

Added

  • Settings 面板:图谱状态(节点/边数、上次索引时间)、配置覆盖层 diff、一键路由诊断。
  • graphPolicy.autoIndexOnSave:保存文件后 debounce 增量索引(Extension 可选开关)。
  • getSettingsPanelStatus / listConfigOverlayKeys:Settings 与 CLI 共用状态 API。
  • Husky pre-push:lint-staged 在推送前自动跑 ESLint。
  • CI:validate.yml 可复用工作流;PR 与 main 发布分离;v* tag 触发 Build / npm publish。
  • postinstall 完成后轻量 bootstrap indexGraph(非 CI 环境)。

Fixed

  • Settings 面板 HTML 模板中反引号导致 ESLint 解析失败,阻断 0.6.5 GitHub Actions 与 Release。

Changed

  • 收紧多处 any 类型;提交 vitest.config.ts 排除 extension 测试。
  • README 更新至 v0.6.5,补充 Release 与本地 npm run ci 说明。

[0.6.4] - 2026-06-10

Added

  • graphPolicy.semanticEnrichment.backend: inherit | network | local,明确区分网络模型与本地 OpenBMB。
  • 语义提取可单独配置网络 API Key / Base URL(semanticEnrichment.apiKey / baseUrl)。
  • Settings 面板「语义提取后端」:继承 Economy(网络)/ 自定义网络模型 / 本地 OpenBMB。

Changed

  • 语义富化运行时注入独立网络凭证(applyEnrichmentProviderEnv);任务编排后增量富化同步应用。
  • MCP graphflow_enrich_graph 描述更新为支持云端或本地后端。

[0.6.3] - 2026-06-10

Added

  • src/config/secrets.ts: API Key 支持环境变量名、${VAR} 占位符、或直接 sk-... 明文;运行时按类型自动解析。
  • Settings 面板新增 Graph Semantic Enrichment(知识图谱语义提取):可单独配置 provider/model,或留空继承 Economy 层。
  • graphPolicy.semanticEnrichment.provider 可选字段,允许语义提取使用与 Worker 不同的 provider。

Changed

  • Smart / Economy 模型改为可选;未配置时由 model-router 默认表按 provider 回退。
  • 语义提取模型不再默认 minicpm5-1b;可配置 DeepSeek(openai + baseUrl + 模型名)或其它云端/本地模型,也可留空。
  • OpenBMB 设置与语义提取解耦;OpenBMB 区块仅用于本地 MiniCPM。
  • formatModelConfigGuide 与初始化文档补充 API Key 规则与图谱更新说明。

[0.6.2] - 2026-06-10

Fixed

  • MCP install on Windows now uses mcp-launcher.cmd / mcp-launcher.cjs so server.js is never the MCP command (fixes Cursor opening the file as an editor tab).
  • Vendor bundle skips Linux-only onnxruntime-node; GitHub Release VSIX is built on windows-latest.
  • CI: Ubuntu runs full tests; Windows job only packages the VSIX. SQLite tests skip when optional better-sqlite3 is unavailable.

[0.6.1] - 2026-06-10

Fixed

  • MCP auto-install now uses system node (or Cursor/Electron with ELECTRON_RUN_AS_NODE) instead of writing process.execPath from the extension host, which broke MCP stdio on other machines.
  • MCP server logs are redirected to stderr so JSON-RPC on stdout is not corrupted.
  • Bundled MCP cwd points at the extension vendor runtime root for reliable module resolution.
  • Extension first-install now scaffolds ~/.graphflow.config.json (global) and workspace .graphflow/config.json when a folder is open.

[0.6.0] - 2026-06-09

Added

  • Agent MCP auto-installer: sniffs Cursor, VS Code, Trae, Claude Code, and Windsurf; writes GraphFlow MCP to user and workspace config (creates missing files).
  • VS Code extension auto-installs bundled MCP on first install/upgrade (onStartupFinished).
  • New extension commands: GraphFlow: Install MCP to Agents, GraphFlow: Model Setup Guide.
  • Post-install model configuration guide in Output panel and .graphflow/README.md.

[0.4.2] - 2026-06-01

Fixed

  • VS Code extension host Cannot find module 'typescript': typescriptIndexer now loads typescript via createRequire lazily and falls back to the regex extractor when unavailable.
  • sync-runtime.mjs now bundles typescript and gpt-tokenizer into vendor/graphflow/node_modules/ so the extension runtime can resolve them; .vscodeignore explicitly whitelists vendor/**.

[0.4.1] - 2026-06-01

Fixed

  • VS Code extension host Cannot find module 'better-sqlite3': sqlite-client switched to dynamic createRequire; client-factory catches the load failure and degrades the sqlite transport to GraphifyFileClient with a single warning instead of crashing.
  • Moved better-sqlite3 from dependencies to optionalDependencies so installs without native build tooling still succeed.

[0.4.0] - 2026-05-31

Added

  • StdIO MCP server entrypoint (graphflow-mcp) for Cursor, Claude Code, and other MCP-capable agents.
  • JSON CLI mode for all primary commands via --json.
  • Agent guidance files: AGENTS.md, CLAUDE.md, and .cursor/rules/graphflow.mdc.
  • Integration config samples under docs/integrations/.
  • CLI help/version entrypoints (--help, --version).
  • AST-based workspace indexer (TypeScript Compiler API) emitting real Symbol nodes (function/class/interface/type/enum/variable/method) and cross-file references edges, with regex fallback on parse errors.
  • LLM-driven agent variants: planTasksLlm, brainstormTaskLlm, validateTaskResultLlm, each with deterministic JSON fallback.
  • Orchestrator options enableLlmAgents, enableDriftReplan, maxReplanRounds — failed DAG triggers a planner re-plan loop with previousPlan + failureFeedback before HUMAN_REVIEW.
  • Skill fusion: composite Skill nodes synthesized when coOccurCount >= 2 && successCount >= 2; prerequisite edges A→C and B→C; suggestSkillHints prioritizes composite skills when both parents match.
  • Prompt context injection: executeRolePrompt accepts PromptContext; orchestrator option enableGraphContextInPrompt threads summaryChannel + skillHints into planner / brainstormer / worker / validator prompts; TaskRunResult.promptContextLines records actual injected lines.
  • Node content compression: Symbol content is a signature line (function planTasks (exported) @src/agents/planner.ts:14), File content adds # exports: ... suffix, raw JSON moved to optional GraphNode.metadata (~1.76× byte reduction per Symbol).
  • Real tokenizer (gpt-tokenizer / o200k_base, lazy-loaded with graceful fallback) replaces length/4 token estimate.
  • Inverted-index keyword lookup + adjacency lists on memory and file graph clients; new getNodesByIds and getNeighbors (optional on MCP client).
  • expandSubgraph BFS along references / imports / depends_on / prerequisite edges; buildLayeredContextPackage pulls 1-hop neighbors of top hits into the same token budget (opt-out via LayeredPackageOptions.enableEdgeExpansion=false).
  • SQLite + FTS5 graph backend (transport: "sqlite") via better-sqlite3: WAL mode, idempotent CREATE schema, FTS5 sync triggers, edges PK + from/to/relation indexes; implements getNodesByIds and getNeighbors.
  • Vector recall with reciprocal-rank fusion: src/learning/embeddings.ts provides deterministic hashEmbedding + createOpenAiEmbeddingProvider + reciprocalRankFusion; buildLayeredContextPackage accepts enableVectorRecall / embeddingProvider / vectorTopK / vectorMinSimilarity for semantic+keyword fusion.
  • Episodic Memory + Reflection: src/learning/episodic-memory.ts persists Episode nodes per task run; src/learning/reflector.ts clusters similar episodes and synthesizes Lesson nodes with improves edges; orchestrator enableEpisodicMemory injects past keyDecisions into PromptContext.extraInstructions; nightly-trainer optionally runs reflection when given a graph client.
  • Cross-language workspace indexer: TypeScript / JavaScript (AST via TS Compiler API) + Python / Rust / Go / C / C++ (regex-based) via dispatch in src/graph/language-indexers/; uniform Symbol / Module / defines / imports / references output across all languages.
  • Tests: m16 agent integrations, m17 release readiness, m18 AST indexer, m19 LLM agents + drift, m20 skill fusion, m21 prompt context injection, m22 node compression, m23 graph retrieval, m24 SQLite backend, m25 vector recall, m26 episodic memory, m27 multi-language indexer.

Changed

  • Root package metadata now matches Apache-2.0 and publishes graphflow / graphflow-mcp binaries.
  • Default router and example config models now use gpt-4.1 and gpt-4.1-mini.
  • Config loader now resolves ${ENV_VAR} placeholders from the process environment.
  • Failed runTask executions now append negative feedback events for the learning flywheel.
  • File indexer skips symbolic links while crawling a workspace.
  • GraphClient interface extended with optional getNodesByIds / getNeighbors; MCP client degrades to [] on unsupported endpoints.
  • graphPolicy.transport accepts "sqlite" in addition to "memory" | "file" | "mcp-http".

Verified

  • npm run ci
  • npx vitest run — 25 test files / 95 tests passing

[0.3.0] - 2026-05-28

GraphFlow 在 0.3.0 完成了从“可跑的多智能体原型”到“可安装、可观测、可分发产品版”的收敛:

  • CLI、VS Code 命令面板、@graphflow chat 三个入口全部打通
  • 图谱存储切到本地持久化默认路径,支持观测与复用
  • 学习飞轮、动态路由、夜跑训练、扩展打包与 CI 已形成闭环
  • 正式使用测试已沉淀到 docs/testing/2026-05-28-formal-usage-test-report.md

Added

  • Core orchestration pipeline with simple/complex routing and DAG execution.
  • Validator retry loop with human review fallback state.
  • Criteria-based validation with matched/missing requirement reporting.
  • Model tier routing and provider fallback path (OpenAI, Anthropic, 百炼, 豆包).
  • Graph client factory with file, memory and Graphify MCP HTTP transports.
  • Automatic graph sync after successful run.
  • Near-lossless context packaging:
    • summary + anchor dual channel
    • L1/L2/L3 quotas
    • dynamic refill manager with de-dup anchors
  • Workspace file indexer for File/Symbol graph nodes.
  • CLI commands:
    • run
    • plan
    • context preview
    • graph index
    • graph inspect
    • skill insights
  • Learning flywheel baseline:
    • feedback collector
    • sample builder
    • learning dataset exporter
    • canary gate
  • VS Code extension scaffold integrated with GraphFlow runtime.
  • VS Code extension command added: GraphFlow: Plan & Brainstorm.
  • VS Code chat participant added: @graphflow with /run, /plan, /history.
  • Dynamic routing health evaluation and configurable provider priority (routingPolicy).
  • GitHub Actions CI workflow for lint/build/test/extension-build.
  • CLI routing diagnostics command: graphflow route diagnose.
  • CLI nightly learning command: graphflow learn nightly.
  • Learning event persistence and nightly summary generation.
  • File indexer now captures Module nodes and imports/defines graph edges.
  • Skill flywheel module with skill extraction, skill scoring, and skill co-occurrence graph updates.
  • Orchestrator integration for learned skill hints in planning and execution feedback.
  • New chat slash commands: @graphflow /diagnose and @graphflow /learn.
  • New chat slash commands: @graphflow /graph and @graphflow /skills.
  • VS Code extension now bundles GraphFlow runtime, removing dependency on workspace npm run start.
  • VS Code extension interactive observability panels:
    • Graph Snapshot with search, type filter, node focus, relation highlight
    • Skill Insights with search, outcome filter, and score/uses/time sorting
  • Config template: graphflow.config.example.json.
  • Formal usage test plan and final pass report under docs/testing/.

Changed

  • README updated to match implemented features and runnable commands.
  • Release notes updated to reflect bundled runtime, observability panels, and formal validation artifacts.
  • Config schema expanded with graph and near-lossless controls.
  • Default graph transport updated to file for persistent local usage testing.
  • Config schema expanded with skillPolicy controls.

Verified

  • npm run lint
  • npm run build
  • npm test (40 tests passing)
  • CLI smoke checks for graph index and context preview
  • CLI smoke check for plan
  • CLI smoke checks for route diagnose and learn nightly
  • CLI smoke checks for graph inspect and skill insights
  • VS Code extension build
  • VS Code extension package (artifacts/graphflow-vscode-0.3.0.vsix)