search

package
v0.34.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package search orchestrates the FTS5-backed spec search index and exposes a single Search entry point shared by the TUI overlay and the CLI.

The package never opens the database itself: all SQL goes through internal/store accessors (AGENTS.md: only internal/store touches SQLite). It does parse markdown via internal/markdown, so the dependency arrow is store ← search → markdown, with store and markdown independent of each other.

Index

Constants

View Source
const (
	ScopeAll      = store.ScopeAll
	ScopeActive   = store.ScopeActive
	ScopeArchived = store.ScopeArchived
)
View Source
const DefaultLimit = 50

DefaultLimit caps the number of hits returned by Search when the caller does not specify one. The TUI overlay and CLI both leave it at this.

Variables

This section is empty.

Functions

This section is empty.

Types

type Hit

type Hit struct {
	SpecID         string  `json:"spec_id"`
	Title          string  `json:"title"`
	Status         string  `json:"status"`
	Author         string  `json:"author,omitempty"`
	Archived       bool    `json:"archived"`
	SectionSlug    string  `json:"section_slug"`
	SectionHeading string  `json:"section_heading"`
	Snippet        string  `json:"snippet"`
	Score          float64 `json:"score"`
}

Hit is one ranked, section-anchored search result. Both the TUI overlay and `spec search --json` consume this shape.

func KeywordScan

func KeywordScan(rc *config.ResolvedConfig, keyword string) []Hit

KeywordScan performs a literal keyword substring scan (the relocated cmd/search.go logic) and returns unranked hits. `spec context` uses this so its keyword-search behaviour is unchanged after the searchDir helper moved out of cmd/.

type Indexer

type Indexer struct {
	// contains filtered or unexported fields
}

Indexer scans the specs repo (active + archive) and keeps the FTS5 index in sync, then answers ranked queries. One instance per process; the TUI keeps it for the lifetime of the App.

func NewIndexer

func NewIndexer(rc *config.ResolvedConfig, db *store.DB) *Indexer

NewIndexer builds an Indexer over the resolved config and shared store. A nil db is tolerated: Search degrades to the live fallback scan and Reconcile is a no-op. This keeps the TUI working when store.Open failed.

func (*Indexer) IndexEmpty

func (ix *Indexer) IndexEmpty() (bool, error)

IndexEmpty reports whether the FTS index has never been populated, so the overlay can show its `indexing…` chip on a cold open. Nil-safe.

func (*Indexer) Reconcile

func (ix *Indexer) Reconcile(ctx context.Context) (Stats, error)

Reconcile scans the specs repo (active + archive) and re-indexes only the files whose mtime changed since the last index (a hash check then skips mtime-only touches), removes index rows for files gone from disk, and returns aggregate stats. It is safe to call repeatedly — on an unchanged repo it does only the directory scans plus a diff and returns near-zero work. A single unparseable spec is counted in Stats.Failed and skipped; it never aborts the pass.

func (*Indexer) Search

func (ix *Indexer) Search(ctx context.Context, query string, opts Options) ([]Hit, error)

Search answers a ranked, section-anchored query. When the index has never been populated (cold start) it transparently falls back to a live substring scan over the same scope, so search is never broken while the background reconcile catches up. A nil db always uses the fallback.

type Options

type Options struct {
	Scope SearchScope
	Limit int // 0 → DefaultLimit
}

Options tunes a Search call.

type SearchScope

type SearchScope = store.SearchScope

SearchScope is re-exported from store so callers depend on search, not store, for the public surface.

type Stats

type Stats struct {
	Scanned   int           `json:"scanned"`
	Reindexed int           `json:"reindexed"`
	Deleted   int           `json:"deleted"`
	Skipped   int           `json:"skipped"` // unchanged (mtime+hash match)
	Failed    int           `json:"failed"`  // parse failures skipped, not fatal
	Elapsed   time.Duration `json:"elapsed"`
}

Stats summarises one Reconcile pass. The overlay shows `indexing…` while in flight and the CLI prints the final numbers for `--reindex`.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL