feat(sync): add sync mode configuration (hq-ew1mbr.3)
Add configurable sync modes for Dolt storage integration: Sync modes: - git-portable (default): Export JSONL on push, import on pull - realtime: Export JSONL on every database change - dolt-native: Use Dolt remotes directly (no JSONL) - belt-and-suspenders: Both Dolt remote AND JSONL backup Configuration options in .beads/config.yaml: - sync.mode: Select sync mode - sync.export_on: push (default) or change - sync.import_on: pull (default) or change - conflict.strategy: newest (default), ours, theirs, manual - federation.remote: Dolt remote URL for dolt-native mode - federation.sovereignty: T1-T4 data sovereignty tier The sync command now displays configuration in `bd sync --status` and uses configured conflict strategy for resolution. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -115,11 +115,11 @@ The --full flag provides the legacy full sync behavior for backwards compatibili
|
||||
|
||||
// If resolve mode, resolve conflicts
|
||||
if resolve {
|
||||
strategy := "newest" // default
|
||||
strategy := config.GetConflictStrategy() // use configured default
|
||||
if resolveOurs {
|
||||
strategy = "ours"
|
||||
strategy = config.ConflictStrategyOurs
|
||||
} else if resolveTheirs {
|
||||
strategy = "theirs"
|
||||
strategy = config.ConflictStrategyTheirs
|
||||
}
|
||||
if err := resolveSyncConflicts(ctx, jsonlPath, strategy, dryRun); err != nil {
|
||||
FatalError("%v", err)
|
||||
@@ -681,8 +681,23 @@ func showSyncStateStatus(ctx context.Context, jsonlPath string) error {
|
||||
|
||||
beadsDir := filepath.Dir(jsonlPath)
|
||||
|
||||
// Sync mode
|
||||
fmt.Println("Sync mode: git-portable")
|
||||
// Sync mode (from config)
|
||||
syncCfg := config.GetSyncConfig()
|
||||
fmt.Printf("Sync mode: %s\n", syncCfg.Mode)
|
||||
fmt.Printf(" Export on: %s, Import on: %s\n", syncCfg.ExportOn, syncCfg.ImportOn)
|
||||
|
||||
// Conflict strategy
|
||||
conflictCfg := config.GetConflictConfig()
|
||||
fmt.Printf("Conflict strategy: %s\n", conflictCfg.Strategy)
|
||||
|
||||
// Federation config (if set)
|
||||
fedCfg := config.GetFederationConfig()
|
||||
if fedCfg.Remote != "" {
|
||||
fmt.Printf("Federation remote: %s\n", fedCfg.Remote)
|
||||
if fedCfg.Sovereignty != "" {
|
||||
fmt.Printf(" Sovereignty: %s\n", fedCfg.Sovereignty)
|
||||
}
|
||||
}
|
||||
|
||||
// Last export time
|
||||
lastExport, err := store.GetMetadata(ctx, "last_import_time")
|
||||
@@ -876,11 +891,15 @@ func resolveSyncConflicts(ctx context.Context, jsonlPath string, strategy string
|
||||
|
||||
var winner string
|
||||
switch strategy {
|
||||
case "ours":
|
||||
case config.ConflictStrategyOurs:
|
||||
winner = "local"
|
||||
case "theirs":
|
||||
case config.ConflictStrategyTheirs:
|
||||
winner = "remote"
|
||||
case "newest":
|
||||
case config.ConflictStrategyManual:
|
||||
// Manual mode should not reach here - conflicts are handled interactively
|
||||
fmt.Printf("⚠ %s: requires manual resolution\n", conflict.IssueID)
|
||||
continue
|
||||
case config.ConflictStrategyNewest:
|
||||
fallthrough
|
||||
default:
|
||||
// Compare updated_at timestamps
|
||||
@@ -898,7 +917,7 @@ func resolveSyncConflicts(ctx context.Context, jsonlPath string, strategy string
|
||||
}
|
||||
|
||||
fmt.Printf("✓ %s: kept %s", conflict.IssueID, winner)
|
||||
if strategy == "newest" {
|
||||
if strategy == config.ConflictStrategyNewest {
|
||||
fmt.Print(" (newer)")
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
Reference in New Issue
Block a user