init commit

This commit is contained in:
ysandler
2026-01-22 23:03:49 -06:00
commit 1eae04fc60
21 changed files with 1688 additions and 0 deletions

144
internal/config/config.go Normal file
View File

@@ -0,0 +1,144 @@
package config
import (
"os"
"path/filepath"
"github.com/spf13/viper"
)
type Config struct {
DoksStorageDir string `json:"doksStorageDir" mapstructure:"doksStorageDir"`
DefaultEditor string `json:"defaultEditor" mapstructure:"defaultEditor"`
Search SearchConfig `json:"search" mapstructure:"search"`
Embeddings EmbedConfig `json:"embeddings" mapstructure:"embeddings"`
Display DisplayConfig `json:"display" mapstructure:"display"`
}
type SearchConfig struct {
Engine string `json:"engine" mapstructure:"engine"`
VectorEnabled bool `json:"vectorEnabled" mapstructure:"vectorEnabled"`
}
type EmbedConfig struct {
Provider string `json:"provider" mapstructure:"provider"`
BaseURL string `json:"baseUrl" mapstructure:"baseUrl"`
APIKey string `json:"apiKey" mapstructure:"apiKey"`
Model string `json:"model" mapstructure:"model"`
}
type DisplayConfig struct {
ContextLines int `json:"contextLines" mapstructure:"contextLines"`
MaxResults int `json:"maxResults" mapstructure:"maxResults"`
}
func DefaultConfig() *Config {
homeDir, _ := os.UserHomeDir()
return &Config{
DoksStorageDir: filepath.Join(homeDir, "doks"),
DefaultEditor: "vim",
Search: SearchConfig{
Engine: "text",
VectorEnabled: false,
},
Embeddings: EmbedConfig{
Provider: "openai",
BaseURL: "https://api.openai.com/v1",
APIKey: "",
Model: "text-embedding-3-small",
},
Display: DisplayConfig{
ContextLines: 3,
MaxResults: 20,
},
}
}
func Load() (*Config, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return nil, err
}
configDir := filepath.Join(homeDir, ".config", "doks")
if err := os.MkdirAll(configDir, 0755); err != nil {
return nil, err
}
viper.SetConfigName("config")
viper.SetConfigType("json")
viper.AddConfigPath(configDir)
// Set defaults
defaults := DefaultConfig()
viper.SetDefault("doksStorageDir", defaults.DoksStorageDir)
viper.SetDefault("defaultEditor", defaults.DefaultEditor)
viper.SetDefault("search.engine", defaults.Search.Engine)
viper.SetDefault("search.vectorEnabled", defaults.Search.VectorEnabled)
viper.SetDefault("embeddings.provider", defaults.Embeddings.Provider)
viper.SetDefault("embeddings.baseUrl", defaults.Embeddings.BaseURL)
viper.SetDefault("embeddings.apiKey", defaults.Embeddings.APIKey)
viper.SetDefault("embeddings.model", defaults.Embeddings.Model)
viper.SetDefault("display.contextLines", defaults.Display.ContextLines)
viper.SetDefault("display.maxResults", defaults.Display.MaxResults)
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found, create with defaults
configPath := filepath.Join(configDir, "config.json")
if err := viper.SafeWriteConfigAs(configPath); err != nil {
return nil, err
}
} else {
return nil, err
}
}
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return nil, err
}
// Expand ~ in storage dir
cfg.DoksStorageDir = expandPath(cfg.DoksStorageDir)
// Ensure storage directory exists
if err := os.MkdirAll(cfg.DoksStorageDir, 0755); err != nil {
return nil, err
}
// Ensure doksFiles subdirectory exists
filesDir := filepath.Join(cfg.DoksStorageDir, "doksFiles")
if err := os.MkdirAll(filesDir, 0755); err != nil {
return nil, err
}
return &cfg, nil
}
func (c *Config) RegistryPath() string {
return filepath.Join(c.DoksStorageDir, "doksRegistry.db")
}
func (c *Config) FilesDir() string {
return filepath.Join(c.DoksStorageDir, "doksFiles")
}
func (c *Config) FilePath(filename string) string {
return filepath.Join(c.FilesDir(), filename)
}
func (c *Config) VectorsDir() string {
return filepath.Join(c.DoksStorageDir, "vectors")
}
func expandPath(path string) string {
if len(path) > 0 && path[0] == '~' {
homeDir, err := os.UserHomeDir()
if err != nil {
return path
}
return filepath.Join(homeDir, path[1:])
}
return path
}