Skip to content

release-v0.1.12

Latest

Choose a tag to compare

@Moowningstar Moowningstar released this 06 Nov 03:41

0.1.12

把读路径的门关完,并第一次回答「这一窗改了什么」。

0.1.11 给写路径和图的投影装了存储闸,但读路径(搜索、三个图工具、项目列表)仍然只问「清单在不在」——一个被复制或移动过的检出,会安静地读到别人的图。0.1.12 把这半扇门关上。同时补上三件小事:一次会话里到底改了什么(而不只是「与索引不同」)、脚本/测试这类没有符号的改动不再让 detect_changes 的输出显得像索引坏了、系统提示里那行改动集终于带上了它说的是哪个仓库。


新增

读路径也用同一张存储词表

0.1.11 的 assertUsableStorage 只覆盖 projectGraph 与 projectViaHelper。搜索与三个图工具(impact/context/query)的宿主侧入口仍走旧口径:isProjectRoot → readIndexMeta → 查 .gitnexus/lbug 存在。后果是 foreign(清单指向另一个检出)或 unknown(字节读不出来)的仓库,只要 lbug 文件还在,就会照常返回结果——只是那些结果是别人的图。

  • src/gitnexus/storage-state.ts 新增 storageReadBlock(storage):owned 返回 null,其余六态返回 { code, message },code 为 no-index(missing/empty)或 index-not-usable(其余)。句子复用 describeBlockedStorage,所以面板、工具与路由说的是同一句话。
  • 闸门必须在 readIndexMeta 之前:后者会把 foreign 清单原样解析并返回(它只做 JSON 解析,不校验 repoPath),放在后面等于先读了别人的元数据再问「能不能读」。
  • searchSymbols、searchViaHelper、searchText 三个入口各加同一道闸,抛 SearchError('index-not-usable', 409, …);SearchErrorCode 与 searchErrorCode() 白名单同步加码。
  • runGraphTool(三个图工具的宿主入口)加同一道闸,返回 failure('index-not-usable', …);GraphToolErrorCode 与 MESSAGES 同步。
  • 路由与客户端不需要改:src/routes/search.ts 原样透传 code/status,面板对 409 直接显示 message(它只特判 404)。
  • 刻意不改的路由:file-history、file-diff、checkout 走的是 git 对象,不读图;存储不可用时它们仍然可以回答「这个提交改了什么」。
  • missing/empty 的搜索文案从「初始化后才能搜索」变成共享句「初始化后才能看图」——同一个状态在四个入口说同一句话,比每个入口各写一句更不容易漂。

这一窗改了什么(会话账本)

git activity 卡片回答的是「与索引不同的文件」,delta 回答的是「要不要刷新」。两者都不是「这一轮里我改了几次、改了什么」:一个文件存了三次又改回去,delta 只有一条,活动列表也只有一条。

  • src/gitnexus/ledger.ts:按「脏窗」聚合。工作树从干净变脏时开窗;窗内 HEAD 变化立即关窗(head),仍脏则另起一窗;变回干净关窗(clean);追踪器停止时冻结为 idle(不丢弃——那一窗发生过的事仍然成立)。上限 200 个路径,截断时 truncated: true。
  • 计数按内容哈希:第一次出现计 1;之后只有哈希与上次不同才 +1,所以「打开文件按了保存、内容没变」不会虚增。哈希来自 readDelta 的 hashAdded 选项(默认关闭,保持 delta 原有成本;追踪器开启它,因为账本需要证据)。
  • 账本明说证据强度:evidence: 'hash' | 'pending'。刚写入、还没比对过哈希的路径进入 pending(面板与路由都列出它们),而不是被当成「没有改动」。
  • GET /api/gitnexus/ledger?repo=<project>:只读,回答 { repo, tracking, degraded, ledger, pending, version };ledger: null 区分三种情况——还没开过窗、追踪器没起来(tracking: false + degraded)、宿主没挂这个路由(客户端 ledgerRoute: 'missing')。文案三句不同,不合并。
  • 面板「本次会话」卡片放在活动区,与 git activity 同屏:它回答的是同一类问题。卡片显示窗口状态(进行中/已结束及原因)、改/增/删计数、不在索引的路径、被索引策略排除的数量,以及每个路径的 ×N 与「不在索引」标记。
  • 不做:内容、diff、行号、落盘、按 agent 归属、跨仓库合并。账本只记路径、次数、时间与哈希证据。

没有符号的改动不再像「索引坏了」

detect_changes 对脚本形态的文件(src/bin/*.ts、测试入口——整个文件体是顶层语句,没有函数声明)永远映射不到符号,输出恒为 PARTIAL。这与索引新鲜度无关,但读起来像索引过期。

  • DeltaReport 新增 attribution: 'symbols' | 'not-applicable' | 'unknown':改动集全落在索引未覆盖的文件 → not-applicable;全是被策略排除的文件 → unknown;干净或至少一处命中索引 → symbols。
  • 文案一句话(SYMBOL_ATTRIBUTION_NOTICE)同时出现在 describeDelta 与面板刷新卡:「本次改动全部落在索引未覆盖的文件(脚本/测试入口/文档),符号归因不适用——这不是索引过期。」客户端不能 import 宿主模块,所以是第二份字面量,由测试钉住措辞。
  • 旧宿主没有该字段时,面板不显示这句(类型上可选,测试覆盖)。

改动集那一行现在有主语

系统提示里的那一行以前取「第一个有非空改动集的 tracker」,不说仓库名。实测后果:在一个干净检出里工作的 agent 被告知「8 改、92 增、90 删;3 处确定断裂」——那是另一个被追踪项目的数据,而句子里没有任何东西表明这一点。

  • 选择规则改为「deltaAt 最新者」(插件拿不到会话目录:config 没有 workspace root,process.cwd() 是 DSH 安装目录),句子改为「改动集(仓库名):…」。
  • 代码抽到 src/gitnexus/watch/change-scope.ts 的纯函数 describeChangeScope,src/index.ts 只留一层 try/catch wrapper——「不能因为 tracker 正在拆除就让提示组装失败」。
  • 干净树仍然返回空串:每轮都说「没有改动」会让模型学会忽略这一行。
  • precheck: false 仍然同时关掉门与这一行。

修正

  • 索引按文件名跳过的锁文件(package-lock.json、pnpm-lock.yaml 等,上游 IGNORED_FILES)不再被算成「新增」。审计时实测:本仓库在 0e9e51b 的索引基线上,8576f11 里改过的 package-lock.json 被报成 1 增 / 索引落后,于是提示行每一轮都说「0 改、1 增」;而刷新永远不会收录它,所以这个「落后」是不可消除的。NAME_IGNORED_FILES 让这些路径进 excluded,理由写明是名字规则。
  • AGENTS.md 的版本口径三处更正:日常驱动是实测装在这里的版本(2026-11-04 全局与受管前缀都是 gitnexus@1.6.12;上游 rc 已到 1.6.13-rc.201,latest 仍是 1.6.12),本 checkout 的 .gitnexus 是 42 存储(runnerIdentity.cliVersion 是 1.6.12),契约矩阵是某一天的记录(rc.159)而不是对当前候选的断言。
  • searchViaHelper 的 409 顺序:存储闸在 isProjectRoot 之后、readIndexMeta 之前,所以一个没有 shell 的 foreign 仓库现在报「存储不可用」而不是「没有 shell」——前者是它能确定的事实。
  • 测试从 1429 增至 1520(引擎 994→1072,插件 90→92,客户端 345→356);面板卡片位置与计划里写的「紧挨 Git 活动」不同:它排在依赖风险卡之后、Git 活动之前。

已知限制

  • 账本的窗口边界是「追踪器看到的脏」,不是「agent 的一次任务」:中间没有提交、但停手很久,仍然算同一窗(只有 idle 冻结时才算结束)。
  • evidence: 'pending' 只覆盖「刚写入、还没比对」的路径;如果追踪器在比对前被停止,这些路径会以 pending 留在快照里,而不是被补算。
  • 读路径闸只覆盖搜索与三个图工具;discover(项目列表)仍按清单存在与否判定 complete,没有按存储状态过滤——这是 0.1.13 的候选(连同孤立影子文件的可见性)。
  • 会话账本不落盘:进程重启即丢,这是有意的(落盘需要先决定脱敏与保留期)。
  • not-applicable 的判定只问「改动文件是否在 fileHashes 里」,不判断文件里是否真的有符号;一个被索引的脚本文件仍然算 symbols。