Theme / v0.9.73

Graphify

Codebase 知識圖譜

基礎觀念

v0.9.66 → v0.9.69:五個新語言 Extractor、決定性與安全修復

理解 v0.9.66~v0.9.69 四個 patch 的重點:COBOL/VB.NET/R/Solidity/Erlang 新語言支援、OCaml/Elixir/Fortran/Julia/Kotlin 結構深度、PYTHONHASHSEED 決定性與 Windows 重啟修正、shell injection 安全修復,以及增量更新保留跨檔邊。

為什麼這四個 patch 值得學

v0.9.66~v0.9.69(2026-09-22 至 2026-09-26)四天內連續發布,主題可以分成三條線:

  1. 廣度:一次補進五個語言 extractor(擷取器),並加深 OCaml、Elixir、Fortran、Julia、Kotlin 的結構擷取。
  2. 可靠性:graph.json 的逐次一致性(determinism,決定性)、Windows 上的 re-exec 修正,以及增量更新不再默默丟掉跨檔邊。
  3. 安全:修掉 /graphify add … --watch 流程中的 shell injection(命令注入)。

對團隊的實務意義:知識圖譜工具的可信度來自「每次跑出來都一樣、且沒有靜默遺漏」;這批 patch 兩者都在補。

新增五個語言 Extractor(v0.9.66)

語言 副檔名 擷取重點 安裝
COBOL .cbl / .cob / .cobol / .cpy program、paragraph、PERFORM / CALL / COPY;純 regex 實作,不新增相依 內建
VB.NET .vb 大小寫不敏感的型別 / 方法、Inherits / Implements / Handles 對應 extra
R .r / .R assignment-form 函式定義、library / source、S4 / R6 class r extra(無獨立 PyPI wheel)
Solidity .sol contract / interface / library、is 繼承、import、modifier 對應 extra
Erlang .erl / .hrl / .escript module、以 arity(參數數量)區分的 function、behaviour、本地與遠端 foo:bar() 呼叫 erlang extra(無獨立 PyPI wheel)

R 與 Erlang 的 grammar 沒有獨立 PyPI wheel,因此走 r / erlang extras;Solidity 與 VB.NET 也有各自的 extra。

語言總數變化:v0.9.66 在既有 36+ 種語言的基礎上新增五個 extractor。release notes 未公布精確總數;上游 README 在 v0.9.65 與 v0.9.69 都維持「約 40 種語言、37 個 tree-sitter grammar」,並未隨這次新增更新數字,因此本頁以新增清單為準,不主張新的總數。

既有語言的結構深度(v0.9.69)

v0.9.69 把五個語言的擷取從「有節點」推進到「有正確的關係」:

  • OCaml:class 的方法以 method 關係呈現,instance variable(實例變數)一併擷取
  • Elixir:defprotocol / defimpl 抽成容器(container)節點,函式掛在容器下,並帶同檔 implements 邊
  • Fortran:derived-type 的 contains block 把 type-bound procedure 連到型別,並解析 => impl 目標
  • Julia:macro 定義與 @enum 型別(含 red = 1 的有值形式與 Color::UInt8 的有型別形式),成員使用 case_of 關係
  • Kotlin:annotation(class / function / property、use-site target)與 primary constructor 的 val / var property 開始產生邊

跨檔 Resolution(v0.9.66、v0.9.69)

  • Go:interface 的 method requirement(type Foo interface { Bar() })解析到 interface 本身,且其參數 / 回傳型別發出 references 邊(#3672、#3737)
  • Rust:簡單 generic impl(impl<T> Foo<T>)的 self.method() 跨檔解析持續(#3653)
  • TypeScript:solution-style(方案式)tsconfig.json 本身只有 references、沒有 paths 時,改為解析被引用專案設定裡的 path alias;tsc -b 的專案佈局中,alias import 不再懸空(#3753、#3745)

決定性與 Windows 修正(v0.9.66 → v0.9.68)

這段是三個版本接力修同一件事,很值得當教材看:

版本 內容
v0.9.66(#3743) update / extract / cluster-only / label 以一次性 re-exec pin PYTHONHASHSEED,讓對 hash seed 敏感的 Leiden / Louvain 社群偵測輸出逐次一致,也與 hook 觸發的 rebuild 相符
v0.9.67(#3780) 改以 python -m graphify 重啟,而不是重播 argv[0];修好 Windows 上透過 console-script .exe launcher 無法重啟的回歸
v0.9.68(#3816、#3799) os.execvpe 只在 POSIX 是真正的行程替換;Windows 上它 spawn 新行程後父行程繼續前進、未被 pin,導致 update / extract / cluster-only / label 崩潰。Windows 路徑改走 subprocess.run 並以子行程 exit code 結束,POSIX 不變

教訓:跨平台的「重新啟動自己」沒有可攜寫法。exec* 的語意差異(行程替換 vs. 生成子行程)是典型的 silent portability trap(可攜性陷阱)。

安全:Shell Injection 修復(v0.9.68,#3742、#3642)

/graphify add … --watch 的參考實作會把 agent 代入的 INPUT_PATH 佔位符未加引號地寫進 shell 指令(… -m graphify.watch INPUT_PATH)。若 scan root 含有 $(…)、backtick 或 ;,就會被 shell 當成指令執行——這是同一個 skill 流程中 Step 1 修復的延伸(follow-on)。

修法:watcher 不再接受可替換的路徑,改讀 Step 1 已解析、受信任的 graphify-out/.graphify_root。

注意:Aider / Devin 的 monolith --watch 片段仍有同一佔位符,上游以另案追蹤。

增量更新與圖譜正確性(v0.9.68)

  • 保留跨檔邊(#3812、#3776):增量更新(update / extract --code-only / watch)保留目標符號位於未變檔案的跨檔 imports / calls / uses 邊——symbol-resolution facts 的 target index 加入唯讀的 resolution context,重萃取單一檔案不會再默默丟掉它連向圖譜其餘部分的邊;真正被移除的邊仍會 prune
  • C# 型別解析(#3815、#3795):inherits / implements / 參數 / 回傳 / base type 不再解析到同名的非型別節點(同名 enum member、property、field、method 被排除出 type-definition index);沒有 contains 邊的 partial class 解析也恢復
  • Dedup(#3786、#3775):合併重複節點時,保留有真實 source location 的節點,而不是較豐富但無來源的推論 / 外部 stub;loser 的屬性仍會折到 survivor

其他可靠性修正(節錄)

  • 建置系統:Maven pom.xml 的依賴可從本地 <parent> 繼承 groupId / version,並展開 ${property} / ${project.*}(離線、一層,v0.9.68/#3823)
  • Secret redaction:Terraform 的 secret 命名 variable default 與 output value 也會 redact(v0.9.68/#3817)
  • COBOL:固定格式(fixed-format)帶序號欄位時正確辨識(v0.9.68/#3813);PERFORM A THRU/THROUGH Z 兩端點都連 calls 邊(v0.9.68/#3814)
  • PHP:closure(匿名 function(){…}、arrow fn()=>…、作為引數傳入)成為節點並擷取內部呼叫;route closure 取得 VERB /path 語意名(v0.9.67/#3461)
  • Python:絕對 import(import pkg.sub、from pkg.sub import x)解析到 scan root 內的本地 package / module(v0.9.67/#3729)
  • Process pool:spawn 無法 re-import __main__(stdin、python -c、REPL、embedded 呼叫端)時先跳過,改走正確的 sequential run,而不是一堆 BrokenProcessPool(v0.9.69/#3754)
  • Dedup self-loop:保留既有的 self-loop(遞迴呼叫、self-referential FK),只丟棄 merge 新產生的(v0.9.69/#3825)
  • 匯出:export 不再每次重寫內容未變的 wiki / Obsidian 頁面,mtime 穩定、git / Obsidian 同步乾淨(v0.9.67/#3760)

升級建議

情境 建議
Windows 使用者 務必升到 v0.9.68 以上;v0.9.66 / v0.9.67 的 hash-seed re-exec 在 Windows 上無效或競速崩潰
用到本次新增語言(COBOL / VB.NET / R / Solidity / Erlang) 升級後重新萃取才會出現新節點
以 /graphify add … --watch 建圖 升級取得注入修復;確認流程不使用未引號的 INPUT_PATH 片段
長期以 watch / hook 維護 graph 建議做一次完整 graphify update,讓跨檔邊與 manifest 由新版接手
需要逐次可重現的 graph.json 升到 v0.9.68 以上,Leiden / Louvain 分群輸出才會穩定

來源:v0.9.66、v0.9.67、v0.9.68、v0.9.69