package ingest import ( "os" "path/filepath" "strings" "time" ) var _ Ingester = (*ObsidianFileIngester)(nil) type ObsidianFileIngester struct { Version string Vault string } func NewObsidianFileIngester(vault string) *ObsidianFileIngester { return &ObsidianFileIngester{Version: "obsidian-file/v1", Vault: vault} } func (o *ObsidianFileIngester) SourceID() string { return "obsidian" } func (o *ObsidianFileIngester) Ingest(path string) (*IngestResult, error) { if !strings.HasSuffix(path, ".md") { return nil, nil } data, err := os.ReadFile(path) if err != nil || len(data) < 10 { return nil, nil } content := string(data) title := extractObsidianTitle(content, path, o.Vault) tags := extractObsidianTags(content) created, _ := extractObsidianTimestamps(content, path) if created == "" { if fi, err := os.Stat(path); err == nil { created = fi.ModTime().UTC().Format(time.RFC3339) } } fp := FingerprintWithMeta(data, map[string]string{ "source": "obsidian", "path": path, }) relPath, _ := filepath.Rel(o.Vault, path) summary := extractBodyPreview(content, 200) return &IngestResult{ Fingerprint: fp, SourceID: o.SourceID(), SourcePath: relPath, Project: filepath.Base(o.Vault), ContentType: ".md", Title: title, Summary: summary, CreatedAt: created, LineEnd: len(strings.Split(content, "\n")), Confidence: 0.85, IngesterVersion: o.Version, Provenance: map[string]any{ "path": relPath, "tags": tags, "note_title": title, }, }, nil }