feat: add bd admin parent command for cleanup/compact/reset (bd-3u8m)

Move cleanup, compact, and reset commands under `bd admin` namespace.
Creates hidden aliases for backwards compatibility that show deprecation
notice when used.

- Create cmd/bd/admin.go with parent command
- Create cmd/bd/admin_aliases.go for hidden backwards-compat aliases
- Update cleanup.go, compact.go, reset.go to remove rootCmd.AddCommand
- Update all documentation to use `bd admin <cmd>` syntax

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-27 16:07:13 -08:00
parent 2c82acd10b
commit d77a697cee
18 changed files with 173 additions and 63 deletions
+26
View File
@@ -0,0 +1,26 @@
package main
import (
"github.com/spf13/cobra"
)
var adminCmd = &cobra.Command{
Use: "admin",
GroupID: "advanced",
Short: "Administrative commands for database maintenance",
Long: `Administrative commands for beads database maintenance.
These commands are for advanced users and should be used carefully:
cleanup Delete closed issues and prune expired tombstones
compact Compact old closed issues to save space
reset Remove all beads data and configuration
For routine operations, prefer 'bd doctor --fix'.`,
}
func init() {
rootCmd.AddCommand(adminCmd)
adminCmd.AddCommand(cleanupCmd)
adminCmd.AddCommand(compactCmd)
adminCmd.AddCommand(resetCmd)
}
+86
View File
@@ -0,0 +1,86 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/steveyegge/beads/internal/ui"
)
// Hidden aliases for backwards compatibility.
// These commands forward to their admin subcommand equivalents.
// They are hidden from help output but still work for scripts/muscle memory.
var cleanupAliasCmd = &cobra.Command{
Use: "cleanup",
Hidden: true,
Short: "Alias for 'bd admin cleanup' (deprecated)",
Long: cleanupCmd.Long,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintln(os.Stderr, ui.RenderMuted("Note: 'bd cleanup' is now 'bd admin cleanup'"))
cleanupCmd.Run(cmd, args)
},
}
var compactAliasCmd = &cobra.Command{
Use: "compact",
Hidden: true,
Short: "Alias for 'bd admin compact' (deprecated)",
Long: compactCmd.Long,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintln(os.Stderr, ui.RenderMuted("Note: 'bd compact' is now 'bd admin compact'"))
compactCmd.Run(cmd, args)
},
}
var resetAliasCmd = &cobra.Command{
Use: "reset",
Hidden: true,
Short: "Alias for 'bd admin reset' (deprecated)",
Long: resetCmd.Long,
Run: func(cmd *cobra.Command, args []string) {
fmt.Fprintln(os.Stderr, ui.RenderMuted("Note: 'bd reset' is now 'bd admin reset'"))
resetCmd.Run(cmd, args)
},
}
func init() {
// Copy flags from original commands to aliases, binding to same global variables
// This ensures that when the alias command runs, the global flag variables are set correctly
// Cleanup alias flags - these read from cmd.Flags() in the Run function
cleanupAliasCmd.Flags().BoolP("force", "f", false, "Actually delete (without this flag, shows error)")
cleanupAliasCmd.Flags().Bool("dry-run", false, "Preview what would be deleted without making changes")
cleanupAliasCmd.Flags().Bool("cascade", false, "Recursively delete all dependent issues")
cleanupAliasCmd.Flags().Int("older-than", 0, "Only delete issues closed more than N days ago (0 = all closed issues)")
cleanupAliasCmd.Flags().Bool("hard", false, "Bypass tombstone TTL safety; use --older-than days as cutoff")
cleanupAliasCmd.Flags().Bool("ephemeral", false, "Only delete closed wisps (transient molecules)")
// Compact alias flags - must bind to same global variables as compactCmd
compactAliasCmd.Flags().BoolVar(&compactDryRun, "dry-run", false, "Preview without compacting")
compactAliasCmd.Flags().IntVar(&compactTier, "tier", 1, "Compaction tier (1 or 2)")
compactAliasCmd.Flags().BoolVar(&compactAll, "all", false, "Process all candidates")
compactAliasCmd.Flags().StringVar(&compactID, "id", "", "Compact specific issue")
compactAliasCmd.Flags().BoolVar(&compactForce, "force", false, "Force compact (bypass checks, requires --id)")
compactAliasCmd.Flags().IntVar(&compactBatch, "batch-size", 10, "Issues per batch")
compactAliasCmd.Flags().IntVar(&compactWorkers, "workers", 5, "Parallel workers")
compactAliasCmd.Flags().BoolVar(&compactStats, "stats", false, "Show compaction statistics")
compactAliasCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output JSON format")
compactAliasCmd.Flags().BoolVar(&compactAnalyze, "analyze", false, "Analyze mode: export candidates for agent review")
compactAliasCmd.Flags().BoolVar(&compactApply, "apply", false, "Apply mode: accept agent-provided summary")
compactAliasCmd.Flags().BoolVar(&compactAuto, "auto", false, "Auto mode: AI-powered compaction (legacy)")
compactAliasCmd.Flags().BoolVar(&compactPrune, "prune", false, "Prune mode: remove expired tombstones from issues.jsonl")
compactAliasCmd.Flags().IntVar(&compactOlderThan, "older-than", 0, "Prune tombstones older than N days (default: 30)")
compactAliasCmd.Flags().StringVar(&compactSummary, "summary", "", "Path to summary file (use '-' for stdin)")
compactAliasCmd.Flags().StringVar(&compactActor, "actor", "agent", "Actor name for audit trail")
compactAliasCmd.Flags().IntVar(&compactLimit, "limit", 0, "Limit number of candidates (0 = no limit)")
// Reset alias flags - these read from cmd.Flags() in the Run function
resetAliasCmd.Flags().Bool("force", false, "Actually perform the reset (required)")
// Register hidden aliases on root command
rootCmd.AddCommand(cleanupAliasCmd)
rootCmd.AddCommand(compactAliasCmd)
rootCmd.AddCommand(resetAliasCmd)
}
+3 -4
View File
@@ -26,9 +26,8 @@ func showCleanupDeprecationHint() {
}
var cleanupCmd = &cobra.Command{
Use: "cleanup",
GroupID: "maint",
Short: "Delete closed issues and prune expired tombstones",
Use: "cleanup",
Short: "Delete closed issues and prune expired tombstones",
Long: `Delete closed issues and prune expired tombstones to reduce database size.
This command:
@@ -271,5 +270,5 @@ func init() {
cleanupCmd.Flags().Int("older-than", 0, "Only delete issues closed more than N days ago (0 = all closed issues)")
cleanupCmd.Flags().Bool("hard", false, "Bypass tombstone TTL safety; use --older-than days as cutoff")
cleanupCmd.Flags().Bool("ephemeral", false, "Only delete closed wisps (transient molecules)")
rootCmd.AddCommand(cleanupCmd)
// Note: cleanupCmd is added to adminCmd in admin.go
}
+1 -1
View File
@@ -1195,5 +1195,5 @@ func init() {
compactCmd.Flags().StringVar(&compactActor, "actor", "agent", "Actor name for audit trail")
compactCmd.Flags().IntVar(&compactLimit, "limit", 0, "Limit number of candidates (0 = no limit)")
rootCmd.AddCommand(compactCmd)
// Note: compactCmd is added to adminCmd in admin.go
}
+3 -4
View File
@@ -15,9 +15,8 @@ import (
)
var resetCmd = &cobra.Command{
Use: "reset",
GroupID: "advanced",
Short: "Remove all beads data and configuration",
Use: "reset",
Short: "Remove all beads data and configuration",
Long: `Reset beads to an uninitialized state, removing all local data.
This command removes:
@@ -37,7 +36,7 @@ Examples:
func init() {
resetCmd.Flags().Bool("force", false, "Actually perform the reset (required)")
rootCmd.AddCommand(resetCmd)
// Note: resetCmd is added to adminCmd in admin.go
}
func runReset(cmd *cobra.Command, args []string) {
+5 -5
View File
@@ -12,11 +12,11 @@ Reduce database size by summarizing closed issues no longer actively referenced.
## Usage
- **Preview candidates**: `bd compact --dry-run`
- **Compact all eligible**: `bd compact --all`
- **Compact specific issue**: `bd compact --id bd-42`
- **Force compact**: `bd compact --id bd-42 --force` (bypass age checks)
- **View statistics**: `bd compact --stats`
- **Preview candidates**: `bd admin compact --dry-run`
- **Compact all eligible**: `bd admin compact --all`
- **Compact specific issue**: `bd admin compact --id bd-42`
- **Force compact**: `bd admin compact --id bd-42 --force` (bypass age checks)
- **View statistics**: `bd admin compact --stats`
## Options
+11 -11
View File
@@ -296,10 +296,10 @@ bd --actor alice <command>
```bash
# Clean up closed issues (bulk deletion)
bd cleanup --force --json # Delete ALL closed issues
bd cleanup --older-than 30 --force --json # Delete closed >30 days ago
bd cleanup --dry-run --json # Preview what would be deleted
bd cleanup --older-than 90 --cascade --force --json # Delete old + dependents
bd admin cleanup --force --json # Delete ALL closed issues
bd admin cleanup --older-than 30 --force --json # Delete closed >30 days ago
bd admin cleanup --dry-run --json # Preview what would be deleted
bd admin cleanup --older-than 90 --cascade --force --json # Delete old + dependents
```
### Duplicate Detection & Merging
@@ -319,15 +319,15 @@ bd merge bd-42 bd-43 --into bd-41 --dry-run # Preview merge
```bash
# Agent-driven compaction
bd compact --analyze --json # Get candidates for review
bd compact --analyze --tier 1 --limit 10 --json # Limited batch
bd compact --apply --id bd-42 --summary summary.txt # Apply compaction
bd compact --apply --id bd-42 --summary - < summary.txt # From stdin
bd compact --stats --json # Show statistics
bd admin compact --analyze --json # Get candidates for review
bd admin compact --analyze --tier 1 --limit 10 --json # Limited batch
bd admin compact --apply --id bd-42 --summary summary.txt # Apply compaction
bd admin compact --apply --id bd-42 --summary - < summary.txt # From stdin
bd admin compact --stats --json # Show statistics
# Legacy AI-powered compaction (requires ANTHROPIC_API_KEY)
bd compact --auto --dry-run --all # Preview
bd compact --auto --all --tier 1 # Auto-compact tier 1
bd admin compact --auto --dry-run --all # Preview
bd admin compact --auto --all --tier 1 # Auto-compact tier 1
# Restore compacted issue from git history
bd restore <id> # View full history at time of compaction
+1 -1
View File
@@ -576,7 +576,7 @@ jira_project = get_config("jira.project")
Some bd commands automatically use configuration:
- `bd compact` uses `compact_tier1_days`, `compact_tier1_dep_levels`, etc.
- `bd admin compact` uses `compact_tier1_days`, `compact_tier1_dep_levels`, etc.
- `bd init` sets `issue_prefix`
External integration scripts can read configuration to sync with Jira, Linear, GitHub, etc.
+3 -3
View File
@@ -66,7 +66,7 @@ Tombstones expire after a configurable TTL (default: 30 days). This prevents unb
### How Expiration Works
1. Tombstones older than TTL + 1 hour grace period are eligible for pruning
2. `bd compact` removes expired tombstones from `issues.jsonl`
2. `bd admin compact` removes expired tombstones from `issues.jsonl`
3. Git history fallback handles edge cases where pruned tombstones are needed
### Configuration
@@ -85,7 +85,7 @@ bd config set tombstone.ttl_days 60
### Manual Pruning
```bash
bd compact # Prune expired tombstones (and other compaction)
bd admin compact # Prune expired tombstones (and other compaction)
```
## Conflict Resolution
@@ -163,7 +163,7 @@ If you have many old tombstones:
bd list --status=tombstone | wc -l
# Prune expired tombstones
bd compact
bd admin compact
```
## Design Rationale
+2 -2
View File
@@ -333,10 +333,10 @@ Use compaction to remove old closed issues:
```bash
# Preview what would be compacted
bd compact --dry-run --all
bd admin compact --dry-run --all
# Compact issues closed more than 90 days ago
bd compact --days 90
bd admin compact --days 90
```
Or split your project into multiple databases:
+4 -4
View File
@@ -178,16 +178,16 @@ As your project accumulates closed issues, the database grows. Manage size with
```bash
# View compaction statistics
bd compact --stats
bd admin compact --stats
# Preview compaction candidates (30+ days closed)
bd compact --analyze --json --no-daemon
bd admin compact --analyze --json --no-daemon
# Apply agent-generated summary
bd compact --apply --id bd-42 --summary summary.txt --no-daemon
bd admin compact --apply --id bd-42 --summary summary.txt --no-daemon
# Immediately delete closed issues (CAUTION: permanent!)
bd cleanup --force
bd admin cleanup --force
```
**When to compact:**
+3 -3
View File
@@ -486,10 +486,10 @@ Check database size and consider compaction:
bd stats
# Preview compaction candidates
bd compact --dry-run --all
bd admin compact --dry-run --all
# Compact old closed issues
bd compact --days 90
bd admin compact --days 90
```
### Large JSONL files
@@ -501,7 +501,7 @@ If `.beads/issues.jsonl` is very large:
ls -lh .beads/issues.jsonl
# Remove old closed issues
bd compact --days 90
bd admin compact --days 90
# Or split into multiple projects
cd ~/project/component1 && bd init --prefix comp1
+1 -1
View File
@@ -171,7 +171,7 @@ Track compaction costs:
```bash
# Show stats after compaction
bd compact --stats
bd admin compact --stats
# Estimate monthly cost
# (issues_compacted / 1000) * $1.00
+4 -4
View File
@@ -46,7 +46,7 @@ fi
# Check eligible issues
echo "Checking eligible issues (Tier $TIER)..."
ELIGIBLE=$(bd compact --dry-run --all --tier "$TIER" --json 2>/dev/null | jq '. | length' || echo "0")
ELIGIBLE=$(bd admin compact --dry-run --all --tier "$TIER" --json 2>/dev/null | jq '. | length' || echo "0")
if [ -z "$ELIGIBLE" ] || [ "$ELIGIBLE" = "null" ]; then
ELIGIBLE=0
@@ -61,18 +61,18 @@ fi
if [ "$DRY_RUN" = true ]; then
echo "🔍 Dry run mode - showing candidates:"
bd compact --dry-run --all --tier "$TIER"
bd admin compact --dry-run --all --tier "$TIER"
exit 0
fi
# Run compaction
echo "🗜️ Compacting $ELIGIBLE issues (Tier $TIER)..."
bd compact --all --tier "$TIER"
bd admin compact --all --tier "$TIER"
# Show stats
echo
echo "📊 Statistics:"
bd compact --stats
bd admin compact --stats
echo
echo "✅ Auto-compaction complete"
+3 -3
View File
@@ -48,17 +48,17 @@ git pull origin main 2>&1 | tee -a "$LOG_FILE"
# Tier 1 compaction
log "Running Tier 1 compaction..."
TIER1_COUNT=$(bd compact --all --json 2>&1 | jq '. | length' || echo "0")
TIER1_COUNT=$(bd admin compact --all --json 2>&1 | jq '. | length' || echo "0")
log "Compacted $TIER1_COUNT Tier 1 issues"
# Tier 2 compaction
log "Running Tier 2 compaction..."
TIER2_COUNT=$(bd compact --all --tier 2 --json 2>&1 | jq '. | length' || echo "0")
TIER2_COUNT=$(bd admin compact --all --tier 2 --json 2>&1 | jq '. | length' || echo "0")
log "Compacted $TIER2_COUNT Tier 2 issues"
# Show statistics
log "Compaction statistics:"
bd compact --stats 2>&1 | tee -a "$LOG_FILE"
bd admin compact --stats 2>&1 | tee -a "$LOG_FILE"
# Commit and push if changes exist
if git diff --quiet .beads/issues.jsonl issues.db 2>/dev/null; then
+5 -5
View File
@@ -30,14 +30,14 @@ fi
# Preview candidates
echo "--- Preview Tier 1 Candidates ---"
bd compact --dry-run --all
bd admin compact --dry-run --all
echo
read -p "Proceed with Tier 1 compaction? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "--- Running Tier 1 Compaction ---"
bd compact --all
bd admin compact --all
echo "✅ Tier 1 compaction complete"
else
echo "⏭️ Skipping Tier 1"
@@ -46,14 +46,14 @@ fi
# Preview Tier 2
echo
echo "--- Preview Tier 2 Candidates ---"
bd compact --dry-run --all --tier 2
bd admin compact --dry-run --all --tier 2
echo
read -p "Proceed with Tier 2 compaction? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "--- Running Tier 2 Compaction ---"
bd compact --all --tier 2
bd admin compact --all --tier 2
echo "✅ Tier 2 compaction complete"
else
echo "⏭️ Skipping Tier 2"
@@ -62,7 +62,7 @@ fi
# Show stats
echo
echo "--- Final Statistics ---"
bd compact --stats
bd admin compact --stats
echo
echo "=== Compaction Complete ==="
+1 -1
View File
@@ -434,7 +434,7 @@ Shows:
| `bd daemon` | Background sync manager | "Start auto-sync daemon" |
| **CLEANUP COMMANDS** | | |
| `bd delete <id>` | Delete issues | "Delete test task" (requires --force) |
| `bd compact` | Archive old closed tasks | "Compress database" |
| `bd admin compact` | Archive old closed tasks | "Compress database" |
| **REPORTING COMMANDS** | | |
| `bd stats` | Project metrics | "Show project health" |
| `bd audit record` | Log interactions | "Record this LLM call" |
+11 -11
View File
@@ -285,10 +285,10 @@ bd --actor alice <command>
```bash
# Clean up closed issues (bulk deletion)
bd cleanup --force --json # Delete ALL closed issues
bd cleanup --older-than 30 --force --json # Delete closed >30 days ago
bd cleanup --dry-run --json # Preview what would be deleted
bd cleanup --older-than 90 --cascade --force --json # Delete old + dependents
bd admin cleanup --force --json # Delete ALL closed issues
bd admin cleanup --older-than 30 --force --json # Delete closed >30 days ago
bd admin cleanup --dry-run --json # Preview what would be deleted
bd admin cleanup --older-than 90 --cascade --force --json # Delete old + dependents
```
### Duplicate Detection & Merging
@@ -308,15 +308,15 @@ bd merge bd-42 bd-43 --into bd-41 --dry-run # Preview merge
```bash
# Agent-driven compaction
bd compact --analyze --json # Get candidates for review
bd compact --analyze --tier 1 --limit 10 --json # Limited batch
bd compact --apply --id bd-42 --summary summary.txt # Apply compaction
bd compact --apply --id bd-42 --summary - < summary.txt # From stdin
bd compact --stats --json # Show statistics
bd admin compact --analyze --json # Get candidates for review
bd admin compact --analyze --tier 1 --limit 10 --json # Limited batch
bd admin compact --apply --id bd-42 --summary summary.txt # Apply compaction
bd admin compact --apply --id bd-42 --summary - < summary.txt # From stdin
bd admin compact --stats --json # Show statistics
# Legacy AI-powered compaction (requires ANTHROPIC_API_KEY)
bd compact --auto --dry-run --all # Preview
bd compact --auto --all --tier 1 # Auto-compact tier 1
bd admin compact --auto --dry-run --all # Preview
bd admin compact --auto --all --tier 1 # Auto-compact tier 1
# Restore compacted issue from git history
bd restore <id> # View full history at time of compaction