@@ -1498,6 +1498,84 @@ func TestTaskEventDetectsPermissionPrompt(t *testing.T) {
14981498 }
14991499}
15001500
1501+ // TestTaskSyncClearsNeedsInputWhenNoLongerBlocked verifies that the task sync
1502+ // loop clears tasksNeedingInput when a task is no longer blocked (e.g., the user
1503+ // provided input from the detail view tmux pane).
1504+ func TestTaskSyncClearsNeedsInputWhenNoLongerBlocked (t * testing.T ) {
1505+ database , err := db .Open (":memory:" )
1506+ if err != nil {
1507+ t .Fatalf ("Failed to create test database: %v" , err )
1508+ }
1509+ defer database .Close ()
1510+
1511+ task := & db.Task {Title : "Test task" , Status : db .StatusProcessing }
1512+ if err := database .CreateTask (task ); err != nil {
1513+ t .Fatalf ("Failed to create task: %v" , err )
1514+ }
1515+
1516+ m := & AppModel {
1517+ width : 100 ,
1518+ height : 50 ,
1519+ currentView : ViewDashboard ,
1520+ keys : DefaultKeyMap (),
1521+ tasks : []* db.Task {task },
1522+ tasksNeedingInput : map [int64 ]bool {task .ID : true },
1523+ executorPrompts : map [int64 ]string {task .ID : "What should I do?" },
1524+ kanban : NewKanbanBoard (100 , 50 ),
1525+ prevStatuses : map [int64 ]string {task .ID : db .StatusBlocked },
1526+ db : database ,
1527+ notification : "⚠ Task #1 needs input" ,
1528+ notifyTaskID : task .ID ,
1529+ }
1530+ m .kanban .SetTasks (m .tasks )
1531+
1532+ // Simulate tasksLoadedMsg with the task now in processing status
1533+ msg := tasksLoadedMsg {tasks : []* db.Task {task }}
1534+ m .Update (msg )
1535+
1536+ if m .tasksNeedingInput [task .ID ] {
1537+ t .Error ("tasksNeedingInput should be cleared when task is no longer blocked" )
1538+ }
1539+ if _ , exists := m .executorPrompts [task .ID ]; exists {
1540+ t .Error ("executorPrompts should be cleared when task is no longer blocked" )
1541+ }
1542+ }
1543+
1544+ // TestRetrySubmitClearsKanbanNotification verifies that submitting the retry
1545+ // form clears both the tasksNeedingInput flag and the notification banner.
1546+ func TestRetrySubmitClearsKanbanNotification (t * testing.T ) {
1547+ task := & db.Task {ID : 42 , Title : "Test task" , Status : db .StatusBlocked }
1548+
1549+ m := & AppModel {
1550+ width : 100 ,
1551+ height : 50 ,
1552+ currentView : ViewRetry ,
1553+ keys : DefaultKeyMap (),
1554+ tasksNeedingInput : map [int64 ]bool {42 : true },
1555+ executorPrompts : map [int64 ]string {42 : "What should I do?" },
1556+ kanban : NewKanbanBoard (100 , 50 ),
1557+ prevStatuses : make (map [int64 ]string ),
1558+ notification : "⚠ Task #42 needs input: Test task (g to jump)" ,
1559+ notifyTaskID : 42 ,
1560+ retryView : & RetryModel {task : task , submitted : true },
1561+ }
1562+
1563+ m .Update (nil )
1564+
1565+ if m .tasksNeedingInput [42 ] {
1566+ t .Error ("tasksNeedingInput[42] should be cleared after retry submit" )
1567+ }
1568+ if _ , exists := m .executorPrompts [42 ]; exists {
1569+ t .Error ("executorPrompts[42] should be cleared after retry submit" )
1570+ }
1571+ if m .notification != "" {
1572+ t .Errorf ("notification should be cleared after retry submit, got %q" , m .notification )
1573+ }
1574+ if m .notifyTaskID != 0 {
1575+ t .Error ("notifyTaskID should be cleared after retry submit" )
1576+ }
1577+ }
1578+
15011579// TestFilterChipDeletion tests the chip deletion feature in filter input.
15021580func TestFilterChipDeletion (t * testing.T ) {
15031581 tests := []struct {
0 commit comments