26f897c1ec
release / release-please (push) Failing after 1m49s
docs / build (push) Failing after 6m34s
release / build-and-upload (arm64, linux) (push) Has been cancelled
release / build-and-upload (arm64, windows) (push) Has been cancelled
release / build-darwin (amd64, darwin) (push) Has been cancelled
release / checksums (push) Has been cancelled
release / finalize (push) Has been cancelled
release / build-darwin (arm64, darwin) (push) Has been cancelled
release / build-and-upload (amd64, linux) (push) Has been cancelled
release / build-and-upload (amd64, windows) (push) Has been cancelled
docs / deploy (push) Has been cancelled
93 lines
3.1 KiB
Go
93 lines
3.1 KiB
Go
package paths
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// Paths provides access to all no-mistakes filesystem locations.
|
|
// The root defaults to ~/.no-mistakes but can be overridden via NM_HOME
|
|
// or by using WithRoot (for testing).
|
|
type Paths struct {
|
|
root string
|
|
}
|
|
|
|
// New returns Paths rooted at NM_HOME or ~/.no-mistakes.
|
|
func New() (*Paths, error) {
|
|
if env := os.Getenv("NM_HOME"); env != "" {
|
|
return &Paths{root: env}, nil
|
|
}
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Paths{root: filepath.Join(home, ".no-mistakes")}, nil
|
|
}
|
|
|
|
// WithRoot returns Paths rooted at a custom directory (for testing).
|
|
func WithRoot(root string) *Paths {
|
|
return &Paths{root: root}
|
|
}
|
|
|
|
func (p *Paths) Root() string { return p.root }
|
|
func (p *Paths) DB() string { return filepath.Join(p.root, "state.sqlite") }
|
|
func (p *Paths) Socket() string { return filepath.Join(p.root, "socket") }
|
|
func (p *Paths) PIDFile() string { return filepath.Join(p.root, "daemon.pid") }
|
|
func (p *Paths) ConfigFile() string { return filepath.Join(p.root, "config.yaml") }
|
|
|
|
// LockFile is the OS-level advisory lock used to enforce a single live daemon
|
|
// per NM_HOME (see the singleton lock in internal/daemon). Distinct from
|
|
// PIDFile, which is an informational record a live daemon writes for
|
|
// CLI/status consumers: LockFile is what actually prevents two daemons from
|
|
// ever running startup recovery or binding the socket concurrently for the
|
|
// same root.
|
|
func (p *Paths) LockFile() string { return filepath.Join(p.root, "daemon.lock") }
|
|
func (p *Paths) UpdateCheckFile() string {
|
|
return filepath.Join(p.root, "update-check.json")
|
|
}
|
|
|
|
// TelemetryGateFile persists the read-surface telemetry dedupe state so
|
|
// high-frequency status polling stays rate-limited across CLI processes.
|
|
func (p *Paths) TelemetryGateFile() string {
|
|
return filepath.Join(p.root, "telemetry-gate.json")
|
|
}
|
|
|
|
func (p *Paths) ReposDir() string { return filepath.Join(p.root, "repos") }
|
|
func (p *Paths) RepoDir(repoID string) string {
|
|
return filepath.Join(p.root, "repos", repoID+".git")
|
|
}
|
|
|
|
func (p *Paths) WorktreesDir() string { return filepath.Join(p.root, "worktrees") }
|
|
func (p *Paths) WorktreeDir(repoID, runID string) string {
|
|
return filepath.Join(p.root, "worktrees", repoID, runID)
|
|
}
|
|
|
|
func (p *Paths) LogsDir() string { return filepath.Join(p.root, "logs") }
|
|
func (p *Paths) RunLogDir(runID string) string {
|
|
return filepath.Join(p.root, "logs", runID)
|
|
}
|
|
func (p *Paths) DaemonLog() string { return filepath.Join(p.root, "logs", "daemon.log") }
|
|
func (p *Paths) CLILog() string { return filepath.Join(p.root, "logs", "cli.log") }
|
|
|
|
// ServerPIDsDir holds PID-tracking files for managed agent servers
|
|
// (opencode, rovodev) so a freshly started daemon can reap orphans left
|
|
// behind by a crashed predecessor.
|
|
func (p *Paths) ServerPIDsDir() string { return filepath.Join(p.root, "servers") }
|
|
|
|
// EnsureDirs creates all required directories under root.
|
|
func (p *Paths) EnsureDirs() error {
|
|
dirs := []string{
|
|
p.root,
|
|
p.ReposDir(),
|
|
p.WorktreesDir(),
|
|
p.LogsDir(),
|
|
p.ServerPIDsDir(),
|
|
}
|
|
for _, d := range dirs {
|
|
if err := os.MkdirAll(d, 0o755); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|