diff --git a/cmd/leyline.go b/cmd/leyline.go index 2aa3fd7..0227e6e 100644 --- a/cmd/leyline.go +++ b/cmd/leyline.go @@ -122,7 +122,7 @@ func materializeCallers(tx *sql.Tx, now int64) error { for token, callerNodeIDs := range callerMap { // Look up the directory that defines this token var dirID string - err := tx.QueryRow(`SELECT dir_id FROM node_defs WHERE token = ?`, token).Scan(&dirID) + err := tx.QueryRow(`SELECT node_id FROM node_defs WHERE token = ?`, token).Scan(&dirID) if err != nil { continue // no definition found, skip } @@ -197,7 +197,7 @@ func materializeCallees(tx *sql.Tx, now int64) error { // Pre-load all defs: token → []dir_id (multiple constructs may define // the same token, e.g. Init in different packages). defsMap := make(map[string][]string) - defRows, err := tx.Query(`SELECT token, dir_id FROM node_defs`) + defRows, err := tx.Query(`SELECT token, node_id FROM node_defs`) if err != nil { return fmt.Errorf("query node_defs: %w", err) } diff --git a/cmd/leyline_callees_test.go b/cmd/leyline_callees_test.go index 06d0f30..4e7f43c 100644 --- a/cmd/leyline_callees_test.go +++ b/cmd/leyline_callees_test.go @@ -41,8 +41,8 @@ func TestMaterializeCallees(t *testing.T) { ); CREATE TABLE node_defs ( token TEXT, - dir_id TEXT, - PRIMARY KEY (token, dir_id) + node_id TEXT, + PRIMARY KEY (token, node_id) ); `) require.NoError(t, err) @@ -76,9 +76,9 @@ func TestMaterializeCallees(t *testing.T) { require.NoError(t, err) // Insert defs: FuncA and FuncB are defined - _, err = db.Exec("INSERT INTO node_defs (token, dir_id) VALUES (?, ?)", "FuncA", "pkg/functions/FuncA") + _, err = db.Exec("INSERT INTO node_defs (token, node_id) VALUES (?, ?)", "FuncA", "pkg/functions/FuncA") require.NoError(t, err) - _, err = db.Exec("INSERT INTO node_defs (token, dir_id) VALUES (?, ?)", "FuncB", "pkg/functions/FuncB") + _, err = db.Exec("INSERT INTO node_defs (token, node_id) VALUES (?, ?)", "FuncB", "pkg/functions/FuncB") require.NoError(t, err) // Materialize callers (existing) diff --git a/cmd/leyline_test.go b/cmd/leyline_test.go index 140440c..894c118 100644 --- a/cmd/leyline_test.go +++ b/cmd/leyline_test.go @@ -38,8 +38,8 @@ func setupTestDB(t *testing.T) *sql.DB { CREATE TABLE node_defs ( token TEXT, - dir_id TEXT, - PRIMARY KEY (token, dir_id) + node_id TEXT, + PRIMARY KEY (token, node_id) ) WITHOUT ROWID; -- Function directories diff --git a/internal/graph/sqlite_graph.go b/internal/graph/sqlite_graph.go index b3b81a6..677658f 100644 --- a/internal/graph/sqlite_graph.go +++ b/internal/graph/sqlite_graph.go @@ -688,7 +688,7 @@ func (g *SQLiteGraph) GetCallees(id string) ([]*Node, error) { } // SQL fallback: node_defs table (pre-built DBs) if !resolved && g.useNodesTable { - rows, qErr := g.db.Query("SELECT dir_id FROM node_defs WHERE token = ?", qualKey) + rows, qErr := g.db.Query("SELECT node_id FROM node_defs WHERE token = ?", qualKey) if qErr == nil { for rows.Next() { var defID string @@ -726,7 +726,7 @@ func (g *SQLiteGraph) GetCallees(id string) ([]*Node, error) { // SQL fallback: node_defs then nodes table if g.useNodesTable { var defID string - err := g.db.QueryRow("SELECT dir_id FROM node_defs WHERE token = ? LIMIT 1", qc.Token).Scan(&defID) + err := g.db.QueryRow("SELECT node_id FROM node_defs WHERE token = ? LIMIT 1", qc.Token).Scan(&defID) if err == nil && defID != id && !seen[defID] { seen[defID] = true nodes = append(nodes, &Node{ID: defID, Mode: os.ModeDir | 0o555}) diff --git a/internal/ingest/ast_walker.go b/internal/ingest/ast_walker.go index e78514d..956d804 100644 --- a/internal/ingest/ast_walker.go +++ b/internal/ingest/ast_walker.go @@ -178,6 +178,38 @@ func (w *ASTWalker) ExtractAddressRefs(sourcePath, langName string) ([]string, e return tokens, nil } +// ExtractGoImports reads Go import aliases from the _imports table +// (produced by ley-line-open's `leyline parse`). Returns alias → path map +// for qualified call resolution (e.g., auth.Validate → github.com/foo/auth). +// Mirrors SitterWalker.ExtractGoImports but uses SQL instead of CGO tree-sitter. +func (w *ASTWalker) ExtractGoImports(sourceID string) (map[string]string, error) { + // Check if _imports table exists (older .dbs produced before LLO didn't have it) + var count int + if err := w.db.QueryRow( + "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='_imports'", + ).Scan(&count); err != nil || count == 0 { + return nil, nil + } + + rows, err := w.db.Query( + "SELECT alias, path FROM _imports WHERE source_id = ?", sourceID, + ) + if err != nil { + return nil, fmt.Errorf("query _imports: %w", err) + } + defer func() { _ = rows.Close() }() + + imports := make(map[string]string) + for rows.Next() { + var alias, path string + if err := rows.Scan(&alias, &path); err != nil { + continue + } + imports[alias] = path + } + return imports, rows.Err() +} + // SelectWalker inspects a SQLite database and returns the best Walker. // If the database has an _ast table (produced by ley-line's ll-open/ts), // returns an ASTWalker (pure Go, no CGO). Otherwise returns a SitterWalker diff --git a/internal/ingest/sqlite_writer.go b/internal/ingest/sqlite_writer.go index 2cd68ac..e74bb5a 100644 --- a/internal/ingest/sqlite_writer.go +++ b/internal/ingest/sqlite_writer.go @@ -73,8 +73,8 @@ func NewSQLiteWriter(dbPath string) (*SQLiteWriter, error) { CREATE TABLE IF NOT EXISTS node_defs ( token TEXT, - dir_id TEXT, - PRIMARY KEY (token, dir_id) + node_id TEXT, + PRIMARY KEY (token, node_id) ) WITHOUT ROWID; CREATE TABLE IF NOT EXISTS file_index ( @@ -121,7 +121,7 @@ func (w *SQLiteWriter) beginTx() error { return err } - w.stmtDef, err = w.tx.Prepare(`INSERT OR IGNORE INTO node_defs (token, dir_id) VALUES (?, ?)`) + w.stmtDef, err = w.tx.Prepare(`INSERT OR IGNORE INTO node_defs (token, node_id) VALUES (?, ?)`) if err != nil { return err } @@ -344,7 +344,7 @@ func (w *SQLiteWriter) DeleteFileNodes(filePath string) { _, _ = w.tx.Exec(`DELETE FROM node_refs WHERE node_id IN ( SELECT id FROM nodes WHERE source_file = ? )`, filePath) - _, _ = w.tx.Exec(`DELETE FROM node_defs WHERE dir_id IN ( + _, _ = w.tx.Exec(`DELETE FROM node_defs WHERE node_id IN ( SELECT id FROM nodes WHERE source_file = ? )`, filePath) _, _ = w.tx.Exec(`DELETE FROM nodes WHERE source_file = ?`, filePath) diff --git a/internal/leyline/socket.go b/internal/leyline/socket.go index 80bddb8..7943c9a 100644 --- a/internal/leyline/socket.go +++ b/internal/leyline/socket.go @@ -133,8 +133,10 @@ func DiscoverOrStart() (string, error) { ctrlPath := filepath.Join(dataDir, "default.ctrl") sockPath := filepath.Join(dataDir, "default.sock") - // Start leyline serve as a background subprocess - cmd := exec.Command(leylineBin, "serve", + // Start leyline daemon as a background subprocess. + // `daemon` creates the UDS socket at .sock that mache connects to. + // `serve` mounts only (no socket) — wrong for our use case. + cmd := exec.Command(leylineBin, "daemon", "--arena", arenaPath, "--arena-size-mib", "64", "--control", ctrlPath,