d5a806a5c3
Adds idx/fts/<token>/<ts>-<id> hardlinks and an FTS-driven query path. - FsSearchTokenizer: lowercase + Unicode-aware split on non letter-or- digit, matching SQLite FTS5's unicode61 default closely enough that the same call indexes content and parses queries (any drift cancels). Tokens capped at 100 chars to keep filenames under FS limits. - FsLayout: idxFts + ftsEntry / ftsTokenDir helpers; skeleton dir. - FsIndexer.pathsFor: when event implements SearchableEvent, emits one hardlink per unique tokenised word — so insert/delete maintenance rides the existing link/unlink path. Eviction (replaceable swap), NIP-09 cascade and NIP-62 vanish all clean up FTS for free. - FsQueryPlanner: when filter.search is non-blank, drives by FTS. Tokenises the query, walks each idx/fts/<token>/ listing into a HashMap<id, ts>, and intersects smallest-first (AND across tokens — matching SQLite FTS5 default MATCH semantics). Output sorted by createdAt DESC. Other Filter fields (kinds, authors, tags, since / until) still apply via Filter.match post-filter. Tests: 16 new in FsSearchTest covering tokenizer (whitespace, case, unicode, punctuation, empty), index maintenance (entries created, non-searchable kinds skipped, delete unlinks), and query semantics (single token, AND of tokens, ordering, limit, kind/author compose, no-match, blank string ignored, reopen). 86 fs tests green.