Iteration 6: --resume + persistent input history + migration scaffold
Closes out track 2's ADR-0015 backlog. * `--resume` CLI flag (L1a, ADR-0015 §7) opens the most- recently-used project, tracked in <data-root>/last_project. Mutually exclusive with a positional <project-path>; errors cleanly to stderr (above the shell prompt) on missing file or stale recorded path. last_project is rewritten on every successful project open (startup, load, new, save as, import). * Persistent input history (I2-persist, ADR-0015 §12). On project open, the in-memory navigable history is hydrated from the tail of history.log (capped at the in-memory cap). ProjectSwitched gains a `history_entries` payload field; App::seed_history is the entry point. Pipes inside source text round-trip via splitn(3); unknown escape sequences are passed through literally. * Migration framework scaffold (F3, ADR-0015 §9). New persistence::migrations module with MigratorRegistry + migrate_to_latest + ensure_project_yaml_migrated. Empty in v1 (production registry has no migrators); the loader runs through it on every project open and is exercised by tests with a fake v1→v2 migrator. Writes project.yaml.v<N>.bak before any migrator runs; verifies each step bumps the version field. Refreshes docs/requirements.md (A1 / I2 / F3 / E1 / L1a / test baseline) and adds docs/handoff/20260508-handoff-3.md covering both Iter 5 and Iter 6. Total tests: 408 passing, 0 failing, 0 skipped (up from 345 at handoff-2). Clippy clean.
This commit is contained in:
+23
@@ -248,6 +248,27 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the in-memory navigable history with `entries`,
|
||||
/// truncating to the in-memory cap.
|
||||
///
|
||||
/// Used by the runtime to hydrate from the project's
|
||||
/// `history.log` on open (I2-persist, ADR-0015 §12).
|
||||
/// Entries should arrive in chronological order (oldest
|
||||
/// first); the most recent stays at the back, which is
|
||||
/// where Up/Down navigation expects it.
|
||||
///
|
||||
/// Cancels any in-flight history navigation so a hydrate
|
||||
/// during a session (e.g. after `load`) doesn't leave a
|
||||
/// dangling cursor pointing at a now-removed entry.
|
||||
pub fn seed_history(&mut self, entries: Vec<String>) {
|
||||
self.history = entries;
|
||||
while self.history.len() > HISTORY_CAPACITY {
|
||||
self.history.remove(0);
|
||||
}
|
||||
self.history_cursor = None;
|
||||
self.history_draft = None;
|
||||
}
|
||||
|
||||
/// Effective mode for the *next* submission, given the
|
||||
/// persistent mode and the current input buffer. See
|
||||
/// [`EffectiveMode`].
|
||||
@@ -353,12 +374,14 @@ impl App {
|
||||
AppEvent::ProjectSwitched {
|
||||
display_name,
|
||||
is_temp,
|
||||
history_entries,
|
||||
} => {
|
||||
self.note_system(format!("[ok] now editing: {display_name}"));
|
||||
self.project_name = Some(display_name);
|
||||
self.project_is_temp = is_temp;
|
||||
self.tables.clear();
|
||||
self.current_table = None;
|
||||
self.seed_history(history_entries);
|
||||
Vec::new()
|
||||
}
|
||||
AppEvent::ProjectSwitchFailed { error } => {
|
||||
|
||||
Reference in New Issue
Block a user