internal/index/sqlite.go
@@ -93,7 +93,7 @@
// ClearData 清空数据(重建前调用)
func (s *Store) ClearData() error {
   _, err := s.db.Exec("DELETE FROM edges; DELETE FROM nodes;")
   _, err := s.db.Exec("DELETE FROM edges; DELETE FROM nodes; DELETE FROM unresolved_links;")
   return err
}
@@ -126,6 +126,17 @@
   return err
}
// InsertUnresolved 悬空链接入表(幂等:同 from_node+link_text 不重复插)
func (s *Store) InsertUnresolved(fromNode int64, linkText, nameTail string) error {
   _, err := s.db.Exec(`
      INSERT INTO unresolved_links (from_node, link_text, name_tail, status)
      SELECT ?, ?, ?, 'pending'
      WHERE NOT EXISTS (
         SELECT 1 FROM unresolved_links WHERE from_node = ? AND link_text = ?)`,
      fromNode, linkText, nameTail, fromNode, linkText)
   return err
}
// FileStat 索引中的文件指纹
type FileStat struct {
   Path        string
@@ -276,6 +287,24 @@
   return links, nil
}
// GetUnresolvedLinks 某文档的悬空链接文本列表
func (s *Store) GetUnresolvedLinks(path string) ([]string, error) {
   rows, err := s.db.Query(`
      SELECT u.link_text FROM unresolved_links u
      JOIN nodes n ON n.id = u.from_node WHERE n.path = ?`, path)
   if err != nil {
      return nil, err
   }
   defer rows.Close()
   var links []string
   for rows.Next() {
      var l string
      rows.Scan(&l)
      links = append(links, l)
   }
   return links, rows.Err()
}
// NodeInfo 节点基本信息(用于 GC)
type NodeInfo struct {
   ID   int64
@@ -453,7 +482,7 @@
         visited[id] = true
         query := `
            SELECT id, from_node, to_node, relation, label
            SELECT id, from_node, to_node, relation, label, provenance
            FROM edges
            WHERE from_node = ?
         `
@@ -472,7 +501,7 @@
         for rows.Next() {
            var e graph.Edge
            var edgeID int64
            if err := rows.Scan(&edgeID, &e.FromNode, &e.ToNode, &e.Relation, &e.Label); err != nil {
            if err := rows.Scan(&edgeID, &e.FromNode, &e.ToNode, &e.Relation, &e.Label, &e.Provenance); err != nil {
               rows.Close()
               return nil, fmt.Errorf("扫描边失败: %w", err)
            }