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:
@@ -89,11 +89,11 @@ type CreateArgs struct {
|
||||
WaitsFor string `json:"waits_for,omitempty"` // Spawner issue ID to wait for
|
||||
WaitsForGate string `json:"waits_for_gate,omitempty"` // Gate type: all-children or any-children
|
||||
// Messaging fields (bd-kwro)
|
||||
Sender string `json:"sender,omitempty"` // Who sent this (for messages)
|
||||
Wisp bool `json:"wisp,omitempty"` // Wisp = ephemeral vapor from the Steam Engine; bulk-deleted when closed
|
||||
Sender string `json:"sender,omitempty"` // Who sent this (for messages)
|
||||
Ephemeral bool `json:"ephemeral,omitempty"` // If true, not exported to JSONL; bulk-deleted when closed
|
||||
RepliesTo string `json:"replies_to,omitempty"` // Issue ID for conversation threading
|
||||
// ID generation (bd-hobo)
|
||||
IDPrefix string `json:"id_prefix,omitempty"` // Override prefix for ID generation (mol, wisp, etc.)
|
||||
IDPrefix string `json:"id_prefix,omitempty"` // Override prefix for ID generation (mol, eph, etc.)
|
||||
CreatedBy string `json:"created_by,omitempty"` // Who created the issue
|
||||
}
|
||||
|
||||
@@ -115,8 +115,8 @@ type UpdateArgs struct {
|
||||
RemoveLabels []string `json:"remove_labels,omitempty"`
|
||||
SetLabels []string `json:"set_labels,omitempty"`
|
||||
// Messaging fields (bd-kwro)
|
||||
Sender *string `json:"sender,omitempty"` // Who sent this (for messages)
|
||||
Wisp *bool `json:"wisp,omitempty"` // Wisp = ephemeral vapor from the Steam Engine; bulk-deleted when closed
|
||||
Sender *string `json:"sender,omitempty"` // Who sent this (for messages)
|
||||
Ephemeral *bool `json:"ephemeral,omitempty"` // If true, not exported to JSONL; bulk-deleted when closed
|
||||
RepliesTo *string `json:"replies_to,omitempty"` // Issue ID for conversation threading
|
||||
// Graph link fields (bd-fu83)
|
||||
RelatesTo *string `json:"relates_to,omitempty"` // JSON array of related issue IDs
|
||||
@@ -193,8 +193,8 @@ type ListArgs struct {
|
||||
// Parent filtering (bd-yqhh)
|
||||
ParentID string `json:"parent_id,omitempty"`
|
||||
|
||||
// Wisp filtering (bd-bkul)
|
||||
Wisp *bool `json:"wisp,omitempty"`
|
||||
// Ephemeral filtering (bd-bkul)
|
||||
Ephemeral *bool `json:"ephemeral,omitempty"`
|
||||
}
|
||||
|
||||
// CountArgs represents arguments for the count operation
|
||||
|
||||
@@ -81,8 +81,8 @@ func updatesFromArgs(a UpdateArgs) map[string]interface{} {
|
||||
if a.Sender != nil {
|
||||
u["sender"] = *a.Sender
|
||||
}
|
||||
if a.Wisp != nil {
|
||||
u["wisp"] = *a.Wisp
|
||||
if a.Ephemeral != nil {
|
||||
u["ephemeral"] = *a.Ephemeral
|
||||
}
|
||||
if a.RepliesTo != nil {
|
||||
u["replies_to"] = *a.RepliesTo
|
||||
@@ -176,8 +176,8 @@ func (s *Server) handleCreate(req *Request) Response {
|
||||
EstimatedMinutes: createArgs.EstimatedMinutes,
|
||||
Status: types.StatusOpen,
|
||||
// Messaging fields (bd-kwro)
|
||||
Sender: createArgs.Sender,
|
||||
Wisp: createArgs.Wisp,
|
||||
Sender: createArgs.Sender,
|
||||
Ephemeral: createArgs.Ephemeral,
|
||||
// NOTE: RepliesTo now handled via replies-to dependency (Decision 004)
|
||||
// ID generation (bd-hobo)
|
||||
IDPrefix: createArgs.IDPrefix,
|
||||
@@ -844,8 +844,8 @@ func (s *Server) handleList(req *Request) Response {
|
||||
filter.ParentID = &listArgs.ParentID
|
||||
}
|
||||
|
||||
// Wisp filtering (bd-bkul)
|
||||
filter.Wisp = listArgs.Wisp
|
||||
// Ephemeral filtering (bd-bkul)
|
||||
filter.Ephemeral = listArgs.Ephemeral
|
||||
|
||||
// Guard against excessive ID lists to avoid SQLite parameter limits
|
||||
const maxIDs = 1000
|
||||
@@ -1475,7 +1475,7 @@ func (s *Server) handleGateCreate(req *Request) Response {
|
||||
Status: types.StatusOpen,
|
||||
Priority: 1, // Gates are typically high priority
|
||||
Assignee: "deacon/",
|
||||
Wisp: true, // Gates are wisps (ephemeral)
|
||||
Ephemeral: true, // Gates are wisps (ephemeral)
|
||||
AwaitType: args.AwaitType,
|
||||
AwaitID: args.AwaitID,
|
||||
Timeout: args.Timeout,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -44,8 +44,8 @@ type Issue struct {
|
||||
OriginalType string `json:"original_type,omitempty"` // Issue type before deletion (for tombstones)
|
||||
|
||||
// Messaging fields (bd-kwro): inter-agent communication support
|
||||
Sender string `json:"sender,omitempty"` // Who sent this (for messages)
|
||||
Wisp bool `json:"wisp,omitempty"` // Wisp = ephemeral vapor from the Steam Engine; bulk-deleted when closed
|
||||
Sender string `json:"sender,omitempty"` // Who sent this (for messages)
|
||||
Ephemeral bool `json:"ephemeral,omitempty"` // If true, not exported to JSONL; bulk-deleted when closed
|
||||
// NOTE: RepliesTo, RelatesTo, DuplicateOf, SupersededBy moved to dependencies table
|
||||
// per Decision 004 (Edge Schema Consolidation). Use dependency API instead.
|
||||
|
||||
@@ -598,8 +598,8 @@ type IssueFilter struct {
|
||||
// Tombstone filtering (bd-1bu)
|
||||
IncludeTombstones bool // If false (default), exclude tombstones from results
|
||||
|
||||
// Wisp filtering (bd-kwro.9)
|
||||
Wisp *bool // Filter by wisp flag (nil = any, true = only wisps, false = only non-wisps)
|
||||
// Ephemeral filtering (bd-kwro.9)
|
||||
Ephemeral *bool // Filter by ephemeral flag (nil = any, true = only ephemeral, false = only persistent)
|
||||
|
||||
// Pinned filtering (bd-7h5)
|
||||
Pinned *bool // Filter by pinned flag (nil = any, true = only pinned, false = only non-pinned)
|
||||
|
||||
Reference in New Issue
Block a user