pacsea 0.8.2

A fast, friendly TUI for browsing and installing Arch and AUR packages with built-in news and security scanning
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
use std::sync::Arc;
use std::sync::atomic::AtomicBool;

use crossterm::event::Event as CEvent;
use tokio::sync::mpsc;

use crate::app::runtime::workers::UpdateCheckPayload;
use crate::app::runtime::workers::aur_vote::{
    AurVoteRequest, AurVoteResponse, AurVoteStateRequest, AurVoteStateResponse,
};
use crate::state::types::NewsFeedPayload;
use crate::state::{
    ArchStatusColor, PackageDetails, PackageItem, PkgbuildCheckRequest, PkgbuildCheckResponse,
    QueryInput, SearchResults,
};

/// What: Channel definitions for runtime communication.
///
/// Details:
/// - Contains all channel senders and receivers used for communication
///   between the main event loop and background workers
#[allow(dead_code)]
pub struct Channels {
    /// Sender for terminal events (keyboard/mouse) from the event reading thread.
    pub event_tx: mpsc::UnboundedSender<CEvent>,
    /// Receiver for terminal events in the main event loop.
    pub event_rx: mpsc::UnboundedReceiver<CEvent>,
    /// Atomic flag to signal cancellation of the event reading thread.
    pub event_thread_cancelled: Arc<AtomicBool>,
    /// Sender for search results from the search worker.
    pub search_result_tx: mpsc::UnboundedSender<SearchResults>,
    /// Receiver for search results in the main event loop.
    pub results_rx: mpsc::UnboundedReceiver<SearchResults>,
    /// Sender for package details requests to the details worker.
    pub details_req_tx: mpsc::UnboundedSender<PackageItem>,
    /// Sender for package details responses from the details worker.
    pub details_res_tx: mpsc::UnboundedSender<PackageDetails>,
    /// Receiver for package details responses in the main event loop.
    pub details_res_rx: mpsc::UnboundedReceiver<PackageDetails>,
    /// Sender for tick events to trigger periodic UI updates.
    pub tick_tx: mpsc::UnboundedSender<()>,
    /// Receiver for tick events in the main event loop.
    pub tick_rx: mpsc::UnboundedReceiver<()>,
    /// Sender for network error messages from background workers.
    pub net_err_tx: mpsc::UnboundedSender<String>,
    /// Receiver for network error messages in the main event loop.
    pub net_err_rx: mpsc::UnboundedReceiver<String>,
    /// Sender for preview requests (package details for Recent pane).
    pub preview_tx: mpsc::UnboundedSender<PackageItem>,
    /// Receiver for preview responses in the main event loop.
    pub preview_rx: mpsc::UnboundedReceiver<PackageItem>,
    /// Sender for adding packages to the install list.
    pub add_tx: mpsc::UnboundedSender<PackageItem>,
    /// Receiver for add requests in the install list handler.
    pub add_rx: mpsc::UnboundedReceiver<PackageItem>,
    /// Sender for index update notifications.
    pub index_notify_tx: mpsc::UnboundedSender<()>,
    /// Receiver for index update notifications in the main event loop.
    pub index_notify_rx: mpsc::UnboundedReceiver<()>,
    /// Sender for PKGBUILD content requests.
    pub pkgb_req_tx: mpsc::UnboundedSender<PackageItem>,
    /// Sender for PKGBUILD content responses (package name, PKGBUILD content).
    pub pkgb_res_tx: mpsc::UnboundedSender<(String, String)>,
    /// Receiver for PKGBUILD content responses in the main event loop.
    pub pkgb_res_rx: mpsc::UnboundedReceiver<(String, String)>,
    /// Sender for PKGBUILD static check requests.
    pub pkgb_check_req_tx: mpsc::UnboundedSender<PkgbuildCheckRequest>,
    /// Receiver for PKGBUILD static check responses.
    pub pkgb_check_res_rx: mpsc::UnboundedReceiver<PkgbuildCheckResponse>,
    /// Sender for AUR comments requests (package name).
    pub comments_req_tx: mpsc::UnboundedSender<String>,
    /// Sender for AUR comments responses (package name, comments or error).
    pub comments_res_tx:
        mpsc::UnboundedSender<(String, Result<Vec<crate::state::types::AurComment>, String>)>,
    /// Receiver for AUR comments responses in the main event loop.
    pub comments_res_rx:
        mpsc::UnboundedReceiver<(String, Result<Vec<crate::state::types::AurComment>, String>)>,
    /// Sender for Arch Linux status updates (status text, color).
    pub status_tx: mpsc::UnboundedSender<(String, ArchStatusColor)>,
    /// Receiver for Arch Linux status updates in the main event loop.
    pub status_rx: mpsc::UnboundedReceiver<(String, ArchStatusColor)>,
    /// Sender for startup news popup items.
    pub news_tx: mpsc::UnboundedSender<Vec<crate::state::types::NewsFeedItem>>,
    /// Receiver for startup news popup items in the main event loop.
    pub news_rx: mpsc::UnboundedReceiver<Vec<crate::state::types::NewsFeedItem>>,
    /// Sender for news feed items plus last-seen state.
    pub news_feed_tx: mpsc::UnboundedSender<NewsFeedPayload>,
    /// Receiver for news feed payloads in the main event loop.
    pub news_feed_rx: mpsc::UnboundedReceiver<NewsFeedPayload>,
    /// Sender for incremental news items (background continuation).
    pub news_incremental_tx: mpsc::UnboundedSender<crate::state::types::NewsFeedItem>,
    /// Receiver for incremental news items in the main event loop.
    pub news_incremental_rx: mpsc::UnboundedReceiver<crate::state::types::NewsFeedItem>,
    /// Request channel for fetching news article content (URL).
    pub news_content_req_tx: mpsc::UnboundedSender<String>,
    /// Response channel for news article content (URL, content).
    pub news_content_res_rx: mpsc::UnboundedReceiver<(String, String)>,
    /// Sender for system updates information (payload includes count, names, authoritative flag).
    pub updates_tx: mpsc::UnboundedSender<UpdateCheckPayload>,
    /// Receiver for system updates information in the main event loop.
    pub updates_rx: mpsc::UnboundedReceiver<UpdateCheckPayload>,
    /// Sender for remote announcements.
    pub announcement_tx: mpsc::UnboundedSender<crate::announcements::RemoteAnnouncement>,
    /// Receiver for remote announcements in the main event loop.
    pub announcement_rx: mpsc::UnboundedReceiver<crate::announcements::RemoteAnnouncement>,
    /// Sender for dependency resolution requests (packages, action).
    pub deps_req_tx:
        mpsc::UnboundedSender<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Sender for dependency resolution responses.
    pub deps_res_tx: mpsc::UnboundedSender<Vec<crate::state::modal::DependencyInfo>>,
    /// Receiver for dependency resolution responses in the main event loop.
    pub deps_res_rx: mpsc::UnboundedReceiver<Vec<crate::state::modal::DependencyInfo>>,
    /// Sender for file analysis requests (packages, action).
    pub files_req_tx:
        mpsc::UnboundedSender<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Sender for file analysis responses.
    pub files_res_tx: mpsc::UnboundedSender<Vec<crate::state::modal::PackageFileInfo>>,
    /// Receiver for file analysis responses in the main event loop.
    pub files_res_rx: mpsc::UnboundedReceiver<Vec<crate::state::modal::PackageFileInfo>>,
    /// Sender for service impact analysis requests (packages, action).
    pub services_req_tx:
        mpsc::UnboundedSender<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Sender for service impact analysis responses.
    pub services_res_tx: mpsc::UnboundedSender<Vec<crate::state::modal::ServiceImpact>>,
    /// Receiver for service impact analysis responses in the main event loop.
    pub services_res_rx: mpsc::UnboundedReceiver<Vec<crate::state::modal::ServiceImpact>>,
    /// Sender for sandbox analysis requests (packages).
    pub sandbox_req_tx: mpsc::UnboundedSender<Vec<PackageItem>>,
    /// Sender for sandbox analysis responses.
    pub sandbox_res_tx: mpsc::UnboundedSender<Vec<crate::logic::sandbox::SandboxInfo>>,
    /// Receiver for sandbox analysis responses in the main event loop.
    pub sandbox_res_rx: mpsc::UnboundedReceiver<Vec<crate::logic::sandbox::SandboxInfo>>,
    /// Sender for preflight summary requests (packages, action).
    pub summary_req_tx:
        mpsc::UnboundedSender<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Sender for preflight summary responses.
    pub summary_res_tx: mpsc::UnboundedSender<crate::logic::preflight::PreflightSummaryOutcome>,
    /// Receiver for preflight summary responses in the main event loop.
    pub summary_res_rx: mpsc::UnboundedReceiver<crate::logic::preflight::PreflightSummaryOutcome>,
    /// Sender for executor requests (install/remove/downgrade operations).
    pub executor_req_tx: mpsc::UnboundedSender<crate::install::ExecutorRequest>,
    /// Receiver for executor responses in the main event loop.
    pub executor_res_rx: mpsc::UnboundedReceiver<crate::install::ExecutorOutput>,
    /// Sender for AUR vote requests (vote/unvote operations).
    pub aur_vote_req_tx: mpsc::UnboundedSender<AurVoteRequest>,
    /// Receiver for AUR vote responses in the main event loop.
    pub aur_vote_res_rx: mpsc::UnboundedReceiver<AurVoteResponse>,
    /// Sender for AUR vote-state requests.
    pub aur_vote_state_req_tx: mpsc::UnboundedSender<AurVoteStateRequest>,
    /// Receiver for AUR vote-state responses in the main event loop.
    pub aur_vote_state_res_rx: mpsc::UnboundedReceiver<AurVoteStateResponse>,
    /// Sender for post-summary computation requests (packages, success flag).
    pub post_summary_req_tx: mpsc::UnboundedSender<(Vec<PackageItem>, Option<bool>)>,
    /// Receiver for post-summary computation results in the main event loop.
    pub post_summary_res_rx: mpsc::UnboundedReceiver<crate::logic::summary::PostSummaryData>,
    /// Sender for search queries to the search worker.
    pub query_tx: mpsc::UnboundedSender<QueryInput>,
}

/// What: Event channel pair and cancellation flag.
struct EventChannels {
    /// Sender for terminal events.
    tx: mpsc::UnboundedSender<CEvent>,
    /// Receiver for terminal events.
    rx: mpsc::UnboundedReceiver<CEvent>,
    /// Cancellation flag for event thread.
    cancelled: Arc<AtomicBool>,
}

/// What: Search-related channels.
struct SearchChannels {
    /// Sender for search results.
    result_tx: mpsc::UnboundedSender<SearchResults>,
    /// Receiver for search results.
    results_rx: mpsc::UnboundedReceiver<SearchResults>,
    /// Sender for search queries.
    query_tx: mpsc::UnboundedSender<QueryInput>,
    /// Receiver for search queries.
    query_rx: mpsc::UnboundedReceiver<QueryInput>,
}

/// What: Package details channels.
struct DetailsChannels {
    /// Sender for package details requests.
    req_tx: mpsc::UnboundedSender<PackageItem>,
    /// Receiver for package details requests.
    req_rx: mpsc::UnboundedReceiver<PackageItem>,
    /// Sender for package details responses.
    res_tx: mpsc::UnboundedSender<PackageDetails>,
    /// Receiver for package details responses.
    res_rx: mpsc::UnboundedReceiver<PackageDetails>,
}

/// What: Preflight-related channels (dependencies, files, services, sandbox, summary).
struct PreflightChannels {
    /// Sender for dependency resolution requests.
    deps_req_tx: mpsc::UnboundedSender<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Receiver for dependency resolution requests.
    deps_req_rx: mpsc::UnboundedReceiver<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Sender for dependency resolution responses.
    deps_res_tx: mpsc::UnboundedSender<Vec<crate::state::modal::DependencyInfo>>,
    /// Receiver for dependency resolution responses.
    deps_res_rx: mpsc::UnboundedReceiver<Vec<crate::state::modal::DependencyInfo>>,
    /// Sender for file analysis requests.
    files_req_tx: mpsc::UnboundedSender<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Receiver for file analysis requests.
    files_req_rx: mpsc::UnboundedReceiver<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Sender for file analysis responses.
    files_res_tx: mpsc::UnboundedSender<Vec<crate::state::modal::PackageFileInfo>>,
    /// Receiver for file analysis responses.
    files_res_rx: mpsc::UnboundedReceiver<Vec<crate::state::modal::PackageFileInfo>>,
    /// Sender for service impact analysis requests.
    services_req_tx:
        mpsc::UnboundedSender<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Receiver for service impact analysis requests.
    services_req_rx:
        mpsc::UnboundedReceiver<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Sender for service impact analysis responses.
    services_res_tx: mpsc::UnboundedSender<Vec<crate::state::modal::ServiceImpact>>,
    /// Receiver for service impact analysis responses.
    services_res_rx: mpsc::UnboundedReceiver<Vec<crate::state::modal::ServiceImpact>>,
    /// Sender for sandbox analysis requests.
    sandbox_req_tx: mpsc::UnboundedSender<Vec<PackageItem>>,
    /// Receiver for sandbox analysis requests.
    sandbox_req_rx: mpsc::UnboundedReceiver<Vec<PackageItem>>,
    /// Sender for sandbox analysis responses.
    sandbox_res_tx: mpsc::UnboundedSender<Vec<crate::logic::sandbox::SandboxInfo>>,
    /// Receiver for sandbox analysis responses.
    sandbox_res_rx: mpsc::UnboundedReceiver<Vec<crate::logic::sandbox::SandboxInfo>>,
    /// Sender for preflight summary requests.
    summary_req_tx: mpsc::UnboundedSender<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Receiver for preflight summary requests.
    summary_req_rx:
        mpsc::UnboundedReceiver<(Vec<PackageItem>, crate::state::modal::PreflightAction)>,
    /// Sender for preflight summary responses.
    summary_res_tx: mpsc::UnboundedSender<crate::logic::preflight::PreflightSummaryOutcome>,
    /// Receiver for preflight summary responses.
    summary_res_rx: mpsc::UnboundedReceiver<crate::logic::preflight::PreflightSummaryOutcome>,
}

/// What: Utility channels (tick, network errors, preview, add, index notify, PKGBUILD, status, news).
struct UtilityChannels {
    /// Sender for tick events.
    tick_tx: mpsc::UnboundedSender<()>,
    /// Receiver for tick events.
    tick_rx: mpsc::UnboundedReceiver<()>,
    /// Sender for network error messages.
    net_err_tx: mpsc::UnboundedSender<String>,
    /// Receiver for network error messages.
    net_err_rx: mpsc::UnboundedReceiver<String>,
    /// Sender for preview requests.
    preview_tx: mpsc::UnboundedSender<PackageItem>,
    /// Receiver for preview requests.
    preview_rx: mpsc::UnboundedReceiver<PackageItem>,
    /// Sender for add to install list requests.
    add_tx: mpsc::UnboundedSender<PackageItem>,
    /// Receiver for add to install list requests.
    add_rx: mpsc::UnboundedReceiver<PackageItem>,
    /// Sender for index update notifications.
    index_notify_tx: mpsc::UnboundedSender<()>,
    /// Receiver for index update notifications.
    index_notify_rx: mpsc::UnboundedReceiver<()>,
    /// Sender for PKGBUILD requests.
    pkgb_req_tx: mpsc::UnboundedSender<PackageItem>,
    /// Receiver for PKGBUILD requests.
    pkgb_req_rx: mpsc::UnboundedReceiver<PackageItem>,
    /// Sender for PKGBUILD responses.
    pkgb_res_tx: mpsc::UnboundedSender<(String, String)>,
    /// Receiver for PKGBUILD responses.
    pkgb_res_rx: mpsc::UnboundedReceiver<(String, String)>,
    /// Sender for PKGBUILD check requests.
    pkgb_check_req_tx: mpsc::UnboundedSender<PkgbuildCheckRequest>,
    /// Receiver for PKGBUILD check requests.
    pkgb_check_req_rx: mpsc::UnboundedReceiver<PkgbuildCheckRequest>,
    /// Sender for PKGBUILD check responses.
    pkgb_check_res_tx: mpsc::UnboundedSender<PkgbuildCheckResponse>,
    /// Receiver for PKGBUILD check responses.
    pkgb_check_res_rx: mpsc::UnboundedReceiver<PkgbuildCheckResponse>,
    /// Sender for AUR comments requests.
    comments_req_tx: mpsc::UnboundedSender<String>,
    /// Receiver for AUR comments requests.
    comments_req_rx: mpsc::UnboundedReceiver<String>,
    /// Sender for AUR comments responses.
    comments_res_tx:
        mpsc::UnboundedSender<(String, Result<Vec<crate::state::types::AurComment>, String>)>,
    /// Receiver for AUR comments responses.
    comments_res_rx:
        mpsc::UnboundedReceiver<(String, Result<Vec<crate::state::types::AurComment>, String>)>,
    /// Sender for Arch Linux status updates.
    status_tx: mpsc::UnboundedSender<(String, ArchStatusColor)>,
    /// Receiver for Arch Linux status updates.
    status_rx: mpsc::UnboundedReceiver<(String, ArchStatusColor)>,
    /// Sender for startup news popup items.
    news_tx: mpsc::UnboundedSender<Vec<crate::state::types::NewsFeedItem>>,
    /// Receiver for startup news popup items.
    news_rx: mpsc::UnboundedReceiver<Vec<crate::state::types::NewsFeedItem>>,
    /// Sender for news feed payloads.
    news_feed_tx: mpsc::UnboundedSender<NewsFeedPayload>,
    /// Receiver for news feed payloads.
    news_feed_rx: mpsc::UnboundedReceiver<NewsFeedPayload>,
    /// Sender for incremental news items.
    news_incremental_tx: mpsc::UnboundedSender<crate::state::types::NewsFeedItem>,
    /// Receiver for incremental news items.
    news_incremental_rx: mpsc::UnboundedReceiver<crate::state::types::NewsFeedItem>,
    /// Sender for news article content requests.
    news_content_req_tx: mpsc::UnboundedSender<String>,
    /// Receiver for news article content requests.
    news_content_req_rx: mpsc::UnboundedReceiver<String>,
    /// Sender for news article content responses.
    news_content_res_tx: mpsc::UnboundedSender<(String, String)>,
    /// Receiver for news article content responses.
    news_content_res_rx: mpsc::UnboundedReceiver<(String, String)>,
    /// Sender for system updates information.
    updates_tx: mpsc::UnboundedSender<UpdateCheckPayload>,
    /// Receiver for system updates information.
    updates_rx: mpsc::UnboundedReceiver<UpdateCheckPayload>,
    /// Sender for remote announcements.
    announcement_tx: mpsc::UnboundedSender<crate::announcements::RemoteAnnouncement>,
    /// Receiver for remote announcements.
    announcement_rx: mpsc::UnboundedReceiver<crate::announcements::RemoteAnnouncement>,
    /// Sender for executor requests.
    executor_req_tx: mpsc::UnboundedSender<crate::install::ExecutorRequest>,
    /// Receiver for executor requests.
    executor_req_rx: mpsc::UnboundedReceiver<crate::install::ExecutorRequest>,
    /// Sender for executor responses.
    executor_res_tx: mpsc::UnboundedSender<crate::install::ExecutorOutput>,
    /// Receiver for executor responses.
    executor_res_rx: mpsc::UnboundedReceiver<crate::install::ExecutorOutput>,
    /// Sender for AUR vote requests.
    aur_vote_req_tx: mpsc::UnboundedSender<AurVoteRequest>,
    /// Receiver for AUR vote requests.
    aur_vote_req_rx: mpsc::UnboundedReceiver<AurVoteRequest>,
    /// Sender for AUR vote responses.
    aur_vote_res_tx: mpsc::UnboundedSender<AurVoteResponse>,
    /// Receiver for AUR vote responses.
    aur_vote_res_rx: mpsc::UnboundedReceiver<AurVoteResponse>,
    /// Sender for AUR vote-state requests.
    aur_vote_state_req_tx: mpsc::UnboundedSender<AurVoteStateRequest>,
    /// Receiver for AUR vote-state requests.
    aur_vote_state_req_rx: mpsc::UnboundedReceiver<AurVoteStateRequest>,
    /// Sender for AUR vote-state responses.
    aur_vote_state_res_tx: mpsc::UnboundedSender<AurVoteStateResponse>,
    /// Receiver for AUR vote-state responses.
    aur_vote_state_res_rx: mpsc::UnboundedReceiver<AurVoteStateResponse>,
    /// Sender for post-summary computation requests.
    post_summary_req_tx: mpsc::UnboundedSender<(Vec<PackageItem>, Option<bool>)>,
    /// Receiver for post-summary computation requests.
    post_summary_req_rx: mpsc::UnboundedReceiver<(Vec<PackageItem>, Option<bool>)>,
    /// Sender for post-summary computation results.
    post_summary_res_tx: mpsc::UnboundedSender<crate::logic::summary::PostSummaryData>,
    /// Receiver for post-summary computation results.
    post_summary_res_rx: mpsc::UnboundedReceiver<crate::logic::summary::PostSummaryData>,
}

/// What: Create event channels.
///
/// Output:
/// - Returns event channels and cancellation flag
fn create_event_channels() -> EventChannels {
    let (tx, rx) = mpsc::unbounded_channel::<CEvent>();
    let cancelled = Arc::new(AtomicBool::new(false));
    EventChannels { tx, rx, cancelled }
}

/// What: Create search-related channels.
///
/// Output:
/// - Returns search channels
fn create_search_channels() -> SearchChannels {
    let (result_tx, results_rx) = mpsc::unbounded_channel::<SearchResults>();
    let (query_tx, query_rx) = mpsc::unbounded_channel::<QueryInput>();
    SearchChannels {
        result_tx,
        results_rx,
        query_tx,
        query_rx,
    }
}

/// What: Create package details channels.
///
/// Output:
/// - Returns details channels
fn create_details_channels() -> DetailsChannels {
    let (req_tx, req_rx) = mpsc::unbounded_channel::<PackageItem>();
    let (res_tx, res_rx) = mpsc::unbounded_channel::<PackageDetails>();
    DetailsChannels {
        req_tx,
        req_rx,
        res_tx,
        res_rx,
    }
}

/// What: Create preflight-related channels.
///
/// Output:
/// - Returns preflight channels
fn create_preflight_channels() -> PreflightChannels {
    let (deps_req_tx, deps_req_rx) =
        mpsc::unbounded_channel::<(Vec<PackageItem>, crate::state::modal::PreflightAction)>();
    let (deps_res_tx, deps_res_rx) =
        mpsc::unbounded_channel::<Vec<crate::state::modal::DependencyInfo>>();
    let (files_req_tx, files_req_rx) =
        mpsc::unbounded_channel::<(Vec<PackageItem>, crate::state::modal::PreflightAction)>();
    let (files_res_tx, files_res_rx) =
        mpsc::unbounded_channel::<Vec<crate::state::modal::PackageFileInfo>>();
    let (services_req_tx, services_req_rx) =
        mpsc::unbounded_channel::<(Vec<PackageItem>, crate::state::modal::PreflightAction)>();
    let (services_res_tx, services_res_rx) =
        mpsc::unbounded_channel::<Vec<crate::state::modal::ServiceImpact>>();
    let (sandbox_req_tx, sandbox_req_rx) = mpsc::unbounded_channel::<Vec<PackageItem>>();
    let (sandbox_res_tx, sandbox_res_rx) =
        mpsc::unbounded_channel::<Vec<crate::logic::sandbox::SandboxInfo>>();
    let (summary_req_tx, summary_req_rx) =
        mpsc::unbounded_channel::<(Vec<PackageItem>, crate::state::modal::PreflightAction)>();
    let (summary_res_tx, summary_res_rx) =
        mpsc::unbounded_channel::<crate::logic::preflight::PreflightSummaryOutcome>();
    PreflightChannels {
        deps_req_tx,
        deps_req_rx,
        deps_res_tx,
        deps_res_rx,
        files_req_tx,
        files_req_rx,
        files_res_tx,
        files_res_rx,
        services_req_tx,
        services_req_rx,
        services_res_tx,
        services_res_rx,
        sandbox_req_tx,
        sandbox_req_rx,
        sandbox_res_tx,
        sandbox_res_rx,
        summary_req_tx,
        summary_req_rx,
        summary_res_tx,
        summary_res_rx,
    }
}

/// What: Create utility channels.
///
/// Output:
/// - Returns utility channels
fn create_utility_channels() -> UtilityChannels {
    let (tick_tx, tick_rx) = mpsc::unbounded_channel::<()>();
    let (net_err_tx, net_err_rx) = mpsc::unbounded_channel::<String>();
    let (preview_tx, preview_rx) = mpsc::unbounded_channel::<PackageItem>();
    let (add_tx, add_rx) = mpsc::unbounded_channel::<PackageItem>();
    let (index_notify_tx, index_notify_rx) = mpsc::unbounded_channel::<()>();
    let (pkgb_req_tx, pkgb_req_rx) = mpsc::unbounded_channel::<PackageItem>();
    let (pkgb_res_tx, pkgb_res_rx) = mpsc::unbounded_channel::<(String, String)>();
    let (pkgb_check_req_tx, pkgb_check_req_rx) = mpsc::unbounded_channel::<PkgbuildCheckRequest>();
    let (pkgb_check_res_tx, pkgb_check_res_rx) = mpsc::unbounded_channel::<PkgbuildCheckResponse>();
    let (comments_req_tx, comments_req_rx) = mpsc::unbounded_channel::<String>();
    let (comments_res_tx, comments_res_rx) =
        mpsc::unbounded_channel::<(String, Result<Vec<crate::state::types::AurComment>, String>)>();
    let (status_tx, status_rx) = mpsc::unbounded_channel::<(String, ArchStatusColor)>();
    let (news_tx, news_rx) = mpsc::unbounded_channel::<Vec<crate::state::types::NewsFeedItem>>();
    let (news_feed_tx, news_feed_rx) = mpsc::unbounded_channel::<NewsFeedPayload>();
    let (news_incremental_tx, news_incremental_rx) =
        mpsc::unbounded_channel::<crate::state::types::NewsFeedItem>();
    let (news_content_req_tx, news_content_req_rx) = mpsc::unbounded_channel::<String>();
    let (news_content_res_tx, news_content_res_rx) = mpsc::unbounded_channel::<(String, String)>();
    let (updates_tx, updates_rx) = mpsc::unbounded_channel::<UpdateCheckPayload>();
    let (announcement_tx, announcement_rx) =
        mpsc::unbounded_channel::<crate::announcements::RemoteAnnouncement>();
    let (executor_req_tx, executor_req_rx) =
        mpsc::unbounded_channel::<crate::install::ExecutorRequest>();
    let (executor_res_tx, executor_res_rx) =
        mpsc::unbounded_channel::<crate::install::ExecutorOutput>();
    let (aur_vote_req_tx, aur_vote_req_rx) = mpsc::unbounded_channel::<AurVoteRequest>();
    let (aur_vote_res_tx, aur_vote_res_rx) = mpsc::unbounded_channel::<AurVoteResponse>();
    let (aur_vote_state_req_tx, aur_vote_state_req_rx) =
        mpsc::unbounded_channel::<AurVoteStateRequest>();
    let (aur_vote_state_res_tx, aur_vote_state_res_rx) =
        mpsc::unbounded_channel::<AurVoteStateResponse>();
    let (post_summary_req_tx, post_summary_req_rx) =
        mpsc::unbounded_channel::<(Vec<PackageItem>, Option<bool>)>();
    let (post_summary_res_tx, post_summary_res_rx) =
        mpsc::unbounded_channel::<crate::logic::summary::PostSummaryData>();
    UtilityChannels {
        tick_tx,
        tick_rx,
        net_err_tx,
        net_err_rx,
        preview_tx,
        preview_rx,
        add_tx,
        add_rx,
        index_notify_tx,
        index_notify_rx,
        pkgb_req_tx,
        pkgb_req_rx,
        pkgb_res_tx,
        pkgb_res_rx,
        pkgb_check_req_tx,
        pkgb_check_req_rx,
        pkgb_check_res_tx,
        pkgb_check_res_rx,
        comments_req_tx,
        comments_req_rx,
        comments_res_tx,
        comments_res_rx,
        status_tx,
        status_rx,
        news_tx,
        news_rx,
        news_feed_tx,
        news_feed_rx,
        news_incremental_tx,
        news_incremental_rx,
        news_content_req_tx,
        news_content_req_rx,
        news_content_res_tx,
        news_content_res_rx,
        updates_tx,
        updates_rx,
        announcement_tx,
        announcement_rx,
        executor_req_tx,
        executor_req_rx,
        executor_res_tx,
        executor_res_rx,
        aur_vote_req_tx,
        aur_vote_req_rx,
        aur_vote_res_tx,
        aur_vote_res_rx,
        aur_vote_state_req_tx,
        aur_vote_state_req_rx,
        aur_vote_state_res_tx,
        aur_vote_state_res_rx,
        post_summary_req_tx,
        post_summary_req_rx,
        post_summary_res_tx,
        post_summary_res_rx,
    }
}

impl Channels {
    /// What: Create all channels used for runtime communication.
    ///
    /// Inputs:
    /// - `index_path`: Path to official package index (for search worker)
    ///
    /// Output:
    /// - Returns a `Channels` struct with all senders and receivers initialized
    pub fn new(index_path: std::path::PathBuf) -> Self {
        let event_channels = create_event_channels();
        let search_channels = create_search_channels();
        let details_channels = create_details_channels();
        let preflight_channels = create_preflight_channels();
        let utility_channels = create_utility_channels();

        // Spawn background workers
        crate::app::runtime::workers::details::spawn_details_worker(
            &utility_channels.net_err_tx,
            details_channels.req_rx,
            details_channels.res_tx.clone(),
        );
        crate::app::runtime::workers::details::spawn_pkgbuild_worker(
            utility_channels.pkgb_req_rx,
            utility_channels.pkgb_res_tx.clone(),
        );
        crate::app::runtime::workers::details::spawn_pkgbuild_checks_worker(
            utility_channels.pkgb_check_req_rx,
            utility_channels.pkgb_check_res_tx.clone(),
        );
        crate::app::runtime::workers::comments::spawn_comments_worker(
            utility_channels.comments_req_rx,
            utility_channels.comments_res_tx.clone(),
        );
        crate::app::runtime::workers::news_content::spawn_news_content_worker(
            utility_channels.news_content_req_rx,
            utility_channels.news_content_res_tx.clone(),
        );
        crate::app::runtime::workers::preflight::spawn_dependency_worker(
            preflight_channels.deps_req_rx,
            preflight_channels.deps_res_tx.clone(),
        );
        crate::app::runtime::workers::preflight::spawn_file_worker(
            preflight_channels.files_req_rx,
            preflight_channels.files_res_tx.clone(),
        );
        crate::app::runtime::workers::preflight::spawn_service_worker(
            preflight_channels.services_req_rx,
            preflight_channels.services_res_tx.clone(),
        );
        crate::app::runtime::workers::preflight::spawn_sandbox_worker(
            preflight_channels.sandbox_req_rx,
            preflight_channels.sandbox_res_tx.clone(),
        );
        crate::app::runtime::workers::preflight::spawn_summary_worker(
            preflight_channels.summary_req_rx,
            preflight_channels.summary_res_tx.clone(),
        );
        crate::app::runtime::workers::search::spawn_search_worker(
            search_channels.query_rx,
            search_channels.result_tx.clone(),
            &utility_channels.net_err_tx,
            index_path,
        );
        crate::app::runtime::workers::executor::spawn_executor_worker(
            utility_channels.executor_req_rx,
            utility_channels.executor_res_tx.clone(),
        );
        crate::app::runtime::workers::aur_vote::spawn_aur_vote_worker(
            utility_channels.aur_vote_req_rx,
            utility_channels.aur_vote_res_tx.clone(),
        );
        crate::app::runtime::workers::aur_vote::spawn_aur_vote_state_worker(
            utility_channels.aur_vote_state_req_rx,
            utility_channels.aur_vote_state_res_tx.clone(),
        );
        spawn_post_summary_worker(
            utility_channels.post_summary_req_rx,
            utility_channels.post_summary_res_tx.clone(),
        );

        Self {
            event_tx: event_channels.tx,
            event_rx: event_channels.rx,
            event_thread_cancelled: event_channels.cancelled,
            search_result_tx: search_channels.result_tx,
            results_rx: search_channels.results_rx,
            details_req_tx: details_channels.req_tx,
            details_res_tx: details_channels.res_tx,
            details_res_rx: details_channels.res_rx,
            tick_tx: utility_channels.tick_tx,
            tick_rx: utility_channels.tick_rx,
            net_err_tx: utility_channels.net_err_tx,
            net_err_rx: utility_channels.net_err_rx,
            preview_tx: utility_channels.preview_tx,
            preview_rx: utility_channels.preview_rx,
            add_tx: utility_channels.add_tx,
            add_rx: utility_channels.add_rx,
            index_notify_tx: utility_channels.index_notify_tx,
            index_notify_rx: utility_channels.index_notify_rx,
            pkgb_req_tx: utility_channels.pkgb_req_tx,
            pkgb_res_tx: utility_channels.pkgb_res_tx,
            pkgb_res_rx: utility_channels.pkgb_res_rx,
            pkgb_check_req_tx: utility_channels.pkgb_check_req_tx,
            pkgb_check_res_rx: utility_channels.pkgb_check_res_rx,
            comments_req_tx: utility_channels.comments_req_tx,
            comments_res_tx: utility_channels.comments_res_tx,
            comments_res_rx: utility_channels.comments_res_rx,
            status_tx: utility_channels.status_tx,
            status_rx: utility_channels.status_rx,
            news_tx: utility_channels.news_tx,
            news_rx: utility_channels.news_rx,
            news_feed_tx: utility_channels.news_feed_tx,
            news_feed_rx: utility_channels.news_feed_rx,
            news_incremental_tx: utility_channels.news_incremental_tx,
            news_incremental_rx: utility_channels.news_incremental_rx,
            news_content_req_tx: utility_channels.news_content_req_tx,
            news_content_res_rx: utility_channels.news_content_res_rx,
            updates_tx: utility_channels.updates_tx,
            updates_rx: utility_channels.updates_rx,
            announcement_tx: utility_channels.announcement_tx,
            announcement_rx: utility_channels.announcement_rx,
            deps_req_tx: preflight_channels.deps_req_tx,
            deps_res_tx: preflight_channels.deps_res_tx,
            deps_res_rx: preflight_channels.deps_res_rx,
            files_req_tx: preflight_channels.files_req_tx,
            files_res_tx: preflight_channels.files_res_tx,
            files_res_rx: preflight_channels.files_res_rx,
            services_req_tx: preflight_channels.services_req_tx,
            services_res_tx: preflight_channels.services_res_tx,
            services_res_rx: preflight_channels.services_res_rx,
            sandbox_req_tx: preflight_channels.sandbox_req_tx,
            sandbox_res_tx: preflight_channels.sandbox_res_tx,
            sandbox_res_rx: preflight_channels.sandbox_res_rx,
            summary_req_tx: preflight_channels.summary_req_tx,
            summary_res_tx: preflight_channels.summary_res_tx,
            summary_res_rx: preflight_channels.summary_res_rx,
            executor_req_tx: utility_channels.executor_req_tx,
            executor_res_rx: utility_channels.executor_res_rx,
            aur_vote_req_tx: utility_channels.aur_vote_req_tx,
            aur_vote_res_rx: utility_channels.aur_vote_res_rx,
            aur_vote_state_req_tx: utility_channels.aur_vote_state_req_tx,
            aur_vote_state_res_rx: utility_channels.aur_vote_state_res_rx,
            post_summary_req_tx: utility_channels.post_summary_req_tx,
            post_summary_res_rx: utility_channels.post_summary_res_rx,
            query_tx: search_channels.query_tx,
        }
    }
}

/// What: Spawn background worker for post-summary computation.
///
/// Inputs:
/// - `req_rx`: Channel receiver for post-summary requests (package items)
/// - `res_tx`: Channel sender for post-summary results
///
/// Details:
/// - Runs `compute_post_summary` in a blocking task to avoid blocking the UI
fn spawn_post_summary_worker(
    mut req_rx: mpsc::UnboundedReceiver<(Vec<PackageItem>, Option<bool>)>,
    res_tx: mpsc::UnboundedSender<crate::logic::summary::PostSummaryData>,
) {
    tokio::spawn(async move {
        while let Some((items, success)) = req_rx.recv().await {
            let res_tx = res_tx.clone();
            tokio::task::spawn_blocking(move || {
                let data = crate::logic::compute_post_summary(&items, success);
                let _ = res_tx.send(data);
            });
        }
    });
}