Add a new nixpkgs-search CLI that combines NixOS options search with Nix package search functionality. This provides two MCP servers from a single binary: - `nixpkgs-search options serve` for NixOS options - `nixpkgs-search packages serve` for Nix packages Key changes: - Add packages table to database schema (version 3) - Add Package type and search methods to database layer - Create internal/packages/ with indexer and parser for nix-env JSON - Add MCP server mode (options/packages) with separate tool sets - Add package handlers: search_packages, get_package - Create cmd/nixpkgs-search with combined indexing support - Update flake.nix with nixpkgs-search package (now default) - Bump version to 0.2.0 The index command can index both options and packages together, or use --no-packages/--no-options flags for partial indexing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
150 lines
4.5 KiB
Go
150 lines
4.5 KiB
Go
// Package database provides database abstraction for storing NixOS options.
|
|
package database
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
)
|
|
|
|
// Revision represents an indexed nixpkgs revision.
|
|
type Revision struct {
|
|
ID int64
|
|
GitHash string
|
|
ChannelName string
|
|
CommitDate time.Time
|
|
IndexedAt time.Time
|
|
OptionCount int
|
|
PackageCount int
|
|
}
|
|
|
|
// Option represents a NixOS configuration option.
|
|
type Option struct {
|
|
ID int64
|
|
RevisionID int64
|
|
Name string
|
|
ParentPath string
|
|
Type string
|
|
DefaultValue string // JSON text
|
|
Example string // JSON text
|
|
Description string
|
|
ReadOnly bool
|
|
}
|
|
|
|
// Declaration represents a file where an option is declared.
|
|
type Declaration struct {
|
|
ID int64
|
|
OptionID int64
|
|
FilePath string
|
|
Line int
|
|
}
|
|
|
|
// File represents a cached file from nixpkgs.
|
|
type File struct {
|
|
ID int64
|
|
RevisionID int64
|
|
FilePath string
|
|
Extension string
|
|
Content string
|
|
ByteSize int
|
|
LineCount int
|
|
}
|
|
|
|
// Package represents a Nix package from nixpkgs.
|
|
type Package struct {
|
|
ID int64
|
|
RevisionID int64
|
|
AttrPath string // e.g., "python312Packages.requests"
|
|
Pname string // Package name
|
|
Version string
|
|
Description string
|
|
LongDescription string
|
|
Homepage string
|
|
License string // JSON array
|
|
Platforms string // JSON array
|
|
Maintainers string // JSON array
|
|
Broken bool
|
|
Unfree bool
|
|
Insecure bool
|
|
}
|
|
|
|
// DeclarationWithMetadata includes declaration info plus file metadata.
|
|
type DeclarationWithMetadata struct {
|
|
Declaration
|
|
ByteSize int // File size in bytes, 0 if file not indexed
|
|
LineCount int // Number of lines, 0 if file not indexed
|
|
HasFile bool // True if file is indexed
|
|
}
|
|
|
|
// FileRange specifies a range of lines to return from a file.
|
|
type FileRange struct {
|
|
Offset int // Line offset (0-based)
|
|
Limit int // Maximum lines to return (0 = default 250)
|
|
}
|
|
|
|
// FileResult contains a file with range metadata.
|
|
type FileResult struct {
|
|
*File
|
|
TotalLines int // Total lines in the file
|
|
StartLine int // First line returned (1-based)
|
|
EndLine int // Last line returned (1-based)
|
|
}
|
|
|
|
// SearchFilters contains optional filters for option search.
|
|
type SearchFilters struct {
|
|
Type string
|
|
Namespace string
|
|
HasDefault *bool
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// PackageSearchFilters contains optional filters for package search.
|
|
type PackageSearchFilters struct {
|
|
Broken *bool
|
|
Unfree *bool
|
|
Insecure *bool
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// Store defines the interface for database operations.
|
|
type Store interface {
|
|
// Schema operations
|
|
Initialize(ctx context.Context) error
|
|
Close() error
|
|
|
|
// Revision operations
|
|
CreateRevision(ctx context.Context, rev *Revision) error
|
|
GetRevision(ctx context.Context, gitHash string) (*Revision, error)
|
|
GetRevisionByChannel(ctx context.Context, channel string) (*Revision, error)
|
|
ListRevisions(ctx context.Context) ([]*Revision, error)
|
|
DeleteRevision(ctx context.Context, id int64) error
|
|
UpdateRevisionOptionCount(ctx context.Context, id int64, count int) error
|
|
|
|
// Option operations
|
|
CreateOption(ctx context.Context, opt *Option) error
|
|
CreateOptionsBatch(ctx context.Context, opts []*Option) error
|
|
GetOption(ctx context.Context, revisionID int64, name string) (*Option, error)
|
|
GetChildren(ctx context.Context, revisionID int64, parentPath string) ([]*Option, error)
|
|
SearchOptions(ctx context.Context, revisionID int64, query string, filters SearchFilters) ([]*Option, error)
|
|
|
|
// Declaration operations
|
|
CreateDeclaration(ctx context.Context, decl *Declaration) error
|
|
CreateDeclarationsBatch(ctx context.Context, decls []*Declaration) error
|
|
GetDeclarations(ctx context.Context, optionID int64) ([]*Declaration, error)
|
|
GetDeclarationsWithMetadata(ctx context.Context, revisionID, optionID int64) ([]*DeclarationWithMetadata, error)
|
|
|
|
// File operations
|
|
CreateFile(ctx context.Context, file *File) error
|
|
CreateFilesBatch(ctx context.Context, files []*File) error
|
|
GetFile(ctx context.Context, revisionID int64, path string) (*File, error)
|
|
GetFileWithRange(ctx context.Context, revisionID int64, path string, r FileRange) (*FileResult, error)
|
|
|
|
// Package operations
|
|
CreatePackage(ctx context.Context, pkg *Package) error
|
|
CreatePackagesBatch(ctx context.Context, pkgs []*Package) error
|
|
GetPackage(ctx context.Context, revisionID int64, attrPath string) (*Package, error)
|
|
SearchPackages(ctx context.Context, revisionID int64, query string, filters PackageSearchFilters) ([]*Package, error)
|
|
UpdateRevisionPackageCount(ctx context.Context, id int64, count int) error
|
|
}
|