feat: add nixpkgs-search binary with package search support

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>
This commit is contained in:
2026-02-04 17:12:41 +01:00
parent 9efcca217c
commit ea4c69bc23
17 changed files with 2559 additions and 63 deletions

View File

@@ -2,7 +2,7 @@ package database
// SchemaVersion is the current database schema version.
// When this changes, the database will be dropped and recreated.
const SchemaVersion = 2
const SchemaVersion = 3
// Common SQL statements shared between implementations.
const (
@@ -20,7 +20,8 @@ const (
channel_name TEXT,
commit_date TIMESTAMP,
indexed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
option_count INTEGER NOT NULL DEFAULT 0
option_count INTEGER NOT NULL DEFAULT 0,
package_count INTEGER NOT NULL DEFAULT 0
)`
// OptionsTable creates the options table.
@@ -57,6 +58,25 @@ const (
byte_size INTEGER NOT NULL DEFAULT 0,
line_count INTEGER NOT NULL DEFAULT 0
)`
// PackagesTable creates the packages table.
PackagesTable = `
CREATE TABLE IF NOT EXISTS packages (
id INTEGER PRIMARY KEY,
revision_id INTEGER NOT NULL REFERENCES revisions(id) ON DELETE CASCADE,
attr_path TEXT NOT NULL,
pname TEXT NOT NULL,
version TEXT,
description TEXT,
long_description TEXT,
homepage TEXT,
license TEXT,
platforms TEXT,
maintainers TEXT,
broken BOOLEAN NOT NULL DEFAULT FALSE,
unfree BOOLEAN NOT NULL DEFAULT FALSE,
insecure BOOLEAN NOT NULL DEFAULT FALSE
)`
)
// Index creation statements.
@@ -80,6 +100,16 @@ const (
IndexDeclarationsOption = `
CREATE INDEX IF NOT EXISTS idx_declarations_option
ON declarations(option_id)`
// IndexPackagesRevisionAttr creates an index on packages(revision_id, attr_path).
IndexPackagesRevisionAttr = `
CREATE UNIQUE INDEX IF NOT EXISTS idx_packages_revision_attr
ON packages(revision_id, attr_path)`
// IndexPackagesRevisionPname creates an index on packages(revision_id, pname).
IndexPackagesRevisionPname = `
CREATE INDEX IF NOT EXISTS idx_packages_revision_pname
ON packages(revision_id, pname)`
)
// Drop statements for schema recreation.
@@ -87,6 +117,7 @@ const (
DropSchemaInfo = `DROP TABLE IF EXISTS schema_info`
DropDeclarations = `DROP TABLE IF EXISTS declarations`
DropOptions = `DROP TABLE IF EXISTS options`
DropPackages = `DROP TABLE IF EXISTS packages`
DropFiles = `DROP TABLE IF EXISTS files`
DropRevisions = `DROP TABLE IF EXISTS revisions`
)