summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-11 20:48:01 +0200
committerPaul Buetow <paul@buetow.org>2026-02-11 20:48:01 +0200
commit8312a19b4e1f9849aae9912433824b19e03a8daf (patch)
tree8ca381d8a6549e94b15a5c65f688a353f0da98ca
parent97b8887fb3448fd08524111d98425859bec8789f (diff)
refactor: consolidate cache and state into .local/hexai directory
Move all cache and state files under ~/.local/hexai/ with subdirectories: - ~/.local/hexai/cache/ (was ~/.cache/hexai/) - ~/.local/hexai/state/ (was ~/.local/state/hexai/) - ~/.local/hexai/data/ (was ~/.local/share/hexai/) This centralizes all non-config hexai files under a single .local/hexai directory, making it easier to manage and back up user data. Amp-Thread-ID: https://ampcode.com/threads/T-019c4e03-73db-70a2-ae27-3e1cc31d59c3 Co-authored-by: Amp <amp@ampcode.com>
-rw-r--r--.gitignore3
-rw-r--r--README.md6
-rw-r--r--internal/appconfig/config.go6
-rw-r--r--internal/appconfig/config_test.go8
-rw-r--r--internal/hexaimcp/run.go6
-rw-r--r--internal/hexaimcp/run_test.go2
-rw-r--r--internal/stats/stats.go2
-rw-r--r--internal/tmuxedit/history_test.go2
8 files changed, 17 insertions, 18 deletions
diff --git a/.gitignore b/.gitignore
index 0d66562..43ae798 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,8 +11,7 @@ docs/coverage/
# Temp/scratch files
.tmux-edit-send.*.md
-/.gocache/
-/.gocache*
+/.local/
/.gomodcache/
/*.out
/*.html
diff --git a/README.md b/README.md
index 5a6417b..18f6c6f 100644
--- a/README.md
+++ b/README.md
@@ -47,15 +47,15 @@ hexai follows the XDG Base Directory Specification:
- **Configuration:** `~/.config/hexai/config.toml` (or `$XDG_CONFIG_HOME/hexai/`)
- Global settings, provider credentials, and preferences
- Project-specific: `.hexaiconfig.toml` at repository root
-- **Cache:** `~/.cache/hexai/` (or `$XDG_CACHE_HOME/hexai/`)
+- **Cache:** `~/.local/hexai/cache/` (or `$XDG_CACHE_HOME/hexai/`)
- `stats.json` - LLM usage tracking (regenerable)
- `stats.lock` - File lock for stats access
-- **State & Logs:** `~/.local/state/hexai/` (or `$XDG_STATE_HOME/hexai/`)
+- **State & Logs:** `~/.local/hexai/state/` (or `$XDG_STATE_HOME/state/`)
- `tmux-edit-history.jsonl` - History of text submitted via tmux popup
- `hexai-lsp.log` - LSP server debug logs
- `hexai-tmux-edit.log` - Tmux edit debug logs
- `hexai-mcp-server.log` - MCP server debug logs
-- **Data:** `~/.local/share/hexai/` (or `$XDG_DATA_HOME/hexai/`)
+- **Data:** `~/.local/hexai/data/` (or `$XDG_DATA_HOME/`)
- `prompts/default.jsonl` - Built-in prompts for MCP server
- `prompts/user.jsonl` - User-created custom prompts
- **Temporary Files:** `/tmp/` (OS temp directory)
diff --git a/internal/appconfig/config.go b/internal/appconfig/config.go
index 859b2c1..8ae9597 100644
--- a/internal/appconfig/config.go
+++ b/internal/appconfig/config.go
@@ -1284,7 +1284,7 @@ func ConfigPath() (string, error) {
return configPath, nil
}
-// StateDir returns the XDG state directory for hexai (~/.local/state/hexai by default).
+// StateDir returns the XDG state directory for hexai (~/.local/hexai/state by default).
// Creates the directory if it doesn't exist. This is used for persistent state data
// like logs and history that should survive reboots.
func StateDir() (string, error) {
@@ -1294,10 +1294,10 @@ func StateDir() (string, error) {
if err != nil {
return "", fmt.Errorf("cannot find user home directory: %v", err)
}
- stateHome = filepath.Join(home, ".local", "state")
+ stateHome = filepath.Join(home, ".local", "hexai")
}
- stateDir := filepath.Join(stateHome, "hexai")
+ stateDir := filepath.Join(stateHome, "state")
if err := os.MkdirAll(stateDir, 0o755); err != nil {
return "", fmt.Errorf("cannot create state directory: %v", err)
}
diff --git a/internal/appconfig/config_test.go b/internal/appconfig/config_test.go
index ed7254c..cf9a725 100644
--- a/internal/appconfig/config_test.go
+++ b/internal/appconfig/config_test.go
@@ -321,7 +321,7 @@ func TestStateDir_XDG(t *testing.T) {
if err != nil {
t.Fatalf("StateDir: %v", err)
}
- expected := filepath.Join(dir, "hexai")
+ expected := filepath.Join(dir, "state")
if stateDir != expected {
t.Fatalf("expected %q, got %q", expected, stateDir)
}
@@ -337,9 +337,9 @@ func TestStateDir_Default(t *testing.T) {
if err != nil {
t.Fatalf("StateDir: %v", err)
}
- // Should default to ~/.local/state/hexai
- if !strings.Contains(stateDir, ".local/state/hexai") {
- t.Fatalf("expected path to contain .local/state/hexai, got %q", stateDir)
+ // Should default to ~/.local/hexai/state
+ if !strings.Contains(stateDir, ".local/hexai/state") {
+ t.Fatalf("expected path to contain .local/hexai/state, got %q", stateDir)
}
// Verify directory was created
if _, err := os.Stat(stateDir); err != nil {
diff --git a/internal/hexaimcp/run.go b/internal/hexaimcp/run.go
index 448d826..6b28a2a 100644
--- a/internal/hexaimcp/run.go
+++ b/internal/hexaimcp/run.go
@@ -131,17 +131,17 @@ func getPromptsDir(cfg appconfig.App) (string, error) {
return expandPath(cfgDir)
}
- // Default: $XDG_DATA_HOME/hexai/prompts/ or ~/.local/share/hexai/prompts/
+ // Default: $XDG_DATA_HOME/prompts/ or ~/.local/hexai/data/prompts/
dataDir := os.Getenv("XDG_DATA_HOME")
if dataDir == "" {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("cannot find user home directory: %w", err)
}
- dataDir = filepath.Join(home, ".local", "share")
+ dataDir = filepath.Join(home, ".local", "hexai", "data")
}
- return filepath.Join(dataDir, "hexai", "prompts"), nil
+ return filepath.Join(dataDir, "prompts"), nil
}
// expandPath expands ~ to home directory and returns absolute path.
diff --git a/internal/hexaimcp/run_test.go b/internal/hexaimcp/run_test.go
index 981a05f..2adf678 100644
--- a/internal/hexaimcp/run_test.go
+++ b/internal/hexaimcp/run_test.go
@@ -114,7 +114,7 @@ func TestGetPromptsDir(t *testing.T) {
name: "uses default XDG location",
envVar: "",
cfgValue: "",
- wantMatch: "hexai/prompts",
+ wantMatch: ".local/hexai/data/prompts",
},
}
diff --git a/internal/stats/stats.go b/internal/stats/stats.go
index a98b2c5..7fa61b0 100644
--- a/internal/stats/stats.go
+++ b/internal/stats/stats.go
@@ -234,7 +234,7 @@ func CacheDir() (string, error) {
if err != nil {
return "", fmt.Errorf("cannot resolve home: %w", err)
}
- return filepath.Join(home, ".cache", "hexai"), nil
+ return filepath.Join(home, ".local", "hexai", "cache"), nil
}
// stringsTrim is a tiny helper to avoid importing strings everywhere here.
diff --git a/internal/tmuxedit/history_test.go b/internal/tmuxedit/history_test.go
index 8a3d8af..6d369fe 100644
--- a/internal/tmuxedit/history_test.go
+++ b/internal/tmuxedit/history_test.go
@@ -22,7 +22,7 @@ func TestAppendHistory(t *testing.T) {
}
// Verify file was created
- historyPath := filepath.Join(tmpDir, "hexai", "tmux-edit-history.jsonl")
+ historyPath := filepath.Join(tmpDir, "state", "tmux-edit-history.jsonl")
if _, err := os.Stat(historyPath); err != nil {
t.Fatalf("history file not created: %v", err)
}