Ariver
2026-06-13 8f593a641529e3982d2820e73fd82203b5cfb7f8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package model
 
import (
    "encoding/json"
    "os"
    "path/filepath"
    "time"
 
    "voicesnap/internal/paths"
)
 
type InstallState struct {
    SchemaVersion   int                            `json:"schemaVersion"`
    SelectedModelID string                         `json:"selectedModelId"`
    InstalledModels map[string]InstalledModelState `json:"installedModels"`
}
 
type InstalledModelState struct {
    InstalledAt   int64  `json:"installedAt"`
    Version       string `json:"version"`
    Path          string `json:"path"`
    SourceDirKind string `json:"sourceDirKind"`
}
 
func NewInstallState() *InstallState {
    return &InstallState{
        SchemaVersion:   1,
        SelectedModelID: DefaultModelID,
        InstalledModels: make(map[string]InstalledModelState),
    }
}
 
func LoadInstallState() (*InstallState, error) {
    return LoadInstallStateFromRoot(paths.ModelsRoot())
}
 
func LoadInstallStateFromRoot(modelsRoot string) (*InstallState, error) {
    data, err := os.ReadFile(filepath.Join(modelsRoot, "state.json"))
    if err != nil {
        if os.IsNotExist(err) {
            return NewInstallState(), nil
        }
        return NewInstallState(), err
    }
 
    state := NewInstallState()
    if err := json.Unmarshal(data, state); err != nil {
        return NewInstallState(), err
    }
    normalizeInstallState(state)
    return state, nil
}
 
func SaveInstallState(state *InstallState) error {
    return SaveInstallStateToRoot(paths.ModelsRoot(), state)
}
 
func SaveInstallStateToRoot(modelsRoot string, state *InstallState) error {
    normalizeInstallState(state)
    if err := os.MkdirAll(modelsRoot, 0755); err != nil {
        return err
    }
 
    data, err := json.MarshalIndent(state, "", "  ")
    if err != nil {
        return err
    }
 
    target := filepath.Join(modelsRoot, "state.json")
    tmp := target + ".tmp"
    if err := os.WriteFile(tmp, data, 0644); err != nil {
        return err
    }
    return os.Rename(tmp, target)
}
 
func UpdateInstalledModelState(modelsRoot string, profile ModelProfile, relPath, sourceDirKind string) error {
    state, _ := LoadInstallStateFromRoot(modelsRoot)
    state.SelectedModelID = profile.ID
    state.InstalledModels[profile.ID] = InstalledModelState{
        InstalledAt:   time.Now().UnixMilli(),
        Version:       "unknown",
        Path:          relPath,
        SourceDirKind: sourceDirKind,
    }
    return SaveInstallStateToRoot(modelsRoot, state)
}
 
func normalizeInstallState(state *InstallState) {
    if state.SchemaVersion == 0 {
        state.SchemaVersion = 1
    }
    state.SelectedModelID = NormalizeModelID(state.SelectedModelID)
    if state.InstalledModels == nil {
        state.InstalledModels = make(map[string]InstalledModelState)
    }
}