feat: Rename 'wisp' to 'ephemeral' in beads API (bd-o18s)

BREAKING CHANGE: API field and CLI command renamed

- types.Issue.Wisp → types.Issue.Ephemeral
- JSON field: "wisp" → "ephemeral"
- CLI: bd wisp → bd ephemeral
- Flags: --wisp → --ephemeral
- ID prefix: wisp → eph

The SQLite column already uses 'ephemeral' so no schema migration needed.

🤖 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-26 21:07:37 -08:00
parent 89be2a9d7f
commit ea8ae11002
34 changed files with 277 additions and 276 deletions

View File

@@ -885,7 +885,7 @@ func (s *SQLiteStorage) scanIssues(ctx context.Context, rows *sql.Rows) ([]*type
issue.Sender = sender.String
}
if wisp.Valid && wisp.Int64 != 0 {
issue.Wisp = true
issue.Ephemeral = true
}
// Pinned field (bd-7h5)
if pinned.Valid && pinned.Int64 != 0 {
@@ -1006,7 +1006,7 @@ func (s *SQLiteStorage) scanIssuesWithDependencyType(ctx context.Context, rows *
issue.Sender = sender.String
}
if wisp.Valid && wisp.Int64 != 0 {
issue.Wisp = true
issue.Ephemeral = true
}
// Pinned field (bd-7h5)
if pinned.Valid && pinned.Int64 != 0 {

View File

@@ -295,7 +295,7 @@ func TestRepliesTo(t *testing.T) {
IssueType: types.TypeMessage,
Sender: "alice",
Assignee: "bob",
Wisp: true,
Ephemeral: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
@@ -307,7 +307,7 @@ func TestRepliesTo(t *testing.T) {
IssueType: types.TypeMessage,
Sender: "bob",
Assignee: "alice",
Wisp: true,
Ephemeral: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
@@ -363,7 +363,7 @@ func TestRepliesTo_Chain(t *testing.T) {
IssueType: types.TypeMessage,
Sender: "user",
Assignee: "inbox",
Wisp: true,
Ephemeral: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
@@ -415,7 +415,7 @@ func TestWispField(t *testing.T) {
Status: types.StatusOpen,
Priority: 2,
IssueType: types.TypeMessage,
Wisp: true,
Ephemeral: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
@@ -426,7 +426,7 @@ func TestWispField(t *testing.T) {
Status: types.StatusOpen,
Priority: 2,
IssueType: types.TypeTask,
Wisp: false,
Ephemeral: false,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
@@ -443,7 +443,7 @@ func TestWispField(t *testing.T) {
if err != nil {
t.Fatalf("GetIssue failed: %v", err)
}
if !savedWisp.Wisp {
if !savedWisp.Ephemeral {
t.Error("Wisp issue should have Wisp=true")
}
@@ -451,7 +451,7 @@ func TestWispField(t *testing.T) {
if err != nil {
t.Fatalf("GetIssue failed: %v", err)
}
if savedPermanent.Wisp {
if savedPermanent.Ephemeral {
t.Error("Permanent issue should have Wisp=false")
}
}
@@ -468,7 +468,7 @@ func TestWispFilter(t *testing.T) {
Status: types.StatusClosed, // Closed for cleanup test
Priority: 2,
IssueType: types.TypeMessage,
Wisp: true,
Ephemeral: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
@@ -483,7 +483,7 @@ func TestWispFilter(t *testing.T) {
Status: types.StatusClosed,
Priority: 2,
IssueType: types.TypeTask,
Wisp: false,
Ephemeral: false,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
@@ -497,7 +497,7 @@ func TestWispFilter(t *testing.T) {
closedStatus := types.StatusClosed
wispFilter := types.IssueFilter{
Status: &closedStatus,
Wisp: &wispTrue,
Ephemeral: &wispTrue,
}
wispIssues, err := store.SearchIssues(ctx, "", wispFilter)
@@ -512,7 +512,7 @@ func TestWispFilter(t *testing.T) {
wispFalse := false
nonWispFilter := types.IssueFilter{
Status: &closedStatus,
Wisp: &wispFalse,
Ephemeral: &wispFalse,
}
permanentIssues, err := store.SearchIssues(ctx, "", nonWispFilter)

View File

@@ -28,7 +28,7 @@ func insertIssue(ctx context.Context, conn *sql.Conn, issue *types.Issue) error
}
wisp := 0
if issue.Wisp {
if issue.Ephemeral {
wisp = 1
}
pinned := 0
@@ -94,7 +94,7 @@ func insertIssues(ctx context.Context, conn *sql.Conn, issues []*types.Issue) er
}
wisp := 0
if issue.Wisp {
if issue.Ephemeral {
wisp = 1
}
pinned := 0

View File

@@ -282,7 +282,7 @@ func (s *SQLiteStorage) upsertIssueInTx(ctx context.Context, tx *sql.Tx, issue *
err := tx.QueryRowContext(ctx, `SELECT id FROM issues WHERE id = ?`, issue.ID).Scan(&existingID)
wisp := 0
if issue.Wisp {
if issue.Ephemeral {
wisp = 1
}
pinned := 0

View File

@@ -54,7 +54,7 @@ func (s *SQLiteStorage) ExportToMultiRepo(ctx context.Context) (map[string]int,
// Wisps exist only in SQLite and are shared via .beads/redirect, not JSONL.
filtered := make([]*types.Issue, 0, len(allIssues))
for _, issue := range allIssues {
if !issue.Wisp {
if !issue.Ephemeral {
filtered = append(filtered, issue)
}
}

View File

@@ -349,7 +349,7 @@ func (s *SQLiteStorage) GetIssue(ctx context.Context, id string) (*types.Issue,
issue.Sender = sender.String
}
if wisp.Valid && wisp.Int64 != 0 {
issue.Wisp = true
issue.Ephemeral = true
}
// Pinned field (bd-7h5)
if pinned.Valid && pinned.Int64 != 0 {
@@ -562,7 +562,7 @@ func (s *SQLiteStorage) GetIssueByExternalRef(ctx context.Context, externalRef s
issue.Sender = sender.String
}
if wisp.Valid && wisp.Int64 != 0 {
issue.Wisp = true
issue.Ephemeral = true
}
// Pinned field (bd-7h5)
if pinned.Valid && pinned.Int64 != 0 {
@@ -1652,8 +1652,8 @@ func (s *SQLiteStorage) SearchIssues(ctx context.Context, query string, filter t
}
// Wisp filtering (bd-kwro.9)
if filter.Wisp != nil {
if *filter.Wisp {
if filter.Ephemeral != nil {
if *filter.Ephemeral {
whereClauses = append(whereClauses, "ephemeral = 1") // SQL column is still 'ephemeral'
} else {
whereClauses = append(whereClauses, "(ephemeral = 0 OR ephemeral IS NULL)")

View File

@@ -400,7 +400,7 @@ func (s *SQLiteStorage) GetStaleIssues(ctx context.Context, filter types.StaleFi
issue.Sender = sender.String
}
if ephemeral.Valid && ephemeral.Int64 != 0 {
issue.Wisp = true
issue.Ephemeral = true
}
// Pinned field (bd-7h5)
if pinned.Valid && pinned.Int64 != 0 {

View File

@@ -1089,8 +1089,8 @@ func (t *sqliteTxStorage) SearchIssues(ctx context.Context, query string, filter
}
// Wisp filtering (bd-kwro.9)
if filter.Wisp != nil {
if *filter.Wisp {
if filter.Ephemeral != nil {
if *filter.Ephemeral {
whereClauses = append(whereClauses, "ephemeral = 1") // SQL column is still 'ephemeral'
} else {
whereClauses = append(whereClauses, "(ephemeral = 0 OR ephemeral IS NULL)")
@@ -1244,7 +1244,7 @@ func scanIssueRow(row scanner) (*types.Issue, error) {
issue.Sender = sender.String
}
if wisp.Valid && wisp.Int64 != 0 {
issue.Wisp = true
issue.Ephemeral = true
}
// Pinned field (bd-7h5)
if pinned.Valid && pinned.Int64 != 0 {