helwasm: hierarchical quick-gen, pure sugar over the engine

Quick form now drives the one shared engine through commands only, so it and the
console give identical results (form == console).

- password hook answers only the "/" prompt, so read_master climbs and computes
  every ^parent from a single root master (Req 4)
- new master in the field is authoritative via `unpass`; empty field reuses the
  stored session master, so later names generate without re-typing it (Req 1/2)
- `unpass` with no name now clears ALL cached masters (real command, not a private
  hook) so the form stays reproducible in the console
- result colour = root master marked correct (correct / / uncorrect /), derived
  live from the engine; black otherwise (Req 3)
- Mark-correct toggle button; click the master to reveal it; honest memory-only hint
- master stays in memory only, never written to storage; only the one-way correct
  hash is saved on the device

parser: bare-name forms now keep a trailing comment, and a ^-led token is never a
name, so `name ^parent` / `name MODE ^parent` link the parent instead of qpname
reading it as prefix+name (was silently mis-stored).
This commit is contained in:
Oleksandr Kozachuk
2026-06-09 22:45:44 +02:00
parent e25746d5f0
commit 10a21d1f9d
6 changed files with 130 additions and 41 deletions
+6 -2
View File
@@ -133,10 +133,14 @@ impl<'a> LKEval<'a> {
Command::Set(key, value) => { to_history = false; self.cmd_set(&out, key, value); }
Command::Pass(name, None) => self.cmd_pass(&out, &name, &None),
Command::Pass(name, pass) => { to_history = false; self.cmd_pass(&out, &name, &pass); },
Command::UnPass(name) => match self.state.lock().borrow_mut().secrets.remove(name) {
Command::UnPass(Some(name)) => match self.state.lock().borrow_mut().secrets.remove(name) {
Some(_) => out.o(format!("Removed saved password for {}", name)),
None => out.e(format!("error: saved password for {} not found", name)),
},
Command::UnPass(None) => {
self.state.lock().borrow_mut().secrets.clear();
out.o("forgot all cached masters".to_string());
},
Command::Correct(name) => self.cmd_correct(&out, name, true, None),
Command::Uncorrect(name) => self.cmd_correct(&out, name, false, None),
Command::Noop => { to_history = false; },
@@ -156,7 +160,7 @@ impl<'a> LKEval<'a> {
" enc <name> show the generated password\n",
" gen[N] <name> N numbered variants; name ends in G.. (all) or X.. (random)\n",
" pass <name> [pw] cache a master / override for an entry's subtree\n",
" unpass <name> forget a cached password (unpass / = the root master)\n",
" unpass [name] forget a cached password (unpass / = root; unpass = all)\n",
" correct <name> trust this password's hash uncorrect <name> untrust it\n",
"\n",
"catalog\n",