Cleanup pass: --help, in-app help, post-rebuild message, unmodified-temp cleanup

Four post-Iteration-4 polish items surfaced by manual testing.

1. `--help` / `-h` CLI flag prints a usage banner (options +
   app-level commands + DSL grammar reference) and exits. Parse
   errors also print the banner to stderr.

2. `help` app-level command notes the same list of supported
   commands to the output panel -- a simple stand-in for the
   richer H3 help system, kept in sync with what's actually
   wired up.

3. The silent rebuild that runs when playground.db is missing
   now surfaces a system message in the output panel ("[ok]
   rebuild -- N tables, M rows reconstructed; ...") via a new
   initial_events plumbing. The user no longer wonders whether
   the .db was magically restored or whether anything happened
   on launch.

4. Unmodified empty temp projects (kind=Temp, project.yaml has
   tables: [] and relationships: []) are now auto-deleted when
   the user switches away (load / new / save as) or quits. This
   addresses the "launch app, load existing project, quit"
   pattern that was leaving an empty temp directory behind
   every time. Modified temps (with any user-created tables or
   relationships) are never auto-deleted; corrupted projects
   are also never auto-deleted (defensive default-to-false on
   yaml read/parse errors).

Tests: 338 passing (272 lib + 9 + 5 + 6 + 20 + 9 + 17),
0 failing, 0 skipped. Clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-08 06:43:49 +00:00
parent f2198275f0
commit b7addd6161
6 changed files with 302 additions and 18 deletions
+31
View File
@@ -346,6 +346,37 @@ impl Project {
self.kind
}
/// Is this an auto-named temp project that the user has
/// not modified?
///
/// Used to clean up the inevitable accumulation of
/// auto-named temp directories left behind when the user
/// launches the app, immediately loads another project
/// (or quits without doing anything), and never returns
/// to the temp.
///
/// "Unmodified" is defined as: kind is Temp AND
/// `project.yaml` lists no tables and no relationships.
/// The user-visible schema is what counts — show queries
/// only append to history.log and don't trip this check.
/// Errors reading or parsing the YAML default to "not
/// unmodified" (false), so a corrupted project is never
/// auto-deleted.
#[must_use]
pub fn is_unmodified_temp(&self) -> bool {
if !matches!(self.kind, ProjectKind::Temp) {
return false;
}
let yaml_path = self.path.join(PROJECT_YAML);
let Ok(body) = fs::read_to_string(&yaml_path) else {
return false;
};
let Ok(snapshot) = crate::persistence::parse_schema(&body) else {
return false;
};
snapshot.tables.is_empty() && snapshot.relationships.is_empty()
}
/// Path to the SQLite database for this project. Always
/// `<project>/playground.db`.
#[must_use]