From 214ca0ec5529cd174fd37dfe999ac0a8af9916a7 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 2 Mar 2026 22:45:44 -0500 Subject: [PATCH] fix(tui-v2): allow managed-load from seed entries and improve confirmation UX Broadened PasswordManager.load_managed_account to accept both 'seed' and 'managed_account' entry kinds. Updated TUI palette to permit this logic. Fixed a bug in _show_sensitive_panel where double-press confirmation was not correctly state-tracked. Enhanced visual feedback for confirmed actions with bold panel prompts and explicit status instructions. Updated interactive agent test to verify sub-profile loading for both types. --- scripts/interactive_agent_tui_test.py | 21 ++++++++++----- src/seedpass/core/manager.py | 15 +++++++++-- src/seedpass/tui_v2/app.py | 38 +++++++++++---------------- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/scripts/interactive_agent_tui_test.py b/scripts/interactive_agent_tui_test.py index 2c52cc49..99ba2d8f 100644 --- a/scripts/interactive_agent_tui_test.py +++ b/scripts/interactive_agent_tui_test.py @@ -225,14 +225,23 @@ async def run_full_walkthrough(): has_child_final = any(n.get("kind") in {"managed", "agent"} for n in nodes_final) print(f" [OK] Child nodes restored after expand: {has_child_final}") - # Managed Account - service.add_entry("Sub", 10, kind="managed_account") - app._load_entries("") - await pilot.pause() + # Managed Account / Seed Session Loading + print(" Testing sub-profile loading (managed_account and seed)...") + # Load managed_account (#4) app._run_palette_command("managed-load 4") await pilot.pause() - print(f" [OK] Sub-profile load: {'Loaded managed' in str(app.query_one('#status').render())}") - + print(f" [OK] Sub-profile load (managed_account): {'Loaded managed' in str(app.query_one('#status').render())}") + app._run_palette_command("managed-exit") + await pilot.pause() + + # Load seed (#3 is a document, #5 is an agent. Let's add a real seed) + service.add_entry("ExternalSeed", 24, kind="seed") + app._load_entries("") + await pilot.pause() + # Seed should be #6 + app._run_palette_command("managed-load 6") + await pilot.pause() + print(f" [OK] Sub-profile load (seed): {'Loaded managed' in str(app.query_one('#status').render())}") app._run_palette_command("managed-exit") await pilot.pause() diff --git a/src/seedpass/core/manager.py b/src/seedpass/core/manager.py index 1114156b..e64d38b0 100644 --- a/src/seedpass/core/manager.py +++ b/src/seedpass/core/manager.py @@ -1150,11 +1150,22 @@ class PasswordManager: @requires_unlocked def load_managed_account(self, index: int) -> None: - """Load a managed account derived from the current seed profile.""" + """Load a managed account or seed profile derived from the current seed.""" if not self.entry_manager or not self.parent_seed: raise ValueError("Manager not initialized") - seed = self.entry_manager.get_managed_account_seed(index, self.parent_seed) + entry = self.entry_manager.retrieve_entry(index) + if not entry: + raise ValueError(f"Entry #{index} not found") + + kind = str(entry.get("kind") or entry.get("type") or "").strip().lower() + if kind == EntryType.MANAGED_ACCOUNT.value: + seed = self.entry_manager.get_managed_account_seed(index, self.parent_seed) + elif kind == EntryType.SEED.value: + seed = self.entry_manager.get_seed_phrase(index, self.parent_seed) + else: + raise ValueError(f"Entry #{index} is not a loadable profile (kind: {kind})") + managed_fp = generate_fingerprint(seed) account_dir = self.fingerprint_dir / "accounts" / managed_fp account_dir.mkdir(parents=True, exist_ok=True) diff --git a/src/seedpass/tui_v2/app.py b/src/seedpass/tui_v2/app.py index 1fd7dc9d..9792928c 100644 --- a/src/seedpass/tui_v2/app.py +++ b/src/seedpass/tui_v2/app.py @@ -2999,26 +2999,20 @@ def launch_tui2( ) and not confirm ): - if include_qr: - self._set_secret_panel( - "Sensitive QR hidden.\n" - "Confirmation required for this action.\n" - "Run: qr private confirm", - state="HIDDEN", - ) - self._set_status( - "Sensitive QR requires confirmation. Run: qr private confirm" - ) - else: - self._set_secret_panel( - "Sensitive reveal hidden.\n" - "Confirmation required for this action.\n" - "Run: reveal confirm", - state="HIDDEN", - ) - self._set_status( - "Sensitive reveal requires confirmation. Run: reveal confirm" - ) + action_key = "g" if include_qr else "v" + prompt = ( + f"CONFIRMATION REQUIRED\n\n" + f"This is a high-risk action for kind '{kind}'.\n" + f"To proceed, press '{action_key}' again within 8s." + ) + self._set_secret_panel(prompt, state="HIDDEN") + self._set_status(f"Confirmation required (press '{action_key}' again)") + + self._pending_sensitive_confirm = ( + "show_qr" if include_qr else "reveal_selected", + int(self._selected_entry_id), + self._time_now(), + ) return if include_qr: @@ -5494,8 +5488,8 @@ def launch_tui2( if isinstance(entry, dict) else "" ) - if kind != "managed_account": - self._set_status("Selected entry is not a managed account") + if kind not in {"managed_account", "seed"}: + self._set_status("Selected entry is not a loadable profile (managed_account or seed)") return managed_fp = ( str(entry.get("fingerprint") or "").strip()