Fix nil pointer crash in bd reopen command (bd-133)

- Add daemon RPC support to reopen command
- Check daemonClient != nil first, use RPC if available
- Fall back to direct store access with nil check
- Reopened bd-55 for remaining cyclomatic complexity work

Amp-Thread-ID: https://ampcode.com/threads/T-2ea7e226-4672-4a49-96b4-81ab5cf953cd
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-10-25 10:39:45 -07:00
parent fe30e0c527
commit d2084dc3af
2 changed files with 52 additions and 1 deletions

View File

@@ -36,6 +36,7 @@
{"id":"bd-130","title":"Re-land TestDatabaseReinitialization after fixing Windows/Nix issues","description":"TestDatabaseReinitialization test was reverted due to CI failures:\n- Windows: JSON parse errors, missing files \n- Nix: git not available in build environment\n\nNeed to fix and re-land:\n1. Make test work on Windows (path separators, file handling)\n2. Skip test in Nix environment or mock git\n3. Fix JSON parsing issues","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-24T15:06:27.385396-07:00","updated_at":"2025-10-24T15:06:27.385396-07:00"}
{"id":"bd-131","title":"Feature: Use external_ref as primary matching key for import updates","description":"Implement external_ref-based matching for imports to enable hybrid workflows with external systems (Jira, GitHub, Linear).\n\n## Problem\nCurrent import collision detection treats any content change as a collision, preventing users from syncing updates from external systems without creating duplicates.\n\n## Solution\nUse external_ref field as primary matching key during imports. When an incoming issue has external_ref set:\n- Search for existing issue with same external_ref\n- If found, UPDATE (not collision)\n- If not found, create new issue\n- Never match local issues (without external_ref)\n\n## Use Cases\n- Jira integration: Import backlog, add local tasks, re-sync updates\n- GitHub integration: Import issues, track with local subtasks, sync status\n- Linear integration: Team coordination with local breakdown\n\n## Reference\nGitHub issue #142: https://github.com/steveyegge/beads/issues/142","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-10-24T22:10:24.862547-07:00","updated_at":"2025-10-25T10:17:33.543504-07:00","closed_at":"2025-10-25T10:17:33.543504-07:00"}
{"id":"bd-132","title":"GH#146: No color showing in terminal for some users","description":"User reports color not working in macOS (Taho 26.0.1) with iTerm 3.6.4 and Terminal.app, despite color working elsewhere in terminal. Python rich and printf escape codes work.\n\nNeed to investigate:\n- Is NO_COLOR env var set?\n- Terminal type detection?\n- fatih/color library configuration\n- Does bd list show colors? bd ready? bd init?\n- What's the output of: echo $TERM, echo $NO_COLOR","status":"open","priority":2,"issue_type":"bug","created_at":"2025-10-24T22:26:36.22163-07:00","updated_at":"2025-10-24T22:26:36.22163-07:00","external_ref":"github:146"}
{"id":"bd-133","title":"Fix nil pointer crash in bd reopen command","description":"bd reopen crashes with SIGSEGV at reopen.go:30. Nil pointer dereference when trying to reopen an issue.","notes":"Fixed by adding daemon RPC support to reopen command. Pattern: check daemonClient != nil first, use RPC UpdateArgs with Status=open, fall back to direct store if daemon unavailable.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-10-25T10:30:31.602438-07:00","updated_at":"2025-10-25T10:33:39.016623-07:00","closed_at":"2025-10-25T10:33:39.016623-07:00"}
{"id":"bd-14","title":"Auto-flush writes test pollution and session work to git-tracked issues.jsonl","description":"Auto-flush exports ALL issues from DB to issues.jsonl every 5 seconds, including:\n- Test issues (bd-4053 through bd-4059 were version test junk)\n- Issues created during debugging sessions\n- Test pollution from stress tests\n- Temporary diagnostic issues\n\nThis pollutes the git-tracked issues.jsonl with garbage that shouldn't be committed.\n\nExample from today:\n- Git had 49 clean issues\n- Our DB grew to 100+ with test junk and session work\n- Auto-flush wrote all 100+ to issues.jsonl\n- Git status showed modified issues.jsonl with 50+ unwanted issues\n\nImpact:\n- Pollutes git history with test/debug garbage\n- Makes code review difficult (noise in diffs)\n- Can't distinguish real work from session artifacts\n- Other team members pull polluted issues\n\nSolutions to consider:\n1. Disable auto-flush by default (require explicit --enable-auto-flush)\n2. Add .beadsignore to exclude issue ID patterns\n3. Make auto-flush only export 'real' issues (exclude test-*)\n4. Require manual 'bd sync' for git commit\n5. Auto-flush to separate file (.beads/session.jsonl vs issues.jsonl)\n\nRelated: bd-117 (test pollution), isolation_test.go (test DB separation)","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-10-22T00:05:10.788996-07:00","updated_at":"2025-10-24T13:51:54.437366-07:00","closed_at":"2025-10-22T01:05:59.459797-07:00"}
{"id":"bd-15","title":"Make merge command idempotent for safe retry after partial failures","description":"The merge command currently performs 3 operations without an outer transaction:\n1. Migrate dependencies from source → target\n2. Update text references across all issues\n3. Close source issues\n\nIf merge fails mid-operation (network issue, daemon crash, etc.), a retry will fail or produce incorrect results because some operations already succeeded.\n\n**Goal:** Make merge idempotent so retrying after partial failure is safe and completes the remaining work.\n\n**Idempotency checks needed:**\n- Skip dependency migration if target already has the dependency\n- Skip text reference updates if already updated\n- Skip closing source issues if already closed\n- Report which operations were skipped vs performed\n\n**Example output:**\n```\n✓ Merged 2 issue(s) into bd-63\n - Dependencies: 3 migrated, 2 already existed\n - Text references: 5 updated, 0 already correct\n - Source issues: 1 closed, 1 already closed\n```\n\n**Related:** bd-115 originally requested transaction support, but idempotency is a better solution for this use case since individual operations are already atomic.","design":"Current merge code already has some idempotency:\n- Dependency migration checks `alreadyExists` before adding (line ~145-151 in merge.go)\n- Text reference updates are naturally idempotent (replacing bd-X with bd-Y twice has same result)\n\nMissing idempotency:\n- CloseIssue fails if source already closed\n- Error messages don't distinguish \"already done\" from \"real failure\"\n\nImplementation:\n1. Check source issue status before closing - skip if already closed\n2. Track which operations succeeded/skipped\n3. Return detailed results for user visibility\n4. Consider adding --dry-run output showing what would be done vs skipped","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-10-22T00:47:43.165434-07:00","updated_at":"2025-10-24T13:51:54.437619-07:00","closed_at":"2025-10-22T11:56:36.526276-07:00"}
{"id":"bd-16","title":"Global daemon should warn/reject --auto-commit and --auto-push","description":"When user runs 'bd daemon --global --auto-commit', it's unclear which repo the daemon will commit to (especially after fixing bd-62 where global daemon won't open a DB).\n\nOptions:\n1. Warn and ignore the flags in global mode\n2. Error out with clear message\n\nLine 87-91 already checks autoPush, but should skip check entirely for global mode. Add user-friendly messaging about flag incompatibility.","status":"closed","priority":3,"issue_type":"feature","created_at":"2025-10-22T00:47:43.165645-07:00","updated_at":"2025-10-24T13:51:54.437812-07:00","closed_at":"2025-10-17T23:04:30.223432-07:00"}
@@ -81,7 +82,7 @@
{"id":"bd-52","title":"Clean up linter errors (914 total issues)","description":"The codebase has 914 linter issues reported by golangci-lint. While many are documented as baseline in LINTING.md, we should clean these up systematically to improve code quality and maintainability.","design":"Break down by linter category, prioritizing high-impact issues:\n1. dupl (7) - Code duplication\n2. goconst (12) - Repeated strings\n3. gocyclo (11) - High complexity functions\n4. revive (78) - Style issues\n5. gosec (102) - Security warnings\n6. errcheck (683) - Unchecked errors (many in tests)","acceptance_criteria":"All linter categories reduced to acceptable levels, with remaining baseline documented in LINTING.md","notes":"Reduced from 56 to 41 issues locally, then to 0 issues.\n\n**Fixed in commits:**\n- c2c7eda: Fixed 15 actual errors (dupl, gosec, revive, staticcheck, unparam)\n- 963181d: Configured exclusions to get to 0 issues locally\n\n**Current status:**\n- ✅ Local: golangci-lint reports 0 issues\n- ❌ CI: Still failing (see bd-65)\n\n**Problem:**\nConfig v2 format or golangci-lint-action@v8 compatibility issue causing CI to fail despite local success.\n\n**Next:** Debug bd-65 to fix CI/local discrepancy","status":"in_progress","priority":2,"issue_type":"epic","created_at":"2025-10-24T01:01:12.997982-07:00","updated_at":"2025-10-24T13:51:54.439577-07:00"}
{"id":"bd-53","title":"Fix code duplication in label.go (dupl)","description":"Lines 72-120 duplicate lines 122-170 in cmd/bd/label.go. The add and remove commands have nearly identical structure.","design":"Extract common batch operation logic into a shared helper function that takes the operation type as a parameter.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-24T01:01:36.971666-07:00","updated_at":"2025-10-24T13:51:54.416434-07:00","closed_at":"2025-10-24T12:40:43.046348-07:00","dependencies":[{"issue_id":"bd-53","depends_on_id":"bd-52","type":"parent-child","created_at":"2025-10-24T13:17:40.325899-07:00","created_by":"renumber"}]}
{"id":"bd-54","title":"Convert repeated strings to constants (goconst)","description":"12 instances of repeated strings that should be constants: \"alice\", \"windows\", \"bd-114\", \"daemon\", \"import\", \"healthy\", \"unhealthy\", \"1.0.0\", \"custom-1\", \"custom-2\"","design":"Create package-level or test-level constants for frequently used test strings and command names.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-24T01:01:36.9778-07:00","updated_at":"2025-10-24T13:51:54.439751-07:00","dependencies":[{"issue_id":"bd-54","depends_on_id":"bd-52","type":"parent-child","created_at":"2025-10-24T13:17:40.326123-07:00","created_by":"renumber"}]}
{"id":"bd-55","title":"Refactor high complexity functions (gocyclo)","description":"11 functions exceed cyclomatic complexity threshold (\u003e30): runDaemonLoop (42), importIssuesCore (71), TestLabelCommands (67), issueDataChanged (39), etc.","design":"Break down complex functions into smaller, testable units. Extract validation, error handling, and business logic into separate functions.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-10-24T01:01:36.989066-07:00","updated_at":"2025-10-25T10:20:01.90564-07:00","closed_at":"2025-10-25T10:20:01.90564-07:00","dependencies":[{"issue_id":"bd-55","depends_on_id":"bd-52","type":"parent-child","created_at":"2025-10-24T13:17:40.323992-07:00","created_by":"renumber"}]}
{"id":"bd-55","title":"Refactor high complexity functions (gocyclo)","description":"11 functions exceed cyclomatic complexity threshold (\u003e30): runDaemonLoop (42), importIssuesCore (71), TestLabelCommands (67), issueDataChanged (39), etc.","design":"Break down complex functions into smaller, testable units. Extract validation, error handling, and business logic into separate functions.","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-24T01:01:36.989066-07:00","updated_at":"2025-10-25T10:33:30.169063-07:00","dependencies":[{"issue_id":"bd-55","depends_on_id":"bd-52","type":"parent-child","created_at":"2025-10-24T13:17:40.323992-07:00","created_by":"renumber"}]}
{"id":"bd-56","title":"Fix revive style issues (78 issues)","description":"Style violations: unused parameters (many cmd/args in cobra commands), missing exported comments, stuttering names (SQLiteStorage), indent-error-flow issues.","design":"Rename unused params to _, add godoc comments to exported types, fix stuttering names, simplify control flow.","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-24T01:01:36.99984-07:00","updated_at":"2025-10-24T13:51:54.417341-07:00","dependencies":[{"issue_id":"bd-56","depends_on_id":"bd-52","type":"parent-child","created_at":"2025-10-24T13:17:40.322412-07:00","created_by":"renumber"}]}
{"id":"bd-57","title":"Address gosec security warnings (102 issues)","description":"Security linter warnings: file permissions (0755 should be 0750), G304 file inclusion via variable, G204 subprocess launches. Many are false positives but should be reviewed.","design":"Review each gosec warning. Add exclusions for legitimate cases to .golangci.yml. Fix real security issues (overly permissive file modes).","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-24T01:01:37.0139-07:00","updated_at":"2025-10-24T13:51:54.417632-07:00","dependencies":[{"issue_id":"bd-57","depends_on_id":"bd-52","type":"parent-child","created_at":"2025-10-24T13:17:40.324202-07:00","created_by":"renumber"}]}
{"id":"bd-58","title":"Handle unchecked errors (errcheck - 683 issues)","description":"683 unchecked error returns, mostly in tests (Close, Rollback, RemoveAll). Many already excluded in config but still showing up.","design":"Review .golangci.yml exclude-rules. Most defer Close/Rollback errors in tests can be ignored. Add systematic exclusions or explicit _ = assignments where appropriate.","status":"open","priority":3,"issue_type":"task","created_at":"2025-10-24T01:01:37.018404-07:00","updated_at":"2025-10-24T13:51:54.41793-07:00","dependencies":[{"issue_id":"bd-58","depends_on_id":"bd-52","type":"parent-child","created_at":"2025-10-24T13:17:40.324423-07:00","created_by":"renumber"}]}

View File

@@ -2,11 +2,13 @@ package main
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/steveyegge/beads/internal/rpc"
"github.com/steveyegge/beads/internal/types"
)
@@ -22,6 +24,54 @@ This is more explicit than 'bd update --status open' and emits a Reopened event.
ctx := context.Background()
reopenedIssues := []*types.Issue{}
// If daemon is running, use RPC
if daemonClient != nil {
for _, id := range args {
openStatus := string(types.StatusOpen)
updateArgs := &rpc.UpdateArgs{
ID: id,
Status: &openStatus,
}
resp, err := daemonClient.Update(updateArgs)
if err != nil {
fmt.Fprintf(os.Stderr, "Error reopening %s: %v\n", id, err)
continue
}
// TODO: Add reason as a comment once RPC supports AddComment
if reason != "" {
fmt.Fprintf(os.Stderr, "Warning: reason not supported in daemon mode yet\n")
}
if jsonOutput {
var issue types.Issue
if err := json.Unmarshal(resp.Data, &issue); err == nil {
reopenedIssues = append(reopenedIssues, &issue)
}
} else {
blue := color.New(color.FgBlue).SprintFunc()
reasonMsg := ""
if reason != "" {
reasonMsg = ": " + reason
}
fmt.Printf("%s Reopened %s%s\n", blue("↻"), id, reasonMsg)
}
}
if jsonOutput && len(reopenedIssues) > 0 {
outputJSON(reopenedIssues)
}
return
}
// Fall back to direct storage access
if store == nil {
fmt.Fprintln(os.Stderr, "Error: database not initialized")
os.Exit(1)
}
for _, id := range args {
// UpdateIssue automatically clears closed_at when status changes from closed
updates := map[string]interface{}{