diff options
| author | Clawd <ai@clawd.bot> | 2026-04-18 14:40:17 -0700 |
|---|---|---|
| committer | Clawd <ai@clawd.bot> | 2026-04-18 14:40:17 -0700 |
| commit | 778bef5ee6941056e06326d1eaaa6956d7307a85 (patch) | |
| tree | 23b85f32fb69f85078b3debec08c1353694def6f /internal/state | |
| parent | eb76b1f6e1697ef170fc45d25e81b21679ea7b0d (diff) | |
Remove Go implementation — ship is skills-only nowmain
The skills/ directory fully replaces the old Go CLI. Drop all Go
source, build files, planning docs, and the stale SECURITY.md
(which described the old git-user push-deploy model that no longer
exists). Trim .gitignore to match the new tree.
Diffstat (limited to 'internal/state')
| -rw-r--r-- | internal/state/state.go | 106 |
1 files changed, 0 insertions, 106 deletions
diff --git a/internal/state/state.go b/internal/state/state.go deleted file mode 100644 index 9b06179..0000000 --- a/internal/state/state.go +++ /dev/null | |||
| @@ -1,106 +0,0 @@ | |||
| 1 | package state | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "encoding/json" | ||
| 5 | "fmt" | ||
| 6 | "os" | ||
| 7 | "path/filepath" | ||
| 8 | "regexp" | ||
| 9 | ) | ||
| 10 | |||
| 11 | // State represents the local ship configuration | ||
| 12 | type State struct { | ||
| 13 | DefaultHost string `json:"default_host,omitempty"` | ||
| 14 | Hosts map[string]*Host `json:"hosts"` | ||
| 15 | } | ||
| 16 | |||
| 17 | // Host represents configuration for a single VPS | ||
| 18 | type Host struct { | ||
| 19 | BaseDomain string `json:"base_domain,omitempty"` | ||
| 20 | GitSetup bool `json:"git_setup,omitempty"` | ||
| 21 | } | ||
| 22 | |||
| 23 | var validName = regexp.MustCompile(`^[a-z][a-z0-9-]{0,62}$`) | ||
| 24 | |||
| 25 | // ValidateName checks that a name is safe for use in shell commands, | ||
| 26 | // file paths, systemd units, and DNS labels. | ||
| 27 | func ValidateName(name string) error { | ||
| 28 | if !validName.MatchString(name) { | ||
| 29 | return fmt.Errorf("invalid name %q: must start with a lowercase letter, contain only lowercase letters, digits, and hyphens, and be 1-63 characters", name) | ||
| 30 | } | ||
| 31 | return nil | ||
| 32 | } | ||
| 33 | |||
| 34 | // Load reads state from ~/.config/ship/state.json | ||
| 35 | func Load() (*State, error) { | ||
| 36 | path := statePath() | ||
| 37 | |||
| 38 | if _, err := os.Stat(path); os.IsNotExist(err) { | ||
| 39 | return &State{ | ||
| 40 | Hosts: make(map[string]*Host), | ||
| 41 | }, nil | ||
| 42 | } | ||
| 43 | |||
| 44 | data, err := os.ReadFile(path) | ||
| 45 | if err != nil { | ||
| 46 | return nil, fmt.Errorf("failed to read state file: %w", err) | ||
| 47 | } | ||
| 48 | |||
| 49 | var state State | ||
| 50 | if err := json.Unmarshal(data, &state); err != nil { | ||
| 51 | return nil, fmt.Errorf("failed to parse state file: %w", err) | ||
| 52 | } | ||
| 53 | |||
| 54 | if state.Hosts == nil { | ||
| 55 | state.Hosts = make(map[string]*Host) | ||
| 56 | } | ||
| 57 | |||
| 58 | return &state, nil | ||
| 59 | } | ||
| 60 | |||
| 61 | // Save writes state to ~/.config/ship/state.json | ||
| 62 | func (s *State) Save() error { | ||
| 63 | path := statePath() | ||
| 64 | |||
| 65 | dir := filepath.Dir(path) | ||
| 66 | if err := os.MkdirAll(dir, 0755); err != nil { | ||
| 67 | return fmt.Errorf("failed to create config directory: %w", err) | ||
| 68 | } | ||
| 69 | |||
| 70 | data, err := json.MarshalIndent(s, "", " ") | ||
| 71 | if err != nil { | ||
| 72 | return fmt.Errorf("failed to marshal state: %w", err) | ||
| 73 | } | ||
| 74 | |||
| 75 | if err := os.WriteFile(path, data, 0600); err != nil { | ||
| 76 | return fmt.Errorf("failed to write state file: %w", err) | ||
| 77 | } | ||
| 78 | |||
| 79 | return nil | ||
| 80 | } | ||
| 81 | |||
| 82 | // GetHost returns the host config, creating it if it doesn't exist | ||
| 83 | func (s *State) GetHost(host string) *Host { | ||
| 84 | if s.Hosts[host] == nil { | ||
| 85 | s.Hosts[host] = &Host{} | ||
| 86 | } | ||
| 87 | return s.Hosts[host] | ||
| 88 | } | ||
| 89 | |||
| 90 | // GetDefaultHost returns the default host, or empty string if not set | ||
| 91 | func (s *State) GetDefaultHost() string { | ||
| 92 | return s.DefaultHost | ||
| 93 | } | ||
| 94 | |||
| 95 | // SetDefaultHost sets the default host | ||
| 96 | func (s *State) SetDefaultHost(host string) { | ||
| 97 | s.DefaultHost = host | ||
| 98 | } | ||
| 99 | |||
| 100 | func statePath() string { | ||
| 101 | home, err := os.UserHomeDir() | ||
| 102 | if err != nil { | ||
| 103 | return ".ship-state.json" | ||
| 104 | } | ||
| 105 | return filepath.Join(home, ".config", "ship", "state.json") | ||
| 106 | } | ||
