mirror of
https://github.com/lukaszraczylo/claude-mnemonic.git
synced 2026-10-18 06:09:15 +00:00
Startup and update sequence
1. Version mismatch restart loop (pkg/hooks/worker.go):
- Added versionsCompatible() and extractBaseVersion() functions
- Hooks no longer restart worker when base versions match (e.g., v0.3.5-dirty ≈ v0.3.5-2-gca711a8-dirty)
2. Auto-update detection (internal/update/update.go):
- isNewerVersion() now extracts base version before comparing
- No longer always reports updates for dirty/dev builds
3. Non-blocking ChromaDB sync (internal/worker/handlers.go):
- SyncUserPrompt now runs in a goroutine with 10-second timeout
- /api/sessions/init responds immediately without waiting for ChromaDB
This commit is contained in:
@@ -27,6 +27,7 @@ dashboard:
|
|||||||
@cd ui && npm install --silent && npm run build
|
@cd ui && npm install --silent && npm run build
|
||||||
@rm -rf internal/worker/static
|
@rm -rf internal/worker/static
|
||||||
@mkdir -p internal/worker/static
|
@mkdir -p internal/worker/static
|
||||||
|
@touch internal/worker/static/placeholder.html
|
||||||
@cp -r ui/dist/* internal/worker/static/
|
@cp -r ui/dist/* internal/worker/static/
|
||||||
|
|
||||||
# Build worker service
|
# Build worker service
|
||||||
|
|||||||
@@ -537,14 +537,16 @@ func isNewerVersion(latest, current string) bool {
|
|||||||
latest = strings.TrimPrefix(latest, "v")
|
latest = strings.TrimPrefix(latest, "v")
|
||||||
current = strings.TrimPrefix(current, "v")
|
current = strings.TrimPrefix(current, "v")
|
||||||
|
|
||||||
// Handle dev/dirty versions
|
// For dev/dirty builds, extract the base version for comparison
|
||||||
if strings.Contains(current, "-dirty") || strings.Contains(current, "-dev") {
|
// e.g., "0.3.5-2-gca711a8-dirty" -> "0.3.5"
|
||||||
return true // Always show update available for dev builds
|
currentBase := current
|
||||||
|
if idx := strings.Index(current, "-"); idx > 0 {
|
||||||
|
currentBase = current[:idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simple semver comparison
|
// Simple semver comparison using base version
|
||||||
latestParts := strings.Split(latest, ".")
|
latestParts := strings.Split(latest, ".")
|
||||||
currentParts := strings.Split(current, ".")
|
currentParts := strings.Split(currentBase, ".")
|
||||||
|
|
||||||
for i := 0; i < len(latestParts) && i < len(currentParts); i++ {
|
for i := 0; i < len(latestParts) && i < len(currentParts); i++ {
|
||||||
latestNum, _ := strconv.Atoi(latestParts[i])
|
latestNum, _ := strconv.Atoi(latestParts[i])
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
package worker
|
package worker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -153,7 +154,7 @@ func (s *Service) handleSessionInit(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Warn().Err(err).Msg("Failed to save user prompt")
|
log.Warn().Err(err).Msg("Failed to save user prompt")
|
||||||
// Non-fatal: continue with session initialization
|
// Non-fatal: continue with session initialization
|
||||||
} else if s.chromaSync != nil {
|
} else if s.chromaSync != nil {
|
||||||
// Sync to vector DB
|
// Sync to vector DB asynchronously (non-blocking)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
promptWithSession := &models.UserPromptWithSession{
|
promptWithSession := &models.UserPromptWithSession{
|
||||||
UserPrompt: models.UserPrompt{
|
UserPrompt: models.UserPrompt{
|
||||||
@@ -168,9 +169,13 @@ func (s *Service) handleSessionInit(w http.ResponseWriter, r *http.Request) {
|
|||||||
Project: req.Project,
|
Project: req.Project,
|
||||||
SDKSessionID: req.ClaudeSessionID,
|
SDKSessionID: req.ClaudeSessionID,
|
||||||
}
|
}
|
||||||
if err := s.chromaSync.SyncUserPrompt(r.Context(), promptWithSession); err != nil {
|
go func() {
|
||||||
log.Warn().Err(err).Int64("id", promptID).Msg("Failed to sync user prompt to ChromaDB")
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
}
|
defer cancel()
|
||||||
|
if err := s.chromaSync.SyncUserPrompt(ctx, promptWithSession); err != nil {
|
||||||
|
log.Warn().Err(err).Int64("id", promptID).Msg("Failed to sync user prompt to ChromaDB")
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().
|
log.Info().
|
||||||
|
|||||||
+36
-1
@@ -58,9 +58,13 @@ func EnsureWorkerRunning() (int, error) {
|
|||||||
|
|
||||||
// Check if already running and healthy
|
// Check if already running and healthy
|
||||||
if IsWorkerRunning(port) {
|
if IsWorkerRunning(port) {
|
||||||
// Check version - if mismatch, restart
|
// Check version - if mismatch, restart (unless both are dev builds)
|
||||||
if runningVersion := GetWorkerVersion(port); runningVersion != "" {
|
if runningVersion := GetWorkerVersion(port); runningVersion != "" {
|
||||||
if runningVersion != Version {
|
if runningVersion != Version {
|
||||||
|
// For dev/dirty builds, don't restart if base versions match
|
||||||
|
if versionsCompatible(runningVersion, Version) {
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
fmt.Fprintf(os.Stderr, "[claude-mnemonic] Worker version mismatch (running: %s, expected: %s), restarting...\n", runningVersion, Version)
|
fmt.Fprintf(os.Stderr, "[claude-mnemonic] Worker version mismatch (running: %s, expected: %s), restarting...\n", runningVersion, Version)
|
||||||
if err := KillProcessOnPort(port); err != nil {
|
if err := KillProcessOnPort(port); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "[claude-mnemonic] Warning: failed to kill old worker: %v\n", err)
|
fmt.Fprintf(os.Stderr, "[claude-mnemonic] Warning: failed to kill old worker: %v\n", err)
|
||||||
@@ -275,3 +279,34 @@ func GET(port int, path string) (map[string]interface{}, error) {
|
|||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// versionsCompatible checks if two versions are compatible for dev builds.
|
||||||
|
// Returns true if both versions share the same base version (ignoring -dirty, -dev, commit suffixes).
|
||||||
|
// This prevents unnecessary restarts during development.
|
||||||
|
func versionsCompatible(v1, v2 string) bool {
|
||||||
|
// If either is a plain "dev" version, consider it compatible with anything
|
||||||
|
if v1 == "dev" || v2 == "dev" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract base versions (e.g., "v0.3.5" from "v0.3.5-2-gca711a8-dirty")
|
||||||
|
base1 := extractBaseVersion(v1)
|
||||||
|
base2 := extractBaseVersion(v2)
|
||||||
|
|
||||||
|
// If base versions match, they're compatible
|
||||||
|
return base1 == base2
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractBaseVersion extracts the semver base from a version string.
|
||||||
|
// e.g., "v0.3.5-2-gca711a8-dirty" -> "0.3.5"
|
||||||
|
func extractBaseVersion(version string) string {
|
||||||
|
// Remove leading 'v' if present
|
||||||
|
v := strings.TrimPrefix(version, "v")
|
||||||
|
|
||||||
|
// Find first hyphen (start of suffix like -2-gcommit-dirty)
|
||||||
|
if idx := strings.Index(v, "-"); idx > 0 {
|
||||||
|
v = v[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user