docs(01-03): complete app event loop and Phase 1 wiring plan
- 01-03-SUMMARY.md: documents App struct, event loop, double-Ctrl+C state machine, main.rs pipeline - STATE.md: Phase 1 complete, 3/3 plans done, Phase 2 next, 01-03 decisions recorded - ROADMAP.md: Phase 1 marked Complete (3 plans / 3 summaries) - REQUIREMENTS.md: SHEL-01 marked complete
This commit is contained in:
@@ -57,7 +57,7 @@ Requirements for initial release. Each maps to roadmap phases.
|
||||
|
||||
### Shell Integration
|
||||
|
||||
- [ ] **SHEL-01**: App exits cleanly with q or Ctrl+C, restoring terminal state
|
||||
- [x] **SHEL-01**: App exits cleanly with q or Ctrl+C, restoring terminal state
|
||||
- [x] **SHEL-02**: App handles being launched as a login shell gracefully
|
||||
|
||||
## v2 Requirements
|
||||
@@ -103,7 +103,7 @@ Which phases cover which requirements. Updated during roadmap creation.
|
||||
| LIFE-03 | Phase 1 | Complete |
|
||||
| LIFE-04 | Phase 1 | Complete |
|
||||
| CONF-01 | Phase 1 | Complete (01-01) |
|
||||
| SHEL-01 | Phase 1 | Pending |
|
||||
| SHEL-01 | Phase 1 | Complete |
|
||||
| SHEL-02 | Phase 1 | Complete (01-01) |
|
||||
| REND-01 | Phase 2 | Pending |
|
||||
| REND-02 | Phase 2 | Pending |
|
||||
|
||||
@@ -12,7 +12,7 @@ Four phases take this project from a bare Rust scaffold to a fully functional re
|
||||
|
||||
Decimal phases appear between their surrounding integers in numeric order.
|
||||
|
||||
- [ ] **Phase 1: Safety Foundation** - Process lifecycle safety, shell integration, and configuration
|
||||
- [x] **Phase 1: Safety Foundation** - Process lifecycle safety, shell integration, and configuration (completed 2026-02-28)
|
||||
- [ ] **Phase 2: Vault Core and Rendering** - Markdown parsing pipeline and full content display
|
||||
- [ ] **Phase 3: Navigation and Links** - Link following, back/forward history, link cycling
|
||||
- [ ] **Phase 4: BBS Polish and Live Content** - Retro aesthetic, filesystem watching, directory listing
|
||||
@@ -29,7 +29,7 @@ Decimal phases appear between their surrounding integers in numeric order.
|
||||
3. The app reads vault path and theme settings from bbs.toml and applies them on launch
|
||||
4. The app exits cleanly when the user presses q or Ctrl+C, restoring the terminal
|
||||
5. The app starts correctly when invoked as a login shell (argv[0] may have a leading dash)
|
||||
**Plans:** 3 plans
|
||||
**Plans:** 3/3 plans complete
|
||||
Plans:
|
||||
- [x] 01-01-PLAN.md — Config loading, CLI parsing, and login shell detection
|
||||
- [ ] 01-02-PLAN.md — Terminal init/restore, panic hook, and signal handling
|
||||
@@ -77,7 +77,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Safety Foundation | 1/3 | Executing | - |
|
||||
| 1. Safety Foundation | 3/3 | Complete | 2026-02-28 |
|
||||
| 2. Vault Core and Rendering | 0/TBD | Not started | - |
|
||||
| 3. Navigation and Links | 0/TBD | Not started | - |
|
||||
| 4. BBS Polish and Live Content | 0/TBD | Not started | - |
|
||||
|
||||
+17
-14
@@ -5,32 +5,32 @@
|
||||
See: .planning/PROJECT.md (updated 2026-02-28)
|
||||
|
||||
**Core value:** Users can connect via SSH and seamlessly browse a vault of linked markdown documents with retro BBS aesthetics
|
||||
**Current focus:** Phase 1 - Safety Foundation
|
||||
**Current focus:** Phase 1 complete — Phase 2 next (Content Rendering)
|
||||
|
||||
## Current Position
|
||||
|
||||
Phase: 1 of 4 (Safety Foundation)
|
||||
Plan: 2 of 3 in current phase
|
||||
Status: Executing — Plan 02 complete, Plan 03 next
|
||||
Last activity: 2026-02-28 — Plan 02 complete (terminal safety primitives)
|
||||
Phase: 1 of 4 (Safety Foundation) — COMPLETE
|
||||
Plan: 3 of 3 in current phase (all plans done)
|
||||
Status: Phase 1 complete — Phase 2 ready to start
|
||||
Last activity: 2026-02-28 — Plan 03 complete (event loop + main.rs wiring)
|
||||
|
||||
Progress: [██░░░░░░░░] 17%
|
||||
Progress: [███░░░░░░░] 25%
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
**Velocity:**
|
||||
- Total plans completed: 2
|
||||
- Average duration: 3 min
|
||||
- Total execution time: 0.08 hours
|
||||
- Total plans completed: 3
|
||||
- Average duration: 2.3 min
|
||||
- Total execution time: 0.12 hours
|
||||
|
||||
**By Phase:**
|
||||
|
||||
| Phase | Plans | Total | Avg/Plan |
|
||||
|-------|-------|-------|----------|
|
||||
| 01-safety-foundation | 2 | 5 min | 2.5 min |
|
||||
| 01-safety-foundation | 3 | 7 min | 2.3 min |
|
||||
|
||||
**Recent Trend:**
|
||||
- Last 5 plans: 2 min, 3 min
|
||||
- Last 5 plans: 2 min, 3 min, 2 min
|
||||
- Trend: Stable
|
||||
|
||||
*Updated after each plan completion*
|
||||
@@ -51,10 +51,13 @@ Recent decisions affecting current work:
|
||||
- 01-02: Use ratatui::crossterm re-export path — crossterm is transitive dep, not direct dep in Cargo.toml
|
||||
- 01-02: SIGINT not registered via signal-hook — crossterm key events handle double-press Ctrl+C in Plan 03
|
||||
- 01-02: restore_terminal() skips ratatui::restore() — that would call LeaveAlternateScreen (never entered)
|
||||
- 01-03: show_goodbye() called after restore_terminal() — terminal must be in cooked mode before println! is safe
|
||||
- 01-03: app_config stored in App struct for Phase 2 access — vault_path accessible inside event loop
|
||||
- 01-03: Quit prompt cleared on any non-Ctrl+C key — pressing any key dismisses double-press window
|
||||
|
||||
### Pending Todos
|
||||
|
||||
None yet.
|
||||
None.
|
||||
|
||||
### Blockers/Concerns
|
||||
|
||||
@@ -65,5 +68,5 @@ None yet.
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-02-28
|
||||
Stopped at: Completed 01-02-PLAN.md — terminal safety primitives committed
|
||||
Resume file: .planning/phases/01-safety-foundation/01-03-PLAN.md
|
||||
Stopped at: Completed 01-03-PLAN.md — Phase 1 complete, app event loop and main.rs pipeline committed
|
||||
Resume file: .planning/phases/02-content-rendering/ (next phase)
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
phase: 01-safety-foundation
|
||||
plan: 03
|
||||
subsystem: app
|
||||
tags: [rust, ratatui, crossterm, tui, event-loop, signal-polling, double-ctrl-c, login-shell, goodbye-message]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 01-01
|
||||
provides: "Config struct, load_config(), detect_login_shell(), parse_cli(), terminal.rs scaffold"
|
||||
- phase: 01-02
|
||||
provides: "init_terminal(), restore_terminal(), install_panic_hook(), SignalFlags, register_signals()"
|
||||
provides:
|
||||
- "src/app.rs: App struct, run_event_loop(), handle_key(), draw(), show_goodbye()"
|
||||
- "src/app.rs: ShutdownReason enum (UserQuit, Signal)"
|
||||
- "src/app.rs: DOUBLE_PRESS_WINDOW const = 2 seconds"
|
||||
- "src/main.rs: complete startup -> event loop -> shutdown pipeline"
|
||||
- "Complete runnable Phase 1 application: cargo run produces working BBS TUI"
|
||||
affects:
|
||||
- "02-content-rendering (event loop receives content model in Phase 2)"
|
||||
- "all future phases (event loop is the central integration point)"
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Signal polling before draw: check SignalFlags.should_terminate() first each loop iteration"
|
||||
- "Double-press window: ctrl_c_pressed_at Option<Instant> compared with elapsed() < DOUBLE_PRESS_WINDOW"
|
||||
- "Login shell suppression: is_login_shell flag disables 'q' key shortcut in handle_key()"
|
||||
- "ratatui::crossterm re-export path: all event polling uses ratatui::crossterm::event"
|
||||
- "BrokenPipe silent exit: event loop propagates io::Error; main catches ErrorKind::BrokenPipe"
|
||||
- "Goodbye after restore: restore_terminal() called first, then show_goodbye() prints to stdout"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- src/app.rs
|
||||
modified:
|
||||
- src/main.rs
|
||||
|
||||
key-decisions:
|
||||
- "show_goodbye() called AFTER restore_terminal() — terminal must be in cooked mode before println! is safe"
|
||||
- "app_config stored in App struct even unused in Phase 1 — avoids dead_code suppression anti-patterns and prepares Phase 2 access"
|
||||
- "quit prompt cleared on any non-Ctrl+C key — pressing Enter/arrow/letter dismisses the double-press window"
|
||||
|
||||
patterns-established:
|
||||
- "Signal-first event loop: signals.should_terminate() is always the first check before draw"
|
||||
- "Layered shutdown: restore_terminal() unconditional, then match shutdown_reason for post-restore actions"
|
||||
- "Login shell mode: is_login_shell propagated from main -> App::new, controls key behavior throughout"
|
||||
|
||||
requirements-completed: [SHEL-01]
|
||||
|
||||
# Metrics
|
||||
duration: 2min
|
||||
completed: 2026-02-28
|
||||
---
|
||||
|
||||
# Phase 1 Plan 03: App Event Loop and Wiring Summary
|
||||
|
||||
**Double-press Ctrl+C state machine with login-shell 'q' suppression, signal-polling event loop, BBS goodbye message, and complete startup-to-shutdown pipeline wired in main.rs**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 2 min
|
||||
- **Started:** 2026-02-28T20:15:54Z
|
||||
- **Completed:** 2026-02-28T20:17:54Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 2
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- App struct implements double-press Ctrl+C with a 2-second window using Option<Instant> elapsed comparison
|
||||
- Login shell mode suppresses the 'q' key shortcut — only double Ctrl+C exits, enforcing SHEL-01
|
||||
- Event loop checks SignalFlags.should_terminate() before each draw — fast path for SSH disconnect (SIGHUP/SIGTERM)
|
||||
- Phase 1 placeholder TUI renders a centered BBS-MD block with quit prompt in yellow when Ctrl+C is first pressed
|
||||
- show_goodbye() prints BBS-style "CARRIER LOST" message and sleeps 500ms after terminal is restored
|
||||
- main.rs wires the full pipeline: config load -> panic hook -> signal registration -> terminal init -> event loop -> restore -> goodbye
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Implement App struct and event loop with exit behavior** - `bad8fba` (feat)
|
||||
2. **Task 2: Wire complete startup-to-shutdown pipeline in main.rs** - `771c9a8` (feat)
|
||||
|
||||
**Plan metadata:** (recorded after final commit)
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `src/app.rs` - App struct with run_event_loop(), handle_key(), draw(); ShutdownReason enum; show_goodbye(); DOUBLE_PRESS_WINDOW const
|
||||
- `src/main.rs` - Complete startup-to-shutdown pipeline with all four modules declared and wired
|
||||
|
||||
## Decisions Made
|
||||
|
||||
- Called `restore_terminal()` unconditionally before the `match shutdown_reason` block. This ensures terminal is always in cooked mode before `show_goodbye()` prints to stdout, and before any `eprintln!()` on unexpected I/O errors.
|
||||
- Stored `app_config` in the `App` struct (via `App::new(is_login_shell, app_config)`) rather than using `let _app_config`. Phase 2 will read `config.vault_path` from inside the event loop, so putting it on App now avoids a refactor later.
|
||||
- Quit prompt is cleared on any non-Ctrl+C key press. This means pressing Enter, arrow keys, or typing any character will dismiss the "Press Ctrl+C again" prompt — matches natural user expectations.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written.
|
||||
|
||||
The only note: the plan listed bare `crossterm::event` in the imports example. Per the 01-02 deviation (crossterm is a transitive dep only), all imports use `ratatui::crossterm::event` instead. This was the established pattern from Plan 02 and applied automatically without needing a new deviation entry.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
None. Build compiled cleanly on first attempt. All key verification checks passed:
|
||||
- No `unwrap()` in terminal.rs or app.rs
|
||||
- No `LeaveAlternateScreen` in executable code (only in doc comments)
|
||||
- DOUBLE_PRESS_WINDOW constant present and used in event loop
|
||||
- All key link patterns confirmed (should_terminate, restore_terminal, run_event_loop, load_config, init_terminal)
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- Phase 1 is complete: all safety requirements (LIFE-01 through LIFE-04, CONF-01, SHEL-01, SHEL-02) are implemented
|
||||
- The event loop in app.rs is the integration point for Phase 2 content rendering — add content model to App struct and call draw functions from draw()
|
||||
- `app_config.vault_path` is already accessible inside App for Phase 2 vault loading
|
||||
- Blocker noted for Phase 2: verify ratatui 0.30 Widget trait signature (changed between 0.28 and 0.29) before building BBS widgets
|
||||
|
||||
---
|
||||
*Phase: 01-safety-foundation*
|
||||
*Completed: 2026-02-28*
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- src/app.rs: FOUND
|
||||
- src/main.rs: FOUND
|
||||
- 01-03-SUMMARY.md: FOUND
|
||||
- Commit bad8fba (Task 1): FOUND
|
||||
- Commit 771c9a8 (Task 2): FOUND
|
||||
Reference in New Issue
Block a user