experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(cmd): restore URL detection for domains without protocol (youtube.com)

Regression introduced in xpqyxmqr (2026-02-05) when 'open' command was moved
from static commands to dynamic registration in page extension.

Problem: panel.js checked state.commands['open'] before handling URLs, but
this could be undefined due to race condition with dynamic command registration.

Fix: Remove dependency on 'open' command - panel now opens URLs directly using
api.window.open() instead of going through command execution. This makes URL
handling immediate and reliable.

Also improved error handling in execute() to show message when command not found
instead of silently failing.

Fixes:
- youtube.com now opens immediately (normalized to https://youtube.com)
- http://localhost continues to work
- https://reddit.com opens immediately with visible feedback

+90 -6
+23 -6
extensions/cmd/panel.js
··· 480 480 481 481 // Enter key - execute command (but not if in output selection mode - handled above) 482 482 if (e.key === 'Enter' && !hasModifier(e) && !state.outputSelectionMode) { 483 - // Check if the typed text is a URL - if so, use the "open" command 483 + // Check if the typed text is a URL - if so, open it directly 484 484 const trimmedText = commandInput.value.trim(); 485 485 const urlResult = getValidURL(trimmedText); 486 - if (urlResult.valid && state.commands['open']) { 487 - log('cmd:panel', 'Detected URL, using open command:', urlResult.url); 486 + if (urlResult.valid) { 487 + log('cmd:panel', 'Detected URL, opening:', urlResult.url); 488 488 state.lastExecuted = 'open'; 489 489 updateMatchCount('open'); 490 490 updateAdaptiveFeedback(trimmedText.split(' ')[0], 'open'); 491 491 492 - // Execute open command with the URL 493 - execute('open', 'open ' + trimmedText); 492 + // Open URL directly using api.window.open 493 + api.window.open(urlResult.url, { 494 + width: 800, 495 + height: 600, 496 + trackingSource: 'cmd', 497 + trackingSourceId: 'url-direct' 498 + }).then(result => { 499 + log('cmd:panel', 'URL opened:', result); 500 + }).catch(error => { 501 + log.error('cmd:panel', 'Failed to open URL:', error); 502 + showExecutionError('open', error.message || 'Failed to open URL'); 503 + }); 494 504 495 505 // Clear input and UI 496 506 commandInput.value = ''; 497 507 state.typed = ''; 498 508 updateCommandUI(); 499 509 updateResultsUI(); 510 + 511 + // Close panel after opening URL 512 + setTimeout(shutdown, 100); 500 513 return; 501 514 } 502 515 ··· 1169 1182 */ 1170 1183 async function execute(name, typed) { 1171 1184 log('cmd:panel', 'execute() called with:', name, typed); 1172 - if (!state.commands[name]) return; 1185 + if (!state.commands[name]) { 1186 + log.error('cmd:panel', 'Command not found:', name); 1187 + showExecutionError(name, 'Command not found. Try again in a moment.'); 1188 + return; 1189 + } 1173 1190 1174 1191 log('cmd:panel', 'executing cmd', name, typed); 1175 1192 const context = buildExecutionContext(name, typed);
+67
notes/research-widgets-hud.md
··· 1 + # Widgets System & HUD 2 + 3 + Research note capturing prior session plans for the Widgets system and HUD. 4 + 5 + ## Widgets System 6 + 7 + Full widget infrastructure for Peek. Widgets are the building blocks for HUDs, dashboards, page metadata panels, command previews, and observability displays. 8 + 9 + ### Widget API 10 + 11 + - `api.widgets.register(type, renderer)` — register a widget type with its renderer 12 + - `api.widgets.create(type, config)` — instantiate a widget 13 + - `api.widgets.sheets` — manage widget sheets (collections of widgets) 14 + 15 + ### Widget Types 16 + 17 + 1. **Scalar** — single value display (e.g. window count, datastore size) 18 + 2. **List** — ordered items (e.g. recent URLs, active extensions) 19 + 3. **Table** — tabular data (e.g. extension stats, sync status) 20 + 4. **Stats** — key/value pairs with formatting (e.g. session info) 21 + 5. **Timeline** — time-series data points (e.g. page loads over time) 22 + 6. **Chart** — graphical data visualization 23 + 7. **Carousel** — horizontal/vertical scrollable cards 24 + 8. **Gauge** — progress/threshold indicators 25 + 26 + ### Implementation Phases 27 + 28 + 1. **Foundation** — Widget API, database storage for widget configs, basic scalar/list/table types 29 + 2. **Visualization** — Timeline, chart, gauge types, template system 30 + 3. **Integration** — Extension API for publishing widgets, sheet management 31 + 4. **Polish** — No-code widget creation path, drag-and-drop layout 32 + 33 + ### Database Storage 34 + 35 + Widget configurations stored in datastore — type, config JSON, position, sheet membership. 36 + 37 + ### Template System 38 + 39 + Widgets bind to data sources and re-render reactively. Callers provide schema + data, widget has default template that can be overridden. 40 + 41 + ### Relationship to UI Componentry 42 + 43 + The Widgets system builds on the UI Componentry work outlined in TODO.md (cards, grids, carousels, button sets). Widgets are the data-bound, reactive layer on top of those primitives. 44 + 45 + ## HUD (Always-On-Top Overlay) 46 + 47 + An always-on-top overlay showing Peek context and state. A basic version was implemented independently, but the full version depends on the Widgets system. 48 + 49 + ### What it shows 50 + 51 + - IZUI state (idle, transient, active, overlay) 52 + - Current mode (default, page, settings, group) 53 + - Active window info 54 + - Session info (entry mode, window stack depth) 55 + - System metrics (window count, extension count, datastore stats) 56 + 57 + ### Implementation 58 + 59 + - Transparent, always-on-top BrowserWindow 60 + - Positioned at screen edge (configurable) 61 + - Updates reactively from IZUI state changes and system events 62 + - Full version: composed of Widgets, so each panel is a widget instance in a HUD sheet 63 + 64 + ### Status 65 + 66 + - Basic HUD: completed (standalone implementation) 67 + - Full HUD (widget-based): blocked on Widgets system