summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/cli/serve.go78
-rw-r--r--internal/storage/db.go20
2 files changed, 36 insertions, 62 deletions
diff --git a/internal/cli/serve.go b/internal/cli/serve.go
index 1753a64..efac719 100644
--- a/internal/cli/serve.go
+++ b/internal/cli/serve.go
@@ -1,7 +1,6 @@
package cli
import (
- "bytes"
"context"
"fmt"
"net/http"
@@ -11,7 +10,6 @@ import (
"syscall"
"time"
- "github.com/BurntSushi/toml"
"github.com/thepeterstone/claudomator/internal/api"
"github.com/thepeterstone/claudomator/internal/executor"
"github.com/thepeterstone/claudomator/internal/notify"
@@ -46,29 +44,28 @@ func serve(addr string) error {
return fmt.Errorf("creating dirs: %w", err)
}
- // Auto-generate VAPID keys if not configured.
- if cfg.VAPIDPublicKey == "" || cfg.VAPIDPrivateKey == "" {
- pub, priv, err := notify.GenerateVAPIDKeys()
- if err != nil {
- return fmt.Errorf("generating VAPID keys: %w", err)
- }
- cfg.VAPIDPublicKey = pub
- cfg.VAPIDPrivateKey = priv
- // Write new keys back to config file.
- if cfgFile != "" {
- if err := saveVAPIDToConfig(cfgFile, pub, priv); err != nil {
- // Non-fatal: log but continue.
- fmt.Fprintf(os.Stderr, "warning: failed to persist VAPID keys to %s: %v\n", cfgFile, err)
- }
- }
- }
-
store, err := storage.Open(cfg.DBPath)
if err != nil {
return fmt.Errorf("opening db: %w", err)
}
defer store.Close()
+ // Load VAPID keys from DB; generate and persist if missing.
+ if cfg.VAPIDPublicKey == "" || cfg.VAPIDPrivateKey == "" {
+ pub, _ := store.GetSetting("vapid_public_key")
+ priv, _ := store.GetSetting("vapid_private_key")
+ if pub == "" || priv == "" {
+ pub, priv, err = notify.GenerateVAPIDKeys()
+ if err != nil {
+ return fmt.Errorf("generating VAPID keys: %w", err)
+ }
+ _ = store.SetSetting("vapid_public_key", pub)
+ _ = store.SetSetting("vapid_private_key", priv)
+ }
+ cfg.VAPIDPublicKey = pub
+ cfg.VAPIDPrivateKey = priv
+ }
+
logger := newLogger(verbose)
apiURL := "http://localhost" + addr
@@ -164,46 +161,3 @@ func serve(addr string) error {
return nil
}
-// saveVAPIDToConfig appends VAPID key assignments to the config file.
-// It reads the existing file (if any), then writes a complete TOML file with
-// the new keys merged in. Uses toml encoder for correctness.
-func saveVAPIDToConfig(path, pub, priv string) error {
- existing := cfg // already loaded
-
- // Marshal the full config back including the new VAPID keys.
- // We use a struct alias to only encode fields we want persisted.
- type persistedConfig struct {
- DataDir string `toml:"data_dir,omitempty"`
- ClaudeBinaryPath string `toml:"claude_binary_path,omitempty"`
- GeminiBinaryPath string `toml:"gemini_binary_path,omitempty"`
- MaxConcurrent int `toml:"max_concurrent,omitempty"`
- DefaultTimeout string `toml:"default_timeout,omitempty"`
- ServerAddr string `toml:"server_addr,omitempty"`
- WebhookURL string `toml:"webhook_url,omitempty"`
- WorkspaceRoot string `toml:"workspace_root,omitempty"`
- WebhookSecret string `toml:"webhook_secret,omitempty"`
- VAPIDPublicKey string `toml:"vapid_public_key,omitempty"`
- VAPIDPrivateKey string `toml:"vapid_private_key,omitempty"`
- VAPIDEmail string `toml:"vapid_email,omitempty"`
- }
- pc := persistedConfig{
- DataDir: existing.DataDir,
- ClaudeBinaryPath: existing.ClaudeBinaryPath,
- GeminiBinaryPath: existing.GeminiBinaryPath,
- MaxConcurrent: existing.MaxConcurrent,
- DefaultTimeout: existing.DefaultTimeout,
- ServerAddr: existing.ServerAddr,
- WebhookURL: existing.WebhookURL,
- WorkspaceRoot: existing.WorkspaceRoot,
- WebhookSecret: existing.WebhookSecret,
- VAPIDPublicKey: pub,
- VAPIDPrivateKey: priv,
- VAPIDEmail: existing.VAPIDEmail,
- }
-
- var buf bytes.Buffer
- if err := toml.NewEncoder(&buf).Encode(pc); err != nil {
- return fmt.Errorf("encoding config: %w", err)
- }
- return os.WriteFile(path, buf.Bytes(), 0600)
-}
diff --git a/internal/storage/db.go b/internal/storage/db.go
index 51121e1..25801b2 100644
--- a/internal/storage/db.go
+++ b/internal/storage/db.go
@@ -94,6 +94,10 @@ func (s *DB) migrate() error {
auth_key TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
+ `CREATE TABLE IF NOT EXISTS settings (
+ key TEXT PRIMARY KEY,
+ value TEXT NOT NULL
+ )`,
}
for _, m := range migrations {
if _, err := s.db.Exec(m); err != nil {
@@ -835,3 +839,19 @@ func (s *DB) ListPushSubscriptions() ([]PushSubscription, error) {
}
return subs, rows.Err()
}
+
+// GetSetting returns the value for a key, or ("", nil) if not found.
+func (s *DB) GetSetting(key string) (string, error) {
+ var value string
+ err := s.db.QueryRow(`SELECT value FROM settings WHERE key = ?`, key).Scan(&value)
+ if err == sql.ErrNoRows {
+ return "", nil
+ }
+ return value, err
+}
+
+// SetSetting upserts a key/value pair in the settings table.
+func (s *DB) SetSetting(key, value string) error {
+ _, err := s.db.Exec(`INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`, key, value)
+ return err
+}