bd sync: 2025-10-31 22:39:53

This commit is contained in:
Steve Yegge
2025-10-31 22:39:53 -07:00
parent c2d3ad2d63
commit acb731a4ec
10 changed files with 119 additions and 9 deletions

File diff suppressed because one or more lines are too long

View File

@@ -571,6 +571,7 @@ func init() {
compactCmd.Flags().IntVar(&compactBatch, "batch-size", 10, "Issues per batch")
compactCmd.Flags().IntVar(&compactWorkers, "workers", 5, "Parallel workers")
compactCmd.Flags().BoolVar(&compactStats, "stats", false, "Show compaction statistics")
compactCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format")
rootCmd.AddCommand(compactCmd)
}

View File

@@ -340,4 +340,55 @@ func TestCompactInitCommand(t *testing.T) {
if len(compactCmd.Long) == 0 {
t.Error("compactCmd should have Long description")
}
// Verify --json flag exists
jsonFlag := compactCmd.Flags().Lookup("json")
if jsonFlag == nil {
t.Error("compact command should have --json flag")
}
}
func TestCompactStatsJSON(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, ".beads", "beads.db")
if err := os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
t.Fatal(err)
}
sqliteStore, err := sqlite.New(dbPath)
if err != nil {
t.Fatal(err)
}
defer sqliteStore.Close()
ctx := context.Background()
// Set issue_prefix
if err := sqliteStore.SetConfig(ctx, "issue_prefix", "test"); err != nil {
t.Fatalf("Failed to set issue_prefix: %v", err)
}
// Create a closed issue eligible for Tier 1
issue := &types.Issue{
ID: "test-1",
Title: "Test Issue",
Description: string(make([]byte, 500)),
Status: types.StatusClosed,
Priority: 2,
IssueType: types.TypeTask,
CreatedAt: time.Now().Add(-60 * 24 * time.Hour),
ClosedAt: ptrTime(time.Now().Add(-35 * 24 * time.Hour)),
}
if err := sqliteStore.CreateIssue(ctx, issue, "test"); err != nil {
t.Fatal(err)
}
// Test with JSON output
savedJSONOutput := jsonOutput
jsonOutput = true
defer func() { jsonOutput = savedJSONOutput }()
// Should not panic and should execute JSON path
runCompactStats(ctx, sqliteStore)
}

View File

@@ -184,6 +184,7 @@ func init() {
daemonCmd.Flags().Bool("migrate-to-global", false, "Migrate from local to global daemon")
daemonCmd.Flags().String("log", "", "Log file path (default: .beads/daemon.log)")
daemonCmd.Flags().Bool("global", false, "Run as global daemon (socket at ~/.beads/bd.sock)")
daemonCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format")
rootCmd.AddCommand(daemonCmd)
}
@@ -324,19 +325,47 @@ func showDaemonStatus(pidFile string, global bool) {
if global {
scope = "global"
}
fmt.Printf("Daemon is running (PID %d, %s)\n", pid, scope)
var started string
if info, err := os.Stat(pidFile); err == nil {
fmt.Printf(" Started: %s\n", info.ModTime().Format("2006-01-02 15:04:05"))
started = info.ModTime().Format("2006-01-02 15:04:05")
}
logPath, err := getLogFilePath("", global)
if err == nil {
if _, err := os.Stat(logPath); err == nil {
fmt.Printf(" Log: %s\n", logPath)
var logPath string
if lp, err := getLogFilePath("", global); err == nil {
if _, err := os.Stat(lp); err == nil {
logPath = lp
}
}
if jsonOutput {
status := map[string]interface{}{
"running": true,
"pid": pid,
"scope": scope,
}
if started != "" {
status["started"] = started
}
if logPath != "" {
status["log_path"] = logPath
}
outputJSON(status)
return
}
fmt.Printf("Daemon is running (PID %d, %s)\n", pid, scope)
if started != "" {
fmt.Printf(" Started: %s\n", started)
}
if logPath != "" {
fmt.Printf(" Log: %s\n", logPath)
}
} else {
if jsonOutput {
outputJSON(map[string]interface{}{"running": false})
return
}
fmt.Println("Daemon is not running")
}
}

View File

@@ -308,6 +308,21 @@ Output to stdout by default, or use -o flag for file output.`,
fmt.Fprintf(os.Stderr, "Warning: failed to set file permissions: %v\n", err)
}
}
// Output statistics if JSON format requested
if jsonOutput {
stats := map[string]interface{}{
"success": true,
"exported": len(exportedIDs),
"skipped": skippedCount,
"total_issues": len(issues),
}
if output != "" {
stats["output_file"] = output
}
data, _ := json.MarshalIndent(stats, "", " ")
fmt.Fprintln(os.Stderr, string(data))
}
},
}
@@ -316,5 +331,6 @@ func init() {
exportCmd.Flags().StringP("output", "o", "", "Output file (default: stdout)")
exportCmd.Flags().StringP("status", "s", "", "Filter by status")
exportCmd.Flags().Bool("force", false, "Force export even if database is empty")
exportCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output export statistics in JSON format")
rootCmd.AddCommand(exportCmd)
}

View File

@@ -249,5 +249,6 @@ func init() {
importCmd.Flags().Bool("dedupe-after", false, "Detect and report content duplicates after import")
importCmd.Flags().Bool("dry-run", false, "Preview collision detection without making changes")
importCmd.Flags().Bool("rename-on-import", false, "Rename imported issues to match database prefix (updates all references)")
importCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output import statistics in JSON format")
rootCmd.AddCommand(importCmd)
}

View File

@@ -588,5 +588,6 @@ func init() {
migrateCmd.Flags().Bool("dry-run", false, "Show what would be done without making changes")
migrateCmd.Flags().Bool("update-repo-id", false, "Update repository ID (use after changing git remote)")
migrateCmd.Flags().Bool("to-hash-ids", false, "Migrate sequential IDs to hash-based IDs")
migrateCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output migration statistics in JSON format")
rootCmd.AddCommand(migrateCmd)
}

View File

@@ -171,5 +171,6 @@ Interactive mode with --interactive prompts for each orphan.`,
func init() {
repairDepsCmd.Flags().Bool("fix", false, "Automatically remove orphaned dependencies")
repairDepsCmd.Flags().Bool("interactive", false, "Interactively review each orphaned dependency")
repairDepsCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output repair results in JSON format")
rootCmd.AddCommand(repairDepsCmd)
}

View File

@@ -112,6 +112,7 @@ This is read-only and does not modify the database or git state.`,
}
func init() {
restoreCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output restore results in JSON format")
rootCmd.AddCommand(restoreCmd)
}

View File

@@ -247,6 +247,7 @@ func init() {
syncCmd.Flags().Bool("rename-on-import", false, "Rename imported issues to match database prefix (updates all references)")
syncCmd.Flags().Bool("flush-only", false, "Only export pending changes to JSONL (skip git operations)")
syncCmd.Flags().Bool("import-only", false, "Only import from JSONL (skip git operations, useful after git pull)")
syncCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output sync statistics in JSON format")
rootCmd.AddCommand(syncCmd)
}