diff --git a/demo/try-mri.cast b/demo/try-mri.cast new file mode 100644 index 0000000..b8decd9 --- /dev/null +++ b/demo/try-mri.cast @@ -0,0 +1,28 @@ +{"version": 2, "width": 80, "height": 24, "timestamp": 1786656048, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}, "title": "try (MRI)"} +[0.097872, "o", "\u001b[?1049h\u001b]2;try\u0007\u001b[1 q"] +[0.102897, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-tui-input 1d ago, 2.6\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-10\u001b[39m\u001b[38;5;245m-\u001b[39mspinel-aot \u001b[38;5;245m3d ago, 2.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39mtui-preview \u001b[38;5;245m5d ago, 2.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-05\u001b[39m\u001b[38;5;245m-\u001b[39mnative-compile \u001b[38;5;245m1w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-01\u001b[39m\u001b[38;5;245m-\u001b[39mredis-cache \u001b[38;5;245m1w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-07-28\u001b[39m\u001b[38;5;245m-\u001b[39mfuzzy-finder \u001b[38;5;245m2w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-07-15\u001b[39m\u001b[38;5;245m-\u001b[39mgraphql-api \u001b[38;5;245m4w ago, 2.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-06-20\u001b[39m\u001b[38;5;245m-\u001b[39mold-prototype \u001b[38;5;245m7w ago, 2.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;9H\u001b[?25h\u001b[0m"] +[1.382594, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39ms\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33ms\u001b[39m\u001b[22m\u001b[38;5;255mpinel-aot 3d ago, 0.1\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-01\u001b[39m\u001b[38;5;245m-\u001b[39mredi\u001b[1;33ms\u001b[39m\u001b[22m-cache \u001b[38;5;245m1w ago, 0.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-s \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;10H\u001b[?25h\u001b[0m"] +[1.60465, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msp\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33msp\u001b[39m\u001b[22m\u001b[38;5;255minel-aot 3d ago, 0.4\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-sp \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;11H\u001b[?25h\u001b[0m"] +[1.830053, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mspi\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspi\u001b[39m\u001b[22m\u001b[38;5;255mnel-aot 3d ago, 0.7\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spi \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[2.052565, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mspin\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspin\u001b[39m\u001b[22m\u001b[38;5;255mel-aot 3d ago, 1.1\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;13H\u001b[?25h\u001b[0m"] +[3.039341, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mspi\u001b[7mn\u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspin\u001b[39m\u001b[22m\u001b[38;5;255mel-aot 3d ago, 1.1\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[3.321995, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msp\u001b[7mi\u001b[27mn \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspin\u001b[39m\u001b[22m\u001b[38;5;255mel-aot 3d ago, 1.1\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;11H\u001b[?25h\u001b[0m"] +[3.605755, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39ms\u001b[7mp\u001b[27min \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspin\u001b[39m\u001b[22m\u001b[38;5;255mel-aot 3d ago, 1.1\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;10H\u001b[?25h\u001b[0m"] +[4.230086, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msx\u001b[7mp\u001b[27min \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;11H\u001b[?25h\u001b[0m"] +[5.095529, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msxpin\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;14H\u001b[?25h\u001b[0m"] +[5.800336, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39m\u001b[7ms\u001b[27mxpin \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;9H\u001b[?25h\u001b[0m"] +[6.504639, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msxpin\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;14H\u001b[?25h\u001b[0m"] +[7.149809, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msxpi\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpi \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;13H\u001b[?25h\u001b[0m"] +[7.915179, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-tui-input 1d ago, 2.6\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-10\u001b[39m\u001b[38;5;245m-\u001b[39mspinel-aot \u001b[38;5;245m3d ago, 2.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39mtui-preview \u001b[38;5;245m5d ago, 2.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-05\u001b[39m\u001b[38;5;245m-\u001b[39mnative-compile \u001b[38;5;245m1w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-01\u001b[39m\u001b[38;5;245m-\u001b[39mredis-cache \u001b[38;5;245m1w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-07-28\u001b[39m\u001b[38;5;245m-\u001b[39mfuzzy-finder \u001b[38;5;245m2w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-07-15\u001b[39m\u001b[38;5;245m-\u001b[39mgraphql-api \u001b[38;5;245m4w ago, 2.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-06-20\u001b[39m\u001b[38;5;245m-\u001b[39mold-prototype \u001b[38;5;245m7w ago, 2.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;9H\u001b[?25h\u001b[0m"] +[8.841754, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mt\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mt\u001b[39m\u001b[22m\u001b[38;5;255mui-input 1d ago, 0.1\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mt\u001b[39m\u001b[22mui-preview \u001b[38;5;245m5d ago, 0.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-05\u001b[39m\u001b[38;5;245m-\u001b[39mna\u001b[1;33mt\u001b[39m\u001b[22mive-compile \u001b[38;5;245m1w ago, 0.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-10\u001b[39m\u001b[38;5;245m-\u001b[39mspinel-ao\u001b[1;33mt\u001b[39m\u001b[22m \u001b[38;5;245m3d ago, 0.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-06-20\u001b[39m\u001b[38;5;245m-\u001b[39mold-pro\u001b[1;33mt\u001b[39m\u001b[22motype \u001b[38;5;245m7w ago, 0.0\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-t \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;10H\u001b[?25h\u001b[0m"] +[9.06559, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtu\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtu\u001b[39m\u001b[22m\u001b[38;5;255mi-input 1d ago, 0.4\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtu\u001b[39m\u001b[22mi-preview \u001b[38;5;245m5d ago, 0.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tu \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;11H\u001b[?25h\u001b[0m"] +[9.288073, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-input 1d ago, 0.8\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-preview \u001b[38;5;245m5d ago, 0.7\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[10.295378, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-12\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-input \u001b[38;5;245m1d ago, 0.8\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-08-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-preview 5d ago, 0.7\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[11.101121, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-input 1d ago, 0.8\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-preview \u001b[38;5;245m5d ago, 0.7\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[11.806595, "o", "\u001b[H\r\u001b[K ✏️\u001b[1;38;5;214m Rename directory\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K📁 2026-08-12-tui-input \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[38;5;245mNew name: \u001b[39m2026-08-12-tui-input\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245mEnter: Confirm Esc: Cancel\u001b[39m \u001b[0m\u001b[6;55H\u001b[?25h\u001b[0m"] +[12.854081, "o", "\u001b[H\r\u001b[K ✏️\u001b[1;38;5;214m Rename directory\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K📁 2026-08-12-tui-input \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[38;5;245mNew name: \u001b[39m2026-08-12-tui-inpu\u001b[7mt\u001b[27m \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245mEnter: Confirm Esc: Cancel\u001b[39m \u001b[0m\u001b[6;54H\u001b[?25h\u001b[0m"] +[13.136497, "o", "\u001b[H\r\u001b[K ✏️\u001b[1;38;5;214m Rename directory\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K📁 2026-08-12-tui-input \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[38;5;245mNew name: \u001b[39m2026-08-12-tui-inp\u001b[7mu\u001b[27mt \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245mEnter: Confirm Esc: Cancel\u001b[39m \u001b[0m\u001b[6;53H\u001b[?25h\u001b[0m"] +[13.419213, "o", "\u001b[H\r\u001b[K ✏️\u001b[1;38;5;214m Rename directory\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K📁 2026-08-12-tui-input \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[38;5;245mNew name: \u001b[39m2026-08-12-tui-in\u001b[7mp\u001b[27mut \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245mEnter: Confirm Esc: Cancel\u001b[39m \u001b[0m\u001b[6;52H\u001b[?25h\u001b[0m"] +[14.185162, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-input 1d ago, 0.8\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-preview \u001b[38;5;245m5d ago, 0.7\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m\u001b[2J\u001b[H"] +[14.185547, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-input 1d ago, 0.8\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-preview \u001b[38;5;245m5d ago, 0.7\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[15.254532, "o", "\u001b[0m\u001b[0 q\u001b[?1049lCancelled.\r\r\n"] diff --git a/demo/try-mri.gif b/demo/try-mri.gif new file mode 100644 index 0000000..ee4b3b7 Binary files /dev/null and b/demo/try-mri.gif differ diff --git a/demo/try-native.cast b/demo/try-native.cast new file mode 100644 index 0000000..f52e88d --- /dev/null +++ b/demo/try-native.cast @@ -0,0 +1,28 @@ +{"version": 2, "width": 80, "height": 24, "timestamp": 1786656068, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}, "title": "try (native / Spinel)"} +[0.021262, "o", "\u001b[?1049h\u001b]2;try\u0007\u001b[1 q"] +[0.025619, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-tui-input 1d ago, 2.6\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-10\u001b[39m\u001b[38;5;245m-\u001b[39mspinel-aot \u001b[38;5;245m3d ago, 2.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39mtui-preview \u001b[38;5;245m5d ago, 2.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-05\u001b[39m\u001b[38;5;245m-\u001b[39mnative-compile \u001b[38;5;245m1w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-01\u001b[39m\u001b[38;5;245m-\u001b[39mredis-cache \u001b[38;5;245m1w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-07-28\u001b[39m\u001b[38;5;245m-\u001b[39mfuzzy-finder \u001b[38;5;245m2w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-07-15\u001b[39m\u001b[38;5;245m-\u001b[39mgraphql-api \u001b[38;5;245m4w ago, 2.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-06-20\u001b[39m\u001b[38;5;245m-\u001b[39mold-prototype \u001b[38;5;245m7w ago, 2.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;9H\u001b[?25h\u001b[0m"] +[1.304534, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39ms\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33ms\u001b[39m\u001b[22m\u001b[38;5;255mpinel-aot 3d ago, 0.1\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-01\u001b[39m\u001b[38;5;245m-\u001b[39mredi\u001b[1;33ms\u001b[39m\u001b[22m-cache \u001b[38;5;245m1w ago, 0.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-s \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;10H\u001b[?25h\u001b[0m"] +[1.526794, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msp\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33msp\u001b[39m\u001b[22m\u001b[38;5;255minel-aot 3d ago, 0.4\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-sp \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;11H\u001b[?25h\u001b[0m"] +[1.749043, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mspi\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspi\u001b[39m\u001b[22m\u001b[38;5;255mnel-aot 3d ago, 0.7\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spi \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[1.971254, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mspin\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspin\u001b[39m\u001b[22m\u001b[38;5;255mel-aot 3d ago, 1.1\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;13H\u001b[?25h\u001b[0m"] +[2.958201, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mspi\u001b[7mn\u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspin\u001b[39m\u001b[22m\u001b[38;5;255mel-aot 3d ago, 1.1\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[3.241012, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msp\u001b[7mi\u001b[27mn \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspin\u001b[39m\u001b[22m\u001b[38;5;255mel-aot 3d ago, 1.1\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;11H\u001b[?25h\u001b[0m"] +[3.523437, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39ms\u001b[7mp\u001b[27min \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-10-\u001b[1;33mspin\u001b[39m\u001b[22m\u001b[38;5;255mel-aot 3d ago, 1.1\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-spin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;10H\u001b[?25h\u001b[0m"] +[4.148608, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msx\u001b[7mp\u001b[27min \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;11H\u001b[?25h\u001b[0m"] +[5.014433, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msxpin\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;14H\u001b[?25h\u001b[0m"] +[5.719059, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39m\u001b[7ms\u001b[27mxpin \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;9H\u001b[?25h\u001b[0m"] +[6.424539, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msxpin\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpin \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;14H\u001b[?25h\u001b[0m"] +[7.069593, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39msxpi\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📂 Create new: 2026-08-13-sxpi \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;13H\u001b[?25h\u001b[0m"] +[7.835563, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-tui-input 1d ago, 2.6\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-10\u001b[39m\u001b[38;5;245m-\u001b[39mspinel-aot \u001b[38;5;245m3d ago, 2.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39mtui-preview \u001b[38;5;245m5d ago, 2.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-05\u001b[39m\u001b[38;5;245m-\u001b[39mnative-compile \u001b[38;5;245m1w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-01\u001b[39m\u001b[38;5;245m-\u001b[39mredis-cache \u001b[38;5;245m1w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-07-28\u001b[39m\u001b[38;5;245m-\u001b[39mfuzzy-finder \u001b[38;5;245m2w ago, 2.2\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-07-15\u001b[39m\u001b[38;5;245m-\u001b[39mgraphql-api \u001b[38;5;245m4w ago, 2.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-06-20\u001b[39m\u001b[38;5;245m-\u001b[39mold-prototype \u001b[38;5;245m7w ago, 2.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;9H\u001b[?25h\u001b[0m"] +[8.762194, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mt\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mt\u001b[39m\u001b[22m\u001b[38;5;255mui-input 1d ago, 0.1\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mt\u001b[39m\u001b[22mui-preview \u001b[38;5;245m5d ago, 0.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-05\u001b[39m\u001b[38;5;245m-\u001b[39mna\u001b[1;33mt\u001b[39m\u001b[22mive-compile \u001b[38;5;245m1w ago, 0.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-10\u001b[39m\u001b[38;5;245m-\u001b[39mspinel-ao\u001b[1;33mt\u001b[39m\u001b[22m \u001b[38;5;245m3d ago, 0.1\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-06-20\u001b[39m\u001b[38;5;245m-\u001b[39mold-pro\u001b[1;33mt\u001b[39m\u001b[22motype \u001b[38;5;245m7w ago, 0.0\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-t \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;10H\u001b[?25h\u001b[0m"] +[8.984046, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtu\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtu\u001b[39m\u001b[22m\u001b[38;5;255mi-input 1d ago, 0.4\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtu\u001b[39m\u001b[22mi-preview \u001b[38;5;245m5d ago, 0.3\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tu \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;11H\u001b[?25h\u001b[0m"] +[9.206147, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-input 1d ago, 0.8\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-preview \u001b[38;5;245m5d ago, 0.7\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[10.212177, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-12\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-input \u001b[38;5;245m1d ago, 0.8\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-08-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-preview 5d ago, 0.7\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[11.017508, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-input 1d ago, 0.8\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-preview \u001b[38;5;245m5d ago, 0.7\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[11.722008, "o", "\u001b[H\r\u001b[K ✏️\u001b[1;38;5;214m Rename directory\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K📁 2026-08-12-tui-input \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[38;5;245mNew name: \u001b[39m2026-08-12-tui-input\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245mEnter: Confirm Esc: Cancel\u001b[39m \u001b[0m\u001b[6;55H\u001b[?25h\u001b[0m"] +[12.769142, "o", "\u001b[H\r\u001b[K ✏️\u001b[1;38;5;214m Rename directory\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K📁 2026-08-12-tui-input \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[38;5;245mNew name: \u001b[39m2026-08-12-tui-inpu\u001b[7mt\u001b[27m \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245mEnter: Confirm Esc: Cancel\u001b[39m \u001b[0m\u001b[6;54H\u001b[?25h\u001b[0m"] +[13.051582, "o", "\u001b[H\r\u001b[K ✏️\u001b[1;38;5;214m Rename directory\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K📁 2026-08-12-tui-input \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[38;5;245mNew name: \u001b[39m2026-08-12-tui-inp\u001b[7mu\u001b[27mt \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245mEnter: Confirm Esc: Cancel\u001b[39m \u001b[0m\u001b[6;53H\u001b[?25h\u001b[0m"] +[13.333821, "o", "\u001b[H\r\u001b[K ✏️\u001b[1;38;5;214m Rename directory\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K📁 2026-08-12-tui-input \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K \u001b[38;5;245mNew name: \u001b[39m2026-08-12-tui-in\u001b[7mp\u001b[27mut \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245mEnter: Confirm Esc: Cancel\u001b[39m \u001b[0m\u001b[6;52H\u001b[?25h\u001b[0m"] +[14.099442, "o", "\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-input 1d ago, 0.8\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-preview \u001b[38;5;245m5d ago, 0.7\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m\u001b[2J\u001b[H\u001b[H\r\u001b[K🏠\u001b[1;38;5;214m Try Directory Selection\u001b[39m\u001b[22m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[38;5;245mSearch: \u001b[39mtui\u001b[7m \u001b[27m \u001b[0m\r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K\u001b[48;5;238m\u001b[38;5;255m\u001b[1;33m→ \u001b[39m\u001b[22m\u001b[38;5;255m📁 2026-08-12-\u001b[1;33mtui\u001b[39m\u001b[22m\u001b[38;5;255m-input 1d ago, 0.8\u001b[39m\u001b[0m\r\n\r\u001b[K 📁 \u001b[38;5;245m2026-08-08\u001b[39m\u001b[38;5;245m-\u001b[39m\u001b[1;33mtui\u001b[39m\u001b[22m-preview \u001b[38;5;245m5d ago, 0.7\u001b[39m\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[0m\r\n\r\u001b[K 📂 Create new: 2026-08-13-tui "] +[14.099508, "o", " \u001b[0m\r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K \r\n\r\u001b[K\u001b[38;5;245m───────────────────────────────────────────────────────────────────────────────\u001b[39m\u001b[0m\r\n\r\u001b[K \u001b[38;5;245m↑/↓: Navigate Enter: Select ^R: Rename ^G: Graduate ^D: Delete Esc: C… \u001b[0m\u001b[3;12H\u001b[?25h\u001b[0m"] +[15.168194, "o", "\u001b[0m\u001b[0 q\u001b[?1049lCancelled.\r\r\n"] diff --git a/demo/try-native.gif b/demo/try-native.gif new file mode 100644 index 0000000..e05e520 Binary files /dev/null and b/demo/try-native.gif differ diff --git a/lib/tui.rb b/lib/tui.rb index efc2cde..55d6f48 100644 --- a/lib/tui.rb +++ b/lib/tui.rb @@ -811,13 +811,140 @@ def apply_style(text, style) end class InputField - attr_accessor :text, :cursor - attr_reader :placeholder + attr_reader :placeholder, :text, :cursor - def initialize(placeholder:, text:, cursor: nil) + def initialize(placeholder: "", text: "", cursor: nil) @placeholder = placeholder @text = text.to_s.dup - @cursor = cursor.nil? ? @text.length : [[cursor, 0].max, @text.length].min + @cursor = cursor.nil? ? @text.length : cursor.to_i + clamp_cursor! + end + + def text=(value) + @text = value.to_s.dup + clamp_cursor! + end + + def cursor=(pos) + @cursor = pos.to_i + clamp_cursor! + end + + # Returns true if consumed as text-editing, false if the selector should handle it. + def handle_key(key) + return false if key.nil? || key.empty? + + case key + when "\x7F", "\x08" + backspace + true + when "\e[3~" + delete_forward + true + when "\x01" + cursor_home + true + when "\x05" + cursor_end + true + when "\x02" + cursor_left + true + when "\x06" + cursor_right + true + when "\x0B" + kill_to_end + true + when "\x15" + kill_to_start + true + when "\x17" + kill_word + true + else + if left_arrow?(key) + cursor_left + true + elsif right_arrow?(key) + cursor_right + true + elsif home_key?(key) + cursor_home + true + elsif end_key?(key) + cursor_end + true + elsif key.length == 1 + code = key.ord + if code >= 32 && code != 127 + insert(key) + true + else + false + end + else + false + end + end + end + + def insert(ch) + s = ch.to_s + return if s.empty? + @text = @text[0...@cursor].to_s + s + @text[@cursor..].to_s + @cursor += 1 + end + + def backspace + return if @cursor <= 0 + @text = @text[0...(@cursor - 1)].to_s + @text[@cursor..].to_s + @cursor -= 1 + end + + def delete_forward + return if @cursor >= @text.length + @text = @text[0...@cursor].to_s + @text[(@cursor + 1)..].to_s + end + + def kill_to_end + @text = @text[0...@cursor].to_s + end + + def kill_to_start + @text = @text[@cursor..].to_s + @cursor = 0 + end + + def kill_word + return if @cursor <= 0 + new_pos = word_boundary_backward(@text, @cursor) + @text = @text[0...new_pos].to_s + @text[@cursor..].to_s + @cursor = new_pos + end + + def cursor_left + @cursor -= 1 if @cursor > 0 + end + + def cursor_right + @cursor += 1 if @cursor < @text.length + end + + def cursor_home + @cursor = 0 + end + + def cursor_end + @cursor = @text.length + end + + # Alphanumeric word boundary (Ctrl-W). Skips separators, then the word. + def word_boundary_backward(buffer, cursor) + pos = cursor - 1 + pos -= 1 while pos >= 0 && !alnum_char?(buffer[pos]) + pos -= 1 while pos >= 0 && alnum_char?(buffer[pos]) + pos + 1 end def to_s @@ -841,5 +968,36 @@ def to_s def render_placeholder Text.dim(placeholder) end + + def clamp_cursor! + @cursor = 0 if @cursor < 0 + @cursor = @text.length if @cursor > @text.length + end + + # Avoid Regexp#match? on control bytes (Spinel can SIGSEGV). + def alnum_char?(ch) + return false if ch.nil? || ch.empty? + c = ch.ord + (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122) + end + + def left_arrow?(key) + return true if key == "\e[D" || key == "\eOD" + key.start_with?("\e[") && key.end_with?("D") && key.length > 3 + end + + def right_arrow?(key) + return true if key == "\e[C" || key == "\eOC" + key.start_with?("\e[") && key.end_with?("C") && key.length > 3 + end + + def home_key?(key) + key == "\e[H" || key == "\e[1~" || key == "\e[7~" || key == "\eOH" + end + + def end_key?(key) + key == "\e[F" || key == "\e[4~" || key == "\e[8~" || key == "\eOF" + end end + end diff --git a/spec/tests/test_08_keyboard.sh b/spec/tests/test_08_keyboard.sh index fe3ca97..a77fec3 100644 --- a/spec/tests/test_08_keyboard.sh +++ b/spec/tests/test_08_keyboard.sh @@ -133,3 +133,21 @@ if echo "$output" | grep -q "hello.*beta"; then else fail "Ctrl-W should stop at dash (delete only world)" "hello.*beta in output" "$output" "tui_spec.md#keyboard-input" fi + +# Test: Left arrow moves cursor in the search box +# Type "beta", Left, Left, insert "X" => "beXta" (create-new path) +output=$(try_run --path="$TEST_TRIES" --and-keys="beta"$'\x1b[D\x1b[D'"X"$'\r' exec 2>/dev/null) +if echo "$output" | grep -q "beXta"; then + pass +else + fail "left arrow should move search cursor" "beXta in output" "$output" "tui_spec.md#keyboard-input" +fi + +# Test: Ctrl-U kills to start of line +# Type "xxx", Ctrl-U (cursor at end, clears all), type "beta" +output=$(try_run --path="$TEST_TRIES" --and-keys="xxx"$'\x15'"beta"$'\r' exec 2>/dev/null) +if echo "$output" | grep -E "(touch|mkdir|cd) " | grep -q "beta" && ! echo "$output" | grep -E "(touch|mkdir|cd) " | grep -q "xxx"; then + pass +else + fail "Ctrl-U should kill to start of line" "beta without xxx" "$output" "tui_spec.md#keyboard-input" +fi diff --git a/spec/tests/test_19_input_field.sh b/spec/tests/test_19_input_field.sh index a64e74a..d9a97e0 100644 --- a/spec/tests/test_19_input_field.sh +++ b/spec/tests/test_19_input_field.sh @@ -35,12 +35,14 @@ output=$(try_run --path="$TEST_TRIES" --and-exit --and-keys="ab,BACKSPACE,BACKSP # Input should be empty or show placeholder pass # Hard to verify empty input, just ensure no crash -# Test: Cursor position updates with arrow keys (if supported) -# Left arrow should move cursor within input -output=$(try_run --path="$TEST_TRIES" --and-exit --and-keys="abc,LEFT,LEFT,d" exec 2>&1) -# Typing 'd' after moving left twice should insert in middle -# Result could be "adbc" if insert mode works -pass # Implementation-dependent +# Test: Left/Right arrows move the search-box cursor (insert in the middle) +output=$(try_run --path="$TEST_TRIES" --and-exit --and-keys="TYPE=abc,LEFT,LEFT,d" exec 2>&1) +stripped=$(echo "$output" | strip_ansi) +if echo "$stripped" | grep -q "adbc"; then + pass +else + fail "left arrow should move cursor so d inserts in the middle" "adbc in search" "$output" "tui_spec.md#line-editing" +fi # Test: Input accepts spaces output=$(try_run --path="$TEST_TRIES" --and-exit --and-keys="a b" exec 2>&1) @@ -71,10 +73,15 @@ else pass # As long as no crash fi -# Test: Ctrl-U clears input line -output=$(try_run --path="$TEST_TRIES" --and-exit --and-keys="testing,CTRL-U" exec 2>&1) -# After Ctrl-U, "testing" should not appear in search line -pass # Implementation-dependent, just verify no crash +# Test: Ctrl-U clears from start of line to cursor (cursor at end => clear all) +output=$(try_run --path="$TEST_TRIES" --and-exit --and-keys="TYPE=testing,CTRL-U" exec 2>&1) +stripped=$(echo "$output" | strip_ansi) +search_line=$(echo "$stripped" | grep "Search:" | tail -1) +if echo "$search_line" | grep -q "testing"; then + fail "Ctrl-U should clear the search text" "no testing on Search: line" "$search_line" "tui_spec.md#line-editing" +else + pass +fi # Test: Empty input shows all entries output=$(try_run --path="$TEST_TRIES" --and-exit exec 2>&1) diff --git a/spec/tui_spec.md b/spec/tui_spec.md index b5a9384..8ae787e 100644 --- a/spec/tui_spec.md +++ b/spec/tui_spec.md @@ -217,14 +217,16 @@ Tokens are preserved intact - never split a `{b}...{/b}` pair. ### Line Editing (in search input) | Key | Action | |-----|--------| -| Ctrl-A | Move cursor to beginning of line | -| Ctrl-E | Move cursor to end of line | -| Ctrl-B | Move cursor backward one character | -| Ctrl-F | Move cursor forward one character | +| Ctrl-A / Home | Move cursor to beginning of line | +| Ctrl-E / End | Move cursor to end of line | +| Ctrl-B / Left arrow | Move cursor backward one character | +| Ctrl-F / Right arrow | Move cursor forward one character | | Backspace / Ctrl-H | Delete character before cursor | +| Delete | Delete character after cursor | | Ctrl-K | Delete from cursor to end of line | +| Ctrl-U | Delete from start of line to cursor | | Ctrl-W | Delete word before cursor (alphanumeric boundaries) | -| Any printable | Append to query, re-filter | +| Any printable | Insert at cursor, re-filter | ## Scrolling diff --git a/test/try_selector_test.rb b/test/try_selector_test.rb index a6304f8..d0b63a4 100644 --- a/test/try_selector_test.rb +++ b/test/try_selector_test.rb @@ -280,7 +280,7 @@ def test_cache_miss_on_buffer_change FileUtils.mkdir_p(File.join(@tmpdir, "mydir")) sel = build_selector first = sel.send(:get_tries) - sel.instance_variable_set(:@input_buffer, "my") + sel.instance_variable_get(:@search).text = "my" second = sel.send(:get_tries) refute_same first, second end @@ -376,7 +376,7 @@ def test_selected_entry_does_not_use_fixed_muted_foreground def test_selected_create_row_restores_foreground Tui.enable_colors! screen = Tui::Screen.new(io: StringIO.new, width: 80, height: 5) - selector.instance_variable_set(:@input_buffer, "new-entry") + selector.instance_variable_get(:@search).text = "new-entry" selector.send(:render_create_line, screen, true, 80) output = StringIO.new diff --git a/test/tui_input_field_test.rb b/test/tui_input_field_test.rb index 70cbb44..c8f58af 100644 --- a/test/tui_input_field_test.rb +++ b/test/tui_input_field_test.rb @@ -19,3 +19,100 @@ def test_placeholder_dimmed_when_colors_enabled assert_includes field.to_s, Tui::Palette::MUTED end end + +class InputFieldEditingTest < TuiTestCase + def field(text = "hello", cursor = nil) + Tui::InputField.new(placeholder: "", text: text, cursor: cursor) + end + + def test_insert_at_cursor + f = field("abc", 1) + f.insert("X") + assert_equal "aXbc", f.text + assert_equal 2, f.cursor + end + + def test_backspace + f = field("abc", 2) + f.backspace + assert_equal "ac", f.text + assert_equal 1, f.cursor + end + + def test_backspace_at_start_is_noop + f = field("abc", 0) + f.backspace + assert_equal "abc", f.text + assert_equal 0, f.cursor + end + + def test_delete_forward + f = field("abc", 1) + f.delete_forward + assert_equal "ac", f.text + assert_equal 1, f.cursor + end + + def test_kill_to_end + f = field("abcdef", 3) + f.kill_to_end + assert_equal "abc", f.text + assert_equal 3, f.cursor + end + + def test_kill_to_start + f = field("abcdef", 3) + f.kill_to_start + assert_equal "def", f.text + assert_equal 0, f.cursor + end + + def test_kill_word_stops_at_dash + f = field("hello-world") + f.kill_word + assert_equal "hello-", f.text + end + + def test_handle_key_consumes_arrows + f = field("abc", 2) + assert f.handle_key("\e[D") + assert_equal 1, f.cursor + assert f.handle_key("\e[C") + assert_equal 2, f.cursor + end + + def test_handle_key_consumes_ctrl_u + f = field("abc", 2) + assert f.handle_key("\x15") + assert_equal "c", f.text + assert_equal 0, f.cursor + end + + def test_handle_key_consumes_delete_csi + f = field("abc", 1) + assert f.handle_key("\e[3~") + assert_equal "ac", f.text + end + + def test_handle_key_rejects_selector_keys + f = field("abc") + ["\r", "\e", "\x03", "\x04", "\x07", "\x14", "\x10", "\x0E", "\e[A", "\e[B", "\t", "\x12"].each do |key| + refute f.handle_key(key), "should not consume #{key.inspect}" + end + assert_equal "abc", f.text + end + + def test_handle_key_inserts_printable + f = field("", 0) + assert f.handle_key("z") + assert_equal "z", f.text + end + + def test_to_s_still_reverse_video_cursor + enable_colors! + f = field("ab", 1) + rendered = f.to_s + assert_includes rendered, Tui::Palette::INPUT_CURSOR_ON + assert_includes rendered, "b" + end +end diff --git a/try.rb b/try.rb index c3f4540..79a188b 100755 --- a/try.rb +++ b/try.rb @@ -40,15 +40,49 @@ def self.stty_set(state) system("stty #{state} 2>/dev/null") end + @raw_active = false + @alt_active = false + @stty_saved = "" + @restored = false + + def self.mark_alt_screen(on) + @alt_active = on + @restored = false if on + end + + def self.emergency_restore + return if @restored + @restored = true + begin + if @alt_active + STDERR.print("#{Tui::ANSI::RESET}#{Tui::ANSI::CURSOR_DEFAULT}#{Tui::ANSI::SHOW}#{Tui::ANSI::ALT_SCREEN_OFF}") + @alt_active = false + elsif @raw_active + STDERR.print("#{Tui::ANSI::RESET}#{Tui::ANSI::CURSOR_DEFAULT}#{Tui::ANSI::SHOW}") + end + rescue + end + if @raw_active + stty_set(@stty_saved) + @raw_active = false + end + end + def self.with_raw_tty saved = nil if STDIN.tty? saved = stty_save + @stty_saved = saved if @stty_saved.nil? || @stty_saved.empty? system("stty raw -echo 2>/dev/null") + @raw_active = true + @restored = false end yield ensure - stty_set(saved) if saved && !saved.empty? + if saved && !saved.empty? + stty_set(saved) + @raw_active = false + end end def self.with_cooked_tty @@ -90,6 +124,8 @@ def self.self_exec_prefix(script_path) end end +at_exit { TryCompat.emergency_restore } + class TrySelector include Tui::Helpers TRY_PATH = ENV['TRY_PATH'] || File.expand_path("~/src/tries") @@ -102,10 +138,11 @@ class TrySelector def initialize(search_term = "", base_path: TRY_PATH, initial_input: nil, test_render_once: false, test_no_cls: false, test_keys: nil, test_confirm: nil) @search_term = search_term.gsub(/\s+/, '-') @cursor_pos = 0 # Navigation cursor (list position) - @input_cursor_pos = 0 # Text cursor (position within search buffer) @scroll_offset = 0 - @input_buffer = initial_input ? initial_input.gsub(/\s+/, '-') : @search_term - @input_cursor_pos = @input_buffer.length # Start at end of buffer + @search = Tui::InputField.new( + placeholder: "", + text: initial_input ? initial_input.gsub(/\s+/, '-') : @search_term + ) @selected = nil @all_trials = nil # Memoized trials @base_path = base_path.to_s @@ -155,9 +192,11 @@ def run private def setup_terminal + @terminal_restored = false unless @test_no_cls # Switch to alternate screen buffer (like vim, less, etc.) STDERR.print("#{Tui::ANSI::ALT_SCREEN_ON}#{Tui::ANSI.set_title("try")}#{Tui::ANSI::CURSOR_BLINK}") + TryCompat.mark_alt_screen(true) end # Spinel can SIGSEGV restoring a previous WINCH handler on process exit. @@ -167,14 +206,18 @@ def setup_terminal end def restore_terminal + return if @terminal_restored + @terminal_restored = true unless @test_no_cls STDERR.print(Tui::ANSI::RESET) STDERR.print(Tui::ANSI::CURSOR_DEFAULT) # Return to main screen buffer STDERR.print(Tui::ANSI::ALT_SCREEN_OFF) + TryCompat.mark_alt_screen(false) end Signal.trap('WINCH', @old_winch_handler) if @old_winch_handler + TryCompat.stdin_iflush end def load_all_tries @@ -223,14 +266,14 @@ def load_all_tries # Result wrapper to avoid Hash#merge allocation per entry TryEntry = Data.define(:data, :score, :highlight_positions) do - def [](key) - case key - when :score then score - when :highlight_positions then highlight_positions - else data[key] - end - end - + def text; data[:text]; end + def basename; data[:basename]; end + def path; data[:path]; end + def is_new; data[:is_new]; end + def is_symlink; data[:is_symlink]; end + def ctime; data[:ctime]; end + def mtime; data[:mtime]; end + def base_score; data[:base_score]; end end def get_tries @@ -238,15 +281,15 @@ def get_tries @fuzzy ||= Fuzzy.new(@all_tries) # Cache results - only re-match when query changes - if @last_query == @input_buffer && @cached_results + if @last_query == @search.text && @cached_results return @cached_results end - @last_query = @input_buffer + @last_query = @search.text height = Tui::Terminal.size(STDERR)[0] || 24 max_results = [height - 6, 3].max results = [] - @fuzzy.match(@input_buffer).limit(max_results).each do |entry, positions, score| + @fuzzy.match(@search.text).limit(max_results).each do |entry, positions, score| results << TryEntry.new(entry, score, positions) end @cached_results = results @@ -255,7 +298,7 @@ def get_tries def main_loop loop do tries = get_tries - show_create_new = !@input_buffer.empty? + show_create_new = !@search.text.empty? total_items = tries.length + (show_create_new ? 1 : 0) # Ensure cursor is within bounds @@ -267,6 +310,12 @@ def main_loop # nil means terminal resize - just re-render with new dimensions next unless key + before = @search.text + if @search.handle_key(key) + @cursor_pos = 0 if @search.text != before + next + end + case key when "\r" # Enter (carriage return) if @delete_mode && !@marked_for_deletion.empty? @@ -285,35 +334,9 @@ def main_loop @cursor_pos = [@cursor_pos - 1, 0].max when "\e[B", "\x0E" # Down arrow or Ctrl-N @cursor_pos = [@cursor_pos + 1, total_items - 1].min - when "\e[C" # Right arrow - ignore - # Do nothing - when "\e[D" # Left arrow - ignore - # Do nothing - when "\x7F", "\b" # Backspace (DEL and BS) - if @input_cursor_pos > 0 - @input_buffer = @input_buffer[0...(@input_cursor_pos-1)] + @input_buffer[@input_cursor_pos..] - @input_cursor_pos -= 1 - end - @cursor_pos = 0 # Reset list selection when typing - when "\x01" # Ctrl-A - beginning of line - @input_cursor_pos = 0 - when "\x05" # Ctrl-E - end of line - @input_cursor_pos = @input_buffer.length - when "\x02" # Ctrl-B - backward char - @input_cursor_pos = [@input_cursor_pos - 1, 0].max - when "\x06" # Ctrl-F - forward char - @input_cursor_pos = [@input_cursor_pos + 1, @input_buffer.length].min - when "\x0B" # Ctrl-K - kill to end of line - @input_buffer = @input_buffer[0...@input_cursor_pos] - when "\x17" # Ctrl-W - delete word backward (alphanumeric) - if @input_cursor_pos > 0 - new_pos = word_boundary_backward(@input_buffer, @input_cursor_pos) - @input_buffer = @input_buffer[0...new_pos] + @input_buffer[@input_cursor_pos..] - @input_cursor_pos = new_pos - end when "\x04" # Ctrl-D - toggle mark for deletion if @cursor_pos < tries.length - path = tries[@cursor_pos][:path] + path = tries[@cursor_pos].path if @marked_for_deletion.include?(path) @marked_for_deletion.delete(path) else @@ -347,14 +370,6 @@ def main_loop @selected = { type: :cancel } break end - when String - # Only accept printable characters, not escape sequences. - # Guard ord first: Spinel can SIGSEGV on Regexp#match? with ESC/Ctrl chars. - if key.length == 1 && key.ord >= 32 && key.match?(INPUT_CHAR_RE) - @input_buffer = @input_buffer[0...@input_cursor_pos] + key + @input_buffer[@input_cursor_pos..] - @input_cursor_pos += 1 - @cursor_pos = 0 # Reset list selection when typing - end end end @@ -386,10 +401,30 @@ def read_keypress if input == "\e" begin - input << STDIN.read_nonblock(3) - input << STDIN.read_nonblock(2) - rescue IO::WaitReadable, EOFError - # No more escape sequence data available + nxt = STDIN.read_nonblock(1) + input << nxt + if nxt == "[" + # CSI: consume until a final byte in 0x40-0x7E so mouse/unknown + # sequences never leak into the filter. Bare ESC still returns "\e" + # when no following byte is available (WaitReadable). + loop do + ch = STDIN.read_nonblock(1) + input << ch + code = ch.ord + break if code >= 0x40 && code <= 0x7E + end + # X10 mouse: ESC [ M + 3 payload bytes + if input == "\e[M" + begin + input << STDIN.read_nonblock(3) + rescue IO::WaitReadable, EOFError, Errno::EAGAIN, Errno::EWOULDBLOCK + end + end + elsif nxt == "O" + input << STDIN.read_nonblock(1) + end + rescue IO::WaitReadable, EOFError, Errno::EAGAIN, Errno::EWOULDBLOCK + # Standalone ESC (or incomplete sequence) — keep what we have end end @@ -420,7 +455,7 @@ def render(tries) line = screen.header.add_line prefix = "Search: " line.write.write_dim(prefix) - line.write.write(screen.input("", value: @input_buffer, cursor: @input_cursor_pos).to_s) + line.write.write(screen.input("", value: @search.text, cursor: @search.cursor).to_s) line.mark_has_input(Tui::Metrics.visible_width(prefix)) line = screen.header.add_line line.write.write_dim(fill("─")) @@ -445,7 +480,7 @@ def render(tries) header_lines = screen.header.lines.length footer_lines = screen.footer.lines.length max_visible = [height - header_lines - footer_lines, 3].max - show_create_new = !@input_buffer.empty? + show_create_new = !@search.text.empty? total_items = tries.length + (show_create_new ? 1 : 0) if @cursor_pos < @scroll_offset @@ -472,7 +507,7 @@ def render(tries) end def render_entry_line(screen, entry, is_selected, width) - is_marked = @marked_for_deletion.include?(entry[:path]) + is_marked = @marked_for_deletion.include?(entry.path) # Marked items keep the danger background; selected rows add a readable foreground. background = if is_marked Tui::Palette::DANGER_BG + (is_selected ? Tui::Palette::SELECTED_FG : "") @@ -484,7 +519,7 @@ def render_entry_line(screen, entry, is_selected, width) line.write.write((is_selected ? Tui::Text.highlight("→ ") + selected_foreground : " ")) icon = if is_marked emoji("🗑️") - elsif entry[:is_symlink] + elsif entry.is_symlink emoji("🔗") else emoji("📁") @@ -493,7 +528,7 @@ def render_entry_line(screen, entry, is_selected, width) plain_name, rendered_name = formatted_entry_name(entry, selected: is_selected) prefix_width = 5 - meta_text = "#{format_relative_time(entry[:mtime])}, #{format('%.1f', entry[:score])}" + meta_text = "#{format_relative_time(entry.mtime)}, #{format('%.1f', entry.score)}" # Only truncate name if it exceeds total line width (not to make room for metadata) max_name_width = width - prefix_width - 1 @@ -516,17 +551,17 @@ def render_create_line(screen, is_selected, width) line = screen.body.add_line(background) line.write.write((is_selected ? Tui::Text.highlight("→ ") + selected_foreground : " ")) date_prefix = Time.now.strftime("%Y-%m-%d") - label = if @input_buffer.empty? + label = if @search.text.empty? "📂 Create new: #{date_prefix}-" else - "📂 Create new: #{date_prefix}-#{@input_buffer}" + "📂 Create new: #{date_prefix}-#{@search.text}" end line.write.write(label) end def formatted_entry_name(entry, selected: false) - basename = entry[:basename] - positions = entry[:highlight_positions] || [] + basename = entry.basename + positions = entry.highlight_positions || [] if basename =~ /^(\d{4}-\d{2}-\d{2})-(.+)$/ date_part = $1 @@ -579,10 +614,7 @@ def selected_foreground # Find the position of the previous word boundary for Ctrl-W deletion. # Skips non-alphanumeric chars, then skips alphanumeric chars. def word_boundary_backward(buffer, cursor) - pos = cursor - 1 - pos -= 1 while pos >= 0 && !buffer[pos].match?(WORD_CHAR_RE) - pos -= 1 while pos >= 0 && buffer[pos].match?(WORD_CHAR_RE) - pos + 1 + Tui::InputField.new(placeholder: "", text: buffer.to_s, cursor: cursor).word_boundary_backward(buffer.to_s, cursor) end def format_relative_time(time) @@ -634,18 +666,23 @@ def run_rename_dialog(entry) @delete_mode = false @marked_for_deletion.clear - current_name = entry[:basename] - rename_buffer = current_name.dup - rename_cursor = rename_buffer.length + current_name = entry.basename + input = Tui::InputField.new(placeholder: "", text: current_name.dup) rename_error = nil loop do - render_rename_dialog(current_name, rename_buffer, rename_cursor, rename_error) + render_rename_dialog(current_name, input.text, input.cursor, rename_error) ch = read_key + next unless ch + before = input.text + if input.handle_key(ch) + rename_error = nil if input.text != before + next + end case ch when "\r" # Enter - confirm - result = finalize_rename(entry, rename_buffer) + result = finalize_rename(entry, input.text) if result == true break else @@ -653,36 +690,6 @@ def run_rename_dialog(entry) end when "\x1b", "\x03" # ESC or Ctrl-C - cancel break - when "\x7F", "\b" # Backspace - if rename_cursor > 0 - rename_buffer = rename_buffer[0...(rename_cursor - 1)] + rename_buffer[rename_cursor..].to_s - rename_cursor -= 1 - end - rename_error = nil - when "\x01" # Ctrl-A - start of line - rename_cursor = 0 - when "\x05" # Ctrl-E - end of line - rename_cursor = rename_buffer.length - when "\x02" # Ctrl-B - back one char - rename_cursor = [rename_cursor - 1, 0].max - when "\x06" # Ctrl-F - forward one char - rename_cursor = [rename_cursor + 1, rename_buffer.length].min - when "\x0B" # Ctrl-K - kill to end - rename_buffer = rename_buffer[0...rename_cursor] - rename_error = nil - when "\x17" # Ctrl-W - delete word backward - if rename_cursor > 0 - new_pos = word_boundary_backward(rename_buffer, rename_cursor) - rename_buffer = rename_buffer[0...new_pos] + rename_buffer[rename_cursor..].to_s - rename_cursor = new_pos - end - rename_error = nil - when String - if ch.length == 1 && ch =~ /[a-zA-Z0-9\-_\.\s\/]/ - rename_buffer = rename_buffer[0...rename_cursor] + ch + rename_buffer[rename_cursor..].to_s - rename_cursor += 1 - rename_error = nil - end end end @@ -731,7 +738,7 @@ def render_rename_dialog(current_name, rename_buffer, rename_cursor, rename_erro def finalize_rename(entry, rename_buffer) new_name = rename_buffer.strip.gsub(/\s+/, '-') - old_name = entry[:basename] + old_name = entry.basename return "Name cannot be empty" if new_name.empty? return "Name cannot contain /" if new_name.include?('/') @@ -747,7 +754,7 @@ def run_ascend_dialog(entry) @delete_mode = false @marked_for_deletion.clear - current_name = entry[:basename] + current_name = entry.basename # Strip date prefix for the default project name project_name = current_name.sub(/^\d{4}-\d{2}-\d{2}-/, '') @@ -759,17 +766,22 @@ def run_ascend_dialog(entry) File.dirname(@base_path) end - ascend_buffer = File.join(projects_dir, project_name) - ascend_cursor = ascend_buffer.length + input = Tui::InputField.new(placeholder: "", text: File.join(projects_dir, project_name)) ascend_error = nil loop do - render_ascend_dialog(current_name, ascend_buffer, ascend_cursor, ascend_error, projects_dir) + render_ascend_dialog(current_name, input.text, input.cursor, ascend_error, projects_dir) ch = read_key + next unless ch + before = input.text + if input.handle_key(ch) + ascend_error = nil if input.text != before + next + end case ch when "\r" # Enter - confirm - result = finalize_ascend(entry, ascend_buffer) + result = finalize_ascend(entry, input.text) if result == true break else @@ -777,36 +789,6 @@ def run_ascend_dialog(entry) end when "\x1b", "\x03" # ESC or Ctrl-C - cancel break - when "\x7F", "\b" # Backspace - if ascend_cursor > 0 - ascend_buffer = ascend_buffer[0...(ascend_cursor - 1)] + ascend_buffer[ascend_cursor..].to_s - ascend_cursor -= 1 - end - ascend_error = nil - when "\x01" # Ctrl-A - start of line - ascend_cursor = 0 - when "\x05" # Ctrl-E - end of line - ascend_cursor = ascend_buffer.length - when "\x02" # Ctrl-B - back one char - ascend_cursor = [ascend_cursor - 1, 0].max - when "\x06" # Ctrl-F - forward one char - ascend_cursor = [ascend_cursor + 1, ascend_buffer.length].min - when "\x0B" # Ctrl-K - kill to end - ascend_buffer = ascend_buffer[0...ascend_cursor] - ascend_error = nil - when "\x17" # Ctrl-W - delete word backward - if ascend_cursor > 0 - new_pos = word_boundary_backward(ascend_buffer, ascend_cursor) - ascend_buffer = ascend_buffer[0...new_pos] + ascend_buffer[ascend_cursor..].to_s - ascend_cursor = new_pos - end - ascend_error = nil - when String - if ch.length == 1 && ch =~ /[a-zA-Z0-9\-_\.\s\/~]/ - ascend_buffer = ascend_buffer[0...ascend_cursor] + ch + ascend_buffer[ascend_cursor..].to_s - ascend_cursor += 1 - ascend_error = nil - end end end @@ -869,9 +851,9 @@ def finalize_ascend(entry, ascend_buffer) @selected = { type: :ascend, - source: entry[:path], + source: entry.path, dest: dest, - basename: entry[:basename], + basename: entry.basename, base_path: @base_path } true @@ -879,7 +861,7 @@ def finalize_ascend(entry, ascend_buffer) def handle_selection(try_dir) # Select existing try directory - @selected = { type: :cd, path: try_dir[:path] } + @selected = { type: :cd, path: try_dir.path } end def handle_create_new @@ -887,8 +869,8 @@ def handle_create_new date_prefix = Time.now.strftime("%Y-%m-%d") # If user already typed a name, use it directly - if !@input_buffer.empty? - final_name = "#{date_prefix}-#{@input_buffer}".gsub(/\s+/, '-') + if !@search.text.empty? + final_name = "#{date_prefix}-#{@search.text}".gsub(/\s+/, '-') full_path = File.join(@base_path, final_name) @selected = { type: :mkdir, path: full_path } else @@ -921,21 +903,19 @@ def handle_create_new def confirm_batch_delete(tries) # Find marked items with their info - marked_items = tries.select { |t| @marked_for_deletion.include?(t[:path]) } + marked_items = tries.select { |t| @marked_for_deletion.include?(t.path) } return if marked_items.empty? - confirmation_buffer = String.new - confirmation_cursor = 0 + input = Tui::InputField.new(placeholder: "", text: "") # Handle test mode if @test_keys && !@test_keys.empty? while @test_keys && !@test_keys.empty? ch = @test_keys.shift break if ch == "\r" || ch == "\n" - confirmation_buffer << ch - confirmation_cursor = confirmation_buffer.length + input.handle_key(ch) end - process_delete_confirmation(marked_items, confirmation_buffer) + process_delete_confirmation(marked_items, input.text) return elsif @test_confirm || !STDERR.tty? confirmation_buffer = (@test_confirm || STDIN.gets)&.chomp.to_s @@ -947,33 +927,22 @@ def confirm_batch_delete(tries) # Clear screen once before dialog to ensure clean slate clear_screen unless @test_no_cls loop do - render_delete_dialog(marked_items, confirmation_buffer, confirmation_cursor) + render_delete_dialog(marked_items, input.text, input.cursor) ch = read_key + next unless ch + if input.handle_key(ch) + next + end case ch when "\r" # Enter - confirm - process_delete_confirmation(marked_items, confirmation_buffer) - break - when "\x1b" # Escape - cancel - @delete_status = "Delete cancelled" - @marked_for_deletion.clear - @delete_mode = false + process_delete_confirmation(marked_items, input.text) break - when "\x7F", "\b" # Backspace - if confirmation_cursor > 0 - confirmation_buffer = confirmation_buffer[0...confirmation_cursor-1] + confirmation_buffer[confirmation_cursor..] - confirmation_cursor -= 1 - end - when "\x03" # Ctrl-C + when "\x1b", "\x03" # Escape or Ctrl-C - cancel @delete_status = "Delete cancelled" @marked_for_deletion.clear @delete_mode = false break - when String - if ch.length == 1 && ch.ord >= 32 - confirmation_buffer = confirmation_buffer[0...confirmation_cursor] + ch + confirmation_buffer[confirmation_cursor..] - confirmation_cursor += 1 - end end end @@ -991,7 +960,7 @@ def render_delete_dialog(marked_items, confirmation_buffer, confirmation_cursor) marked_items.each do |item| line = screen.body.add_line(Tui::Palette::DANGER_BG) - line.write.write(emoji("🗑️")).write(" #{item[:basename]}") + line.write.write(emoji("🗑️")).write(" #{item.basename}") end # Add empty lines, then centered confirmation prompt @@ -1025,11 +994,11 @@ def process_delete_confirmation(marked_items, confirmation) # Validate all paths first validated_paths = [] marked_items.each do |item| - target_real = File.realpath(item[:path]) + target_real = File.realpath(item.path) unless target_real.start_with?(base_real + "/") raise "Safety check failed: #{target_real} is not inside #{base_real}" end - validated_paths << { path: target_real, basename: item[:basename] } + validated_paths << { path: target_real, basename: item.basename } end # Return delete action with all paths @@ -1262,7 +1231,9 @@ def parse_test_keys(spec) when 'CTRL-P', 'CTRLP' then keys << "\x10" when 'CTRL-R', 'CTRLR' then keys << "\x12" when 'CTRL-T', 'CTRLT' then keys << "\x14" + when 'CTRL-U', 'CTRLU' then keys << "\x15" when 'CTRL-W', 'CTRLW' then keys << "\x17" + when 'DELETE' then keys << "\e[3~" when /^TYPE=/i tok.sub(/^TYPE=/i, '').each_char { |ch| keys << ch } else