bd create: support --description=- for stdin input

Allows descriptions with apostrophes and other shell-problematic
characters by reading from stdin. Works with both --description=-
and --body=- (the GitHub CLI-style alias).

Example: echo "It's working" | bd create --title "Test" --description=-

Also fixes pre-existing duplicate pinned column/variable declarations.

Fixes beads-iwi

🤖 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-19 01:47:03 -08:00
parent 22f66879aa
commit 02513f1c31
3 changed files with 23 additions and 16 deletions

View File

@@ -24,6 +24,8 @@ func registerCommonIssueFlags(cmd *cobra.Command) {
// getDescriptionFlag retrieves the description value, checking --body-file, --description-file,
// --description, and --body (in that order of precedence).
// Supports reading from stdin via --description=- or --body=- (useful when description
// contains apostrophes or other characters that are hard to escape in shell).
// Returns the value and whether any flag was explicitly changed.
func getDescriptionFlag(cmd *cobra.Command) (string, bool) {
bodyFileChanged := cmd.Flags().Changed("body-file")
@@ -64,10 +66,29 @@ func getDescriptionFlag(cmd *cobra.Command) (string, bool) {
return content, true
}
// Check if description or body is "-" (read from stdin)
// This provides a convenient shorthand: --description=- instead of --body-file=-
desc, _ := cmd.Flags().GetString("description")
body, _ := cmd.Flags().GetString("body")
if desc == "-" || body == "-" {
// Error if both are set to different values
if descChanged && bodyChanged && desc != body {
fmt.Fprintf(os.Stderr, "Error: cannot specify both --description and --body with different values\n")
fmt.Fprintf(os.Stderr, " --description: %q\n", desc)
fmt.Fprintf(os.Stderr, " --body: %q\n", body)
os.Exit(1)
}
content, err := readBodyFile("-")
if err != nil {
fmt.Fprintf(os.Stderr, "Error reading from stdin: %v\n", err)
os.Exit(1)
}
return content, true
}
// Error if both description and body are specified with different values
if descChanged && bodyChanged {
desc, _ := cmd.Flags().GetString("description")
body, _ := cmd.Flags().GetString("body")
if desc != body {
fmt.Fprintf(os.Stderr, "Error: cannot specify both --description and --body with different values\n")
fmt.Fprintf(os.Stderr, " --description: %q\n", desc)
@@ -78,11 +99,9 @@ func getDescriptionFlag(cmd *cobra.Command) (string, bool) {
// Return whichever was set (or description's value if neither)
if bodyChanged {
body, _ := cmd.Flags().GetString("body")
return body, true
}
desc, _ := cmd.Flags().GetString("description")
return desc, descChanged
}

View File

@@ -36,11 +36,6 @@ func insertIssue(ctx context.Context, conn *sql.Conn, issue *types.Issue) error
pinned = 1
}
pinned := 0
if issue.Pinned {
pinned = 1
}
_, err := conn.ExecContext(ctx, `
INSERT OR IGNORE INTO issues (
id, content_hash, title, description, design, acceptance_criteria, notes,
@@ -100,11 +95,6 @@ func insertIssues(ctx context.Context, conn *sql.Conn, issues []*types.Issue) er
pinned = 1
}
pinned := 0
if issue.Pinned {
pinned = 1
}
_, err = stmt.ExecContext(ctx,
issue.ID, issue.ContentHash, issue.Title, issue.Description, issue.Design,
issue.AcceptanceCriteria, issue.Notes, issue.Status,

View File

@@ -34,8 +34,6 @@ CREATE TABLE IF NOT EXISTS issues (
pinned INTEGER DEFAULT 0,
-- NOTE: replies_to, relates_to, duplicate_of, superseded_by removed per Decision 004
-- These relationships are now stored in the dependencies table
-- Workflow fields
pinned INTEGER DEFAULT 0,
CHECK ((status = 'closed') = (closed_at IS NOT NULL))
);