experiments in a post-browser web
10
fork

Configure Feed

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

docs: save search extension research and active task list

Add comprehensive documentation for persistence and reference:
- research-search-extension.md: Complete design document for search
extension including OpenSearch discovery, cmd integration, settings
UI, suggestions, privacy controls, and 6-phase implementation plan
- active-tasks.md: Master task list tracking all in-progress, pending,
and completed work with status, priorities, and context for new agents

Both files provide essential context for development continuity.

+1429
+250
notes/active-tasks.md
··· 1 + # Active Tasks 2 + 3 + **Last Updated:** 2026-02-10 4 + 5 + ## In Progress 6 + 7 + ### Search Extension Research Completed 8 + - Status: Research phase complete 9 + - File: `/Users/dietrich/misc/mpeek/notes/research-search-extension.md` 10 + - Next: Begin Phase 1 implementation (Core Infrastructure) 11 + 12 + ### Widgets/HUD Research Completed 13 + - Status: Research phase complete 14 + - File: `/Users/dietrich/misc/mpeek/notes/research-widgets-hud.md` 15 + - Next: Implementation planning 16 + 17 + ## Pending - High Priority 18 + 19 + ### Search Extension Implementation - Phase 1 20 + **Goal:** Core Infrastructure (2 weeks) 21 + - [ ] Create `extensions/search/` directory structure 22 + - [ ] Define datastore schema for `search_engines` table 23 + - [ ] Implement engine storage CRUD (add, remove, update, list) 24 + - [ ] Seed built-in engines (Google, DuckDuckGo, Bing, Wikipedia) 25 + - [ ] Register per-engine commands (`/google`, `/ddg`, etc.) 26 + - [ ] Test basic search command execution 27 + - **Deliverables:** 28 + - Extension scaffold with manifest.json 29 + - Datastore schema migration 30 + - Command registration working for built-in engines 31 + 32 + ### UI Componentry Migration 33 + - Status: Significant research complete (see `/Users/dietrich/misc/mpeek/notes/migration-ui-componentry.md`) 34 + - Next: Complete remaining component migrations 35 + - Priority: High (enables other features) 36 + 37 + ## Pending - Medium Priority 38 + 39 + ### Search Extension Implementation - Phase 2 40 + **Goal:** Settings UI (2 weeks) 41 + - [ ] Build Settings UI using peek-components (card, list, button) 42 + - [ ] Default engine selection (radio buttons) 43 + - [ ] Enable/disable toggle per engine 44 + - [ ] Add custom engine dialog (form with validation) 45 + - [ ] Edit engine (keyword, URL template) 46 + - [ ] Remove engine (with confirmation) 47 + - [ ] Persist changes to datastore 48 + - **Dependencies:** Phase 1 complete 49 + - **Deliverables:** 50 + - Functional Settings page at `peek://ext/search/settings.html` 51 + - CRUD operations for engines 52 + - Settings schema JSON for integration 53 + 54 + ### Search Extension Implementation - Phase 3 55 + **Goal:** OpenSearch Discovery (1 week) 56 + - [ ] Content script to detect `<link rel="search">` tags 57 + - [ ] Fetch and parse OpenSearch XML 58 + - [ ] Validate XML schema (ShortName, Url required) 59 + - [ ] Show install prompt (notification or cmd indicator) 60 + - [ ] User confirms → add to datastore 61 + - [ ] Test on popular sites (Wikipedia, GitHub, Stack Overflow) 62 + - **Dependencies:** Phase 2 complete 63 + - **Deliverables:** 64 + - content-discovery.js content script 65 + - XML parser with validation 66 + - Install prompt UI 67 + 68 + ### Session Restoration 69 + - Status: Research complete (see `/Users/dietrich/misc/mpeek/notes/research-session-restoration.md`) 70 + - Next: Implementation planning 71 + - Priority: Medium 72 + 73 + ### Userscripts Support 74 + - Status: Research complete (see `/Users/dietrich/misc/mpeek/notes/research-userscripts.md`) 75 + - Next: Implementation planning 76 + - Priority: Medium 77 + 78 + ## Pending - Lower Priority 79 + 80 + ### Search Extension Implementation - Phase 4 81 + **Goal:** Search Suggestions (2 weeks) 82 + - [ ] Implement suggestion-provider.js (fetch + parse) 83 + - [ ] Support OpenSearch JSON and Google-style formats 84 + - [ ] Debounce requests (200ms) 85 + - [ ] In-memory cache with TTL (5 min) 86 + - [ ] Integrate with cmd panel dropdown 87 + - [ ] Keyboard navigation (arrow keys, Enter) 88 + - [ ] Attribution footer ("Powered by X") 89 + - **Dependencies:** Phase 3 complete 90 + - **Deliverables:** 91 + - Suggestion API integration 92 + - Cache implementation 93 + - Cmd panel dropdown with suggestions 94 + 95 + ### Search Extension Implementation - Phase 5 96 + **Goal:** Default Fallback & Polish (1 week) 97 + - [ ] Cmd panel: detect unmatched input 98 + - [ ] Heuristic: check if it's a URL vs search query 99 + - [ ] Use default engine for non-URL input 100 + - [ ] Privacy mode: disable suggestions when enabled 101 + - [ ] Per-engine suggestion toggle 102 + - [ ] Error handling (network failures, timeouts) 103 + - [ ] Logging and telemetry 104 + - **Dependencies:** Phase 4 complete 105 + - **Deliverables:** 106 + - Default search fallback working 107 + - Privacy controls functional 108 + - Error states handled gracefully 109 + 110 + ### Search Extension Implementation - Phase 6 111 + **Goal:** Testing & Documentation (1 week) 112 + - [ ] Unit tests for engine CRUD 113 + - [ ] Unit tests for suggestion parsing 114 + - [ ] Integration tests: add engine, search, suggestions 115 + - [ ] E2E tests: OpenSearch discovery flow 116 + - [ ] Performance profiling (suggestion latency) 117 + - [ ] User documentation (help text in Settings) 118 + - [ ] Developer documentation (extension API) 119 + - **Dependencies:** Phase 5 complete 120 + - **Deliverables:** 121 + - Test suite with >80% coverage 122 + - Documentation in README or help page 123 + 124 + ### Webview Background Flash Fix 125 + - Status: Research complete (see `/Users/dietrich/misc/mpeek/notes/research-webview-background-flash.md`) 126 + - Next: Implementation planning 127 + - Priority: Low (polish) 128 + 129 + ### Bundled Web Extensions 130 + - Status: Research complete (see `/Users/dietrich/misc/mpeek/notes/research-bundled-web-extensions.md`) 131 + - Next: Implementation planning 132 + - Priority: Low 133 + 134 + ## Completed Recently 135 + 136 + ### Task Management System Setup 137 + - Completed: 2026-02-10 138 + - Created task tracking infrastructure 139 + - Files: 140 + - `/Users/dietrich/misc/mpeek/notes/active-tasks.md` (this file) 141 + - `/Users/dietrich/misc/mpeek/notes/task-1-summary.md` 142 + 143 + ### Groups Migration Summary 144 + - Completed: 2026-02-09 145 + - File: `/Users/dietrich/misc/mpeek/notes/groups-migration-summary.md` 146 + - Summary: Documented the groups model migration and related changes 147 + 148 + ### Startup Feature Review 149 + - Completed: 2026-02-10 150 + - File: `/Users/dietrich/misc/mpeek/notes/startup-feature-review.md` 151 + - Summary: Reviewed startup configuration and feature set 152 + 153 + ## Architecture & Planning Documents 154 + 155 + ### Recent Research Documents 156 + - `/Users/dietrich/misc/mpeek/notes/research-search-extension.md` - Search extension design (complete) 157 + - `/Users/dietrich/misc/mpeek/notes/research-widgets-hud.md` - Widgets/HUD design (complete) 158 + - `/Users/dietrich/misc/mpeek/notes/research-session-restoration.md` - Session restoration design (complete) 159 + - `/Users/dietrich/misc/mpeek/notes/research-userscripts.md` - Userscripts support design (complete) 160 + - `/Users/dietrich/misc/mpeek/notes/research-webview-background-flash.md` - WebView flash fix (complete) 161 + - `/Users/dietrich/misc/mpeek/notes/migration-ui-componentry.md` - UI component migration (in progress) 162 + 163 + ### Core Architecture Documents 164 + - `/Users/dietrich/misc/mpeek/notes/design-vision.md` - Overall design philosophy 165 + - `/Users/dietrich/misc/mpeek/notes/datastore-architecture.md` - Data storage architecture 166 + - `/Users/dietrich/misc/mpeek/notes/extensibility.md` - Extension system architecture 167 + - `/Users/dietrich/misc/mpeek/notes/core-api.md` - Core API documentation 168 + - `/Users/dietrich/misc/mpeek/notes/shortcuts-api.md` - Shortcuts/hotkey system 169 + 170 + ### iOS-Specific Documents 171 + - `/Users/dietrich/misc/mpeek/notes/ios-storage-architecture.md` - iOS storage implementation 172 + - `/Users/dietrich/misc/mpeek/notes/research-tauri-mobile.md` - Tauri mobile research 173 + - `/Users/dietrich/misc/mpeek/notes/research-xcodebuild-environment-issues.md` - iOS build troubleshooting 174 + 175 + ### Sync & Server Documents 176 + - `/Users/dietrich/misc/mpeek/notes/sync-architecture.md` - Sync system design 177 + - `/Users/dietrich/misc/mpeek/notes/sync-architecture-review.md` - Sync system review 178 + - `/Users/dietrich/misc/mpeek/notes/sync-edge-cases.md` - Sync edge case handling 179 + - `/Users/dietrich/misc/mpeek/notes/server-portability-plan.md` - Server deployment options 180 + - `/Users/dietrich/misc/mpeek/notes/cloudflare-vs-railway-evaluation.md` - Hosting comparison 181 + 182 + ## Open Questions & Decisions Needed 183 + 184 + ### Search Extension 185 + 1. **Default Search Fallback**: Should cmd bar automatically fall back to default search for unmatched input? 186 + - Recommendation: Smart detection (>3 chars, has spaces) with setting to disable 187 + 2. **OpenSearch Auto-Install**: Should Peek automatically install discovered search engines? 188 + - Recommendation: Smart prompt (first time per domain) with setting for auto-install 189 + 3. **Suggestion Privacy Default**: Should search suggestions be enabled by default? 190 + - Recommendation: Enabled by default with privacy disclosures 191 + 4. **Keyword Conflicts**: What happens if two engines have the same keyword? 192 + - Recommendation: User resolves during installation 193 + 5. **Search Result Display**: Where should search results open? 194 + - Recommendation: User setting (default: new window) 195 + 6. **Sync Custom Engines**: Should custom engines sync across devices? 196 + - Recommendation: Custom engines only (not built-in) 197 + 198 + ### Widgets/HUD 199 + - Implementation approach TBD after review of research document 200 + 201 + ## Notes for New Agents 202 + 203 + ### Getting Started 204 + 1. Review `/Users/dietrich/misc/mpeek/CLAUDE.md` for jj workflow and project guidelines 205 + 2. Review `/Users/dietrich/misc/mpeek/DEVELOPMENT.md` for architecture overview 206 + 3. Check this file for current priorities and task status 207 + 4. Always commit before rebasing: `jj commit -m "description"` 208 + 209 + ### Key Patterns 210 + - **Extensions:** Located in `extensions/` directory, follow manifest.json pattern 211 + - **Components:** Use peek-components from `app/components/`, see research-ui-componentry.md 212 + - **Datastore:** Use datastore API for all persistence, see datastore-architecture.md 213 + - **Commands:** Register via cmd extension, see `extensions/cmd/` 214 + - **Testing:** Use headless tests (`yarn test:electron:bg`), never headed without user request 215 + 216 + ### iOS Development 217 + - **Build for simulator:** `yarn mobile:ios:dev` (includes HMR) 218 + - **Build for device:** `yarn mobile:ios:xcodebuild:device:full` 219 + - **Build numbers:** Auto-incremented in `backend/tauri-mobile/BUILD_NUMBER` 220 + - **Stale cache:** Run `npm run clean:rust:full` when changing Cargo features 221 + - **Custom protocol:** Only for release builds, never for dev (breaks HMR) 222 + 223 + ### Testing Philosophy 224 + - Never run `npx playwright test` directly (steals focus) 225 + - Use `yarn test:electron:bg` for background execution 226 + - No timeouts for assertions - use events and deterministic checks 227 + - Test logs go to `/tmp/test-electron.log` 228 + 229 + ### jj Workflow 230 + - Always use `jj commit`, never git commands 231 + - Commit before any rebase (uncommitted edits can be lost) 232 + - Push to main: `jj rebase -s 'roots(::@ ~ ::main)' -d main && jj bookmark set main -r '@-'` 233 + - Pull from main: `jj rebase -s 'roots(::@ ~ ::main)' -d main` 234 + 235 + ## Status Legend 236 + 237 + - **In Progress**: Currently being worked on 238 + - **Pending - High Priority**: Should be started soon 239 + - **Pending - Medium Priority**: Important but not urgent 240 + - **Pending - Lower Priority**: Nice to have, not blocking 241 + - **Completed Recently**: Finished in the last few days 242 + 243 + ## Updating This Document 244 + 245 + When working on tasks: 246 + 1. Move tasks between sections as status changes 247 + 2. Add new tasks as they're identified 248 + 3. Update the "Last Updated" date 249 + 4. Add completion notes for finished tasks 250 + 5. Commit changes: `jj commit -m "docs: update active tasks"`
+1179
notes/research-search-extension.md
··· 1 + # Search Extension for Peek - Research & Design 2 + 3 + **Status:** Planning phase 4 + **Last Updated:** 2026-02-10 5 + **Purpose:** Design comprehensive search engine support with browser-level discovery, management, and cmd bar integration 6 + 7 + --- 8 + 9 + ## 1. Overview 10 + 11 + ### Problem Statement 12 + 13 + Peek currently lacks a standardized way to perform web searches through the cmd bar. Users need: 14 + - Quick web search access via keyboard (like `/google query` or `/ddg query`) 15 + - Search engine discovery from websites (like browsers do with OpenSearch) 16 + - Management of multiple search engines with preferences 17 + - Search suggestions as they type 18 + - Default search engine fallback for unmatched cmd input 19 + 20 + ### User Stories 21 + 22 + **As a user, I want to:** 23 + 1. Type `/google artificial intelligence` in cmd bar and search Google 24 + 2. Visit wikipedia.org and have Peek auto-discover "Search Wikipedia" option 25 + 3. Manage my installed search engines in Settings 26 + 4. See search suggestions as I type in cmd bar 27 + 5. Have unrecognized cmd input automatically search using my default engine 28 + 6. Switch my default search engine easily 29 + 7. Use custom search engines (like internal company search) 30 + 31 + ### Success Metrics 32 + 33 + - Search commands execute in <500ms 34 + - Search suggestions appear in <200ms after typing stops 35 + - OpenSearch discovery works on 95% of sites that provide it 36 + - Zero user confusion about which search engine is active 37 + - Settings UI allows full management without complexity 38 + 39 + --- 40 + 41 + ## 2. Browser Research - How Modern Browsers Do It 42 + 43 + ### Firefox (2026) 44 + 45 + **Discovery:** 46 + - Uses `<link rel="search" type="application/opensearchdescription+xml">` in HTML 47 + - Automatically detects OpenSearch XML files 48 + - Shows "Add Search Engine" button in address bar when discovered 49 + - User can also manually add via Settings > Search 50 + 51 + **Management:** 52 + - Settings > Search shows all installed engines 53 + - Set default engine with radio buttons 54 + - Remove engines with Remove button 55 + - Search shortcuts: short keywords like "g" for Google, "w" for Wikipedia 56 + - One-click address bar dropdown shows recent searches and suggestions 57 + 58 + **Suggestions:** 59 + - Fetches suggestions from search engine's suggestion URL 60 + - Debounces requests (300ms typical) 61 + - Caches results in memory (5 min TTL) 62 + - Shows mix of history, bookmarks, and engine suggestions 63 + - Privacy mode: no suggestions in private windows 64 + 65 + **APIs:** 66 + - WebExtension search API: `browser.search.get()`, `browser.search.search()` 67 + - Can programmatically trigger searches 68 + - Cannot modify engine list (security restriction) 69 + 70 + ### Chrome (2026) 71 + 72 + **Discovery:** 73 + - Same OpenSearch auto-discovery as Firefox 74 + - Also uses Web Search manifest key for installed PWAs 75 + - "Manage search engines" in Settings 76 + - Automatic keyword extraction from site search forms 77 + 78 + **Management:** 79 + - Settings > Search engine > Manage search engines 80 + - Default engine dropdown 81 + - Three lists: Default, Active (used recently), Inactive 82 + - Keywords: shortcut text like "youtube.com" → "yt" 83 + - Edit button allows customizing URL template and keyword 84 + 85 + **Suggestions:** 86 + - Chrome-specific suggest protocol (JSON) 87 + - Aggregates: search suggestions, history, bookmarks, tabs 88 + - Privacy: anonymous requests, no cookies 89 + - Cache: in-memory, per-session 90 + 91 + **APIs:** 92 + - `chrome.search.query()` - search with default engine only 93 + - No API to list or manage engines (security) 94 + 95 + ### Safari (2026) 96 + 97 + **Discovery:** 98 + - OpenSearch support (limited) 99 + - Prefers built-in engine list 100 + - Manual addition through profiles or config 101 + 102 + **Management:** 103 + - Settings > Search > Search engine dropdown (4 built-in only by default) 104 + - Custom engines via Safari Technology Preview or profiles 105 + 106 + **Suggestions:** 107 + - From default engine only 108 + - Minimal UI (no rich previews) 109 + 110 + ### Key Patterns Across Browsers 111 + 112 + | Feature | Firefox | Chrome | Safari | 113 + |---------|---------|--------|--------| 114 + | OpenSearch discovery | ✅ Yes | ✅ Yes | ⚠️ Limited | 115 + | Search suggestions | ✅ Yes | ✅ Yes | ✅ Yes | 116 + | Custom engines | ✅ Easy | ✅ Easy | ⚠️ Complex | 117 + | Keyword shortcuts | ✅ Yes | ✅ Yes | ❌ No | 118 + | Default engine | ✅ User choice | ✅ User choice | ✅ 4 options | 119 + | Privacy mode | ✅ No suggestions | ✅ No suggestions | ✅ No suggestions | 120 + 121 + **Takeaways for Peek:** 122 + - OpenSearch XML is the standard for discovery 123 + - Suggestion APIs are engine-specific (no universal protocol) 124 + - Keyword shortcuts are highly valued by power users 125 + - Default fallback is expected UX 126 + - Privacy mode must disable suggestions 127 + 128 + --- 129 + 130 + ## 3. OpenSearch Discovery & Installation 131 + 132 + ### OpenSearch XML Format 133 + 134 + **Standard:** [OpenSearch 1.1 Draft 6](https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md) 135 + 136 + **Example:** 137 + ```xml 138 + <?xml version="1.0" encoding="UTF-8"?> 139 + <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/"> 140 + <ShortName>Wikipedia</ShortName> 141 + <Description>Search Wikipedia, the free encyclopedia</Description> 142 + <Tags>encyclopedia wiki</Tags> 143 + <Contact>contact@example.com</Contact> 144 + <Url type="text/html" template="https://en.wikipedia.org/wiki/Special:Search?search={searchTerms}"/> 145 + <Url type="application/x-suggestions+json" template="https://en.wikipedia.org/w/api.php?action=opensearch&amp;search={searchTerms}"/> 146 + <Image height="16" width="16" type="image/x-icon">https://en.wikipedia.org/favicon.ico</Image> 147 + <InputEncoding>UTF-8</InputEncoding> 148 + <SearchForm>https://en.wikipedia.org/wiki/Special:Search</SearchForm> 149 + </OpenSearchDescription> 150 + ``` 151 + 152 + **Key Elements:** 153 + - `<ShortName>` - Display name (max 16 chars recommended) 154 + - `<Description>` - User-facing description 155 + - `<Url type="text/html">` - Search URL template with `{searchTerms}` placeholder 156 + - `<Url type="application/x-suggestions+json">` - Suggestion URL (optional) 157 + - `<Image>` - Favicon URL 158 + - `<InputEncoding>` - Character encoding (UTF-8 typical) 159 + 160 + **Discovery HTML:** 161 + ```html 162 + <link rel="search" 163 + type="application/opensearchdescription+xml" 164 + title="Search Wikipedia" 165 + href="/opensearch.xml"> 166 + ``` 167 + 168 + **Browser Detection:** 169 + - BrowserWindow webContents monitors page load 170 + - Parse HTML for `<link rel="search">` tags 171 + - Fetch OpenSearch XML file 172 + - Parse and validate XML 173 + - Prompt user to install or auto-install based on settings 174 + 175 + ### Implementation in Peek 176 + 177 + **Detection Flow:** 178 + 1. User visits page (e.g., `https://duckduckgo.com`) 179 + 2. `did-finish-load` event fires in webContents 180 + 3. Search extension injects content script 181 + 4. Content script queries: `document.querySelector('link[rel="search"]')` 182 + 5. If found, sends message to background: `search:discovered` 183 + 6. Background fetches and parses OpenSearch XML 184 + 7. Shows notification or cmd bar indicator: "Install DuckDuckGo search?" 185 + 8. User confirms → adds to search engine list 186 + 187 + **Storage Schema:** 188 + ```javascript 189 + // datastore table: search_engines 190 + { 191 + id: 'uuid', // Unique identifier 192 + name: 'DuckDuckGo', // Display name 193 + shortName: 'ddg', // Keyword for cmd (/ddg query) 194 + description: 'Privacy-focused search', 195 + searchUrl: 'https://duckduckgo.com/?q={searchTerms}', 196 + suggestionUrl: 'https://duckduckgo.com/ac/?q={searchTerms}&type=list', 197 + iconUrl: 'https://duckduckgo.com/favicon.ico', 198 + encoding: 'UTF-8', 199 + isDefault: false, // Whether this is the default engine 200 + isBuiltIn: true, // Pre-installed vs user-added 201 + enabled: true, // User can disable without removing 202 + createdAt: 1234567890, 203 + updatedAt: 1234567890 204 + } 205 + ``` 206 + 207 + **Built-in Engines (Pre-installed):** 208 + - Google (default) 209 + - DuckDuckGo 210 + - Bing 211 + - Wikipedia 212 + - GitHub 213 + - Stack Overflow 214 + 215 + --- 216 + 217 + ## 4. Architecture & Data Flow 218 + 219 + ### Component Structure 220 + 221 + ``` 222 + extensions/search/ 223 + ├── manifest.json # Extension metadata 224 + ├── background.js # Main extension logic 225 + ├── content-discovery.js # Content script for OpenSearch detection 226 + ├── suggestion-provider.js # Handles suggestion API calls 227 + ├── settings-schema.json # Settings UI schema 228 + ├── settings.html # Management UI 229 + ├── settings.js # Settings UI logic 230 + ├── commands/ 231 + │ ├── search-engine-cmd.js # Per-engine cmd registrations (/google, /ddg) 232 + │ └── default-search.js # Fallback search handler 233 + └── config.js # Default engines, schemas 234 + ``` 235 + 236 + ### Data Flow: Command Execution 237 + 238 + ``` 239 + User types: /google AI research 240 + 241 + Cmd panel detects "/google" prefix 242 + 243 + Looks up command in registry → "search:google" 244 + 245 + Executes command with params: ["AI", "research"] 246 + 247 + Search extension constructs URL: 248 + https://google.com/search?q=AI%20research 249 + 250 + Opens in new BrowserWindow or current window 251 + ``` 252 + 253 + ### Data Flow: Search Suggestions 254 + 255 + ``` 256 + User types: /google artificial int 257 + 258 + Cmd panel debounces input (200ms) 259 + 260 + Publishes: cmd:request-suggestions 261 + { command: "google", query: "artificial int" } 262 + 263 + Search extension receives request 264 + 265 + Fetches from Google suggest API: 266 + https://google.com/complete/search?q=artificial%20int 267 + 268 + Parses JSON response: ["artificial intelligence", "artificial intelligence jobs", ...] 269 + 270 + Publishes: cmd:suggestions-response 271 + { suggestions: [...], command: "google" } 272 + 273 + Cmd panel displays in dropdown 274 + 275 + User selects → executes full search 276 + ``` 277 + 278 + ### Data Flow: OpenSearch Discovery 279 + 280 + ``` 281 + User visits: https://en.wikipedia.org 282 + 283 + did-finish-load event fires 284 + 285 + Search content script executes 286 + 287 + Finds: <link rel="search" href="/opensearch.xml"> 288 + 289 + Publishes: search:engine-discovered 290 + { url: "https://en.wikipedia.org/opensearch.xml" } 291 + 292 + Search background fetches XML 293 + 294 + Parses OpenSearchDescription 295 + 296 + Validates schema (ShortName, Url template) 297 + 298 + Publishes: search:install-prompt 299 + { engine: { name: "Wikipedia", ... } } 300 + 301 + Cmd bar shows indicator OR 302 + Notification: "Install Wikipedia search? [Yes] [No]" 303 + 304 + User confirms → Saves to datastore 305 + 306 + Registers new cmd: /wikipedia 307 + ``` 308 + 309 + --- 310 + 311 + ## 5. Command Bar Integration 312 + 313 + ### Per-Engine Commands 314 + 315 + Each installed search engine gets its own cmd: 316 + 317 + ```javascript 318 + // Example: /google query 319 + api.commands.register({ 320 + name: 'google', 321 + description: 'Search Google', 322 + execute: async (ctx) => { 323 + const query = ctx.params.join(' ') || ctx.search; 324 + const engine = await getEngine('google'); 325 + const url = engine.searchUrl.replace('{searchTerms}', encodeURIComponent(query)); 326 + 327 + await api.window.open(url, { 328 + type: 'normal', 329 + show: true 330 + }); 331 + 332 + // Close cmd panel 333 + await api.window.close('peek://ext/cmd/panel.html'); 334 + } 335 + }); 336 + ``` 337 + 338 + **Registration Pattern:** 339 + - Background script loops through enabled engines 340 + - Registers one command per engine with shortName as command name 341 + - Updates registry when engines are added/removed/disabled 342 + 343 + ### Default Search Fallback 344 + 345 + If cmd input doesn't match any command: 346 + 347 + ```javascript 348 + // In cmd panel: handleUnmatchedInput() 349 + async function handleUnmatchedInput(text) { 350 + // Check if it looks like a URL 351 + if (isURL(text)) { 352 + await api.window.open(text); 353 + return; 354 + } 355 + 356 + // Otherwise, use default search engine 357 + const defaultEngine = await getDefaultEngine(); 358 + const url = defaultEngine.searchUrl.replace('{searchTerms}', encodeURIComponent(text)); 359 + 360 + await api.window.open(url); 361 + } 362 + ``` 363 + 364 + **When it triggers:** 365 + - User types text that doesn't match any registered command 366 + - User presses Enter without selecting a suggestion 367 + - Smart heuristics: if it contains spaces or is >3 chars, assume search query 368 + 369 + ### Suggestions in Dropdown 370 + 371 + **UI Pattern (following existing cmd panel):** 372 + ``` 373 + ┌─────────────────────────────────────────┐ 374 + │ /google artificial intelligence │ ← Input 375 + ├─────────────────────────────────────────┤ 376 + │ → artificial intelligence │ ← Top suggestion (highlighted) 377 + │ artificial intelligence jobs │ 378 + │ artificial intelligence news │ 379 + │ artificial intelligence course │ 380 + │ artificial intelligence companies │ 381 + ├─────────────────────────────────────────┤ 382 + │ [Powered by Google] │ ← Attribution 383 + └─────────────────────────────────────────┘ 384 + ``` 385 + 386 + **Implementation:** 387 + - Cmd panel subscribes to `search:suggestions` events 388 + - Search extension debounces API calls (200ms after typing stops) 389 + - Response rendered using peek-list component 390 + - Arrow keys navigate, Enter selects 391 + - Escape dismisses dropdown 392 + 393 + **Keyboard Navigation:** 394 + - `↓` / `j` - Next suggestion 395 + - `↑` / `k` - Previous suggestion 396 + - `Enter` - Select highlighted suggestion 397 + - `Escape` - Clear suggestions 398 + - `Tab` - Autocomplete first suggestion (inline) 399 + 400 + --- 401 + 402 + ## 6. Search Suggestions 403 + 404 + ### API Protocols 405 + 406 + Search engines use different protocols. We support: 407 + 408 + **1. OpenSearch Suggestions (JSON)** 409 + ```javascript 410 + // Request 411 + GET https://example.com/suggest?q=test 412 + 413 + // Response 414 + [ 415 + "test", // Original query 416 + ["test query", "testing", ...], // Suggestions 417 + ["Description 1", "Desc 2", ...], // Descriptions (optional) 418 + ["https://...", "https://..."] // URLs (optional) 419 + ] 420 + ``` 421 + 422 + **2. Google-style JSON** 423 + ```javascript 424 + // Response 425 + { 426 + "suggestions": [ 427 + { "value": "test query", "data": {...} }, 428 + { "value": "testing", "data": {...} } 429 + ] 430 + } 431 + ``` 432 + 433 + **Implementation:** 434 + ```javascript 435 + // suggestion-provider.js 436 + async function fetchSuggestions(engine, query) { 437 + if (!engine.suggestionUrl) return []; 438 + 439 + const url = engine.suggestionUrl.replace('{searchTerms}', encodeURIComponent(query)); 440 + 441 + try { 442 + const response = await fetch(url, { 443 + method: 'GET', 444 + headers: { 'Accept': 'application/json' }, 445 + cache: 'default', 446 + signal: AbortSignal.timeout(2000) // 2s timeout 447 + }); 448 + 449 + const data = await response.json(); 450 + 451 + // Parse format (OpenSearch vs Google-style) 452 + if (Array.isArray(data) && data.length >= 2) { 453 + // OpenSearch format: ["query", ["suggestion1", "suggestion2"]] 454 + return data[1].slice(0, 8); // Max 8 suggestions 455 + } else if (data.suggestions) { 456 + // Google-style: { suggestions: [{value: "..."}] } 457 + return data.suggestions.map(s => s.value).slice(0, 8); 458 + } 459 + 460 + return []; 461 + } catch (err) { 462 + log.error('search:suggestions', 'Fetch failed:', err); 463 + return []; 464 + } 465 + } 466 + ``` 467 + 468 + ### Caching Strategy 469 + 470 + **In-Memory Cache:** 471 + ```javascript 472 + const suggestionCache = new Map(); 473 + 474 + function getCacheKey(engine, query) { 475 + return `${engine.id}:${query.toLowerCase().trim()}`; 476 + } 477 + 478 + async function fetchWithCache(engine, query) { 479 + const key = getCacheKey(engine, query); 480 + const cached = suggestionCache.get(key); 481 + 482 + if (cached && Date.now() - cached.timestamp < 5 * 60 * 1000) { 483 + // Cache hit, <5 min old 484 + return cached.suggestions; 485 + } 486 + 487 + const suggestions = await fetchSuggestions(engine, query); 488 + 489 + suggestionCache.set(key, { 490 + suggestions, 491 + timestamp: Date.now() 492 + }); 493 + 494 + // Limit cache size (LRU) 495 + if (suggestionCache.size > 500) { 496 + const oldestKey = suggestionCache.keys().next().value; 497 + suggestionCache.delete(oldestKey); 498 + } 499 + 500 + return suggestions; 501 + } 502 + ``` 503 + 504 + **Cache Invalidation:** 505 + - Time-based: 5 minute TTL 506 + - Size-based: Max 500 entries (LRU eviction) 507 + - Manual: Clear on settings change (e.g., disable suggestions) 508 + 509 + ### Privacy Considerations 510 + 511 + **Anonymous Requests:** 512 + - No cookies sent with suggestion requests 513 + - Referer header stripped 514 + - User-Agent generic (Peek version only) 515 + - No personal identifiers in query params 516 + 517 + **Privacy Mode:** 518 + - If user enables "Do Not Track" → disable all suggestions 519 + - Setting: "Enable search suggestions" (default: on) 520 + - Per-engine toggle: Some engines may have stricter privacy 521 + 522 + **Data Retention:** 523 + - Suggestions never written to disk 524 + - Cache cleared on app quit 525 + - No history of suggestion queries kept 526 + 527 + **User Control:** 528 + ```javascript 529 + // Settings options 530 + { 531 + enableSuggestions: true, // Global toggle 532 + suggestionEngines: { // Per-engine overrides 533 + 'google': true, 534 + 'duckduckgo': false // User disabled DDG suggestions 535 + } 536 + } 537 + ``` 538 + 539 + --- 540 + 541 + ## 7. Management UI (Settings) 542 + 543 + ### UI Layout 544 + 545 + **Settings > Search** (using peek-components): 546 + 547 + ```html 548 + <peek-card> 549 + <span slot="header">Default Search Engine</span> 550 + <peek-select id="defaultEngine"> 551 + <option value="google">Google</option> 552 + <option value="duckduckgo">DuckDuckGo</option> 553 + <option value="wikipedia">Wikipedia</option> 554 + </peek-select> 555 + </peek-card> 556 + 557 + <peek-card> 558 + <span slot="header">Search Suggestions</span> 559 + <peek-switch id="enableSuggestions" checked> 560 + Enable search suggestions 561 + </peek-switch> 562 + </peek-card> 563 + 564 + <peek-card> 565 + <span slot="header">Installed Search Engines</span> 566 + 567 + <peek-list id="engineList"> 568 + <!-- Dynamically populated --> 569 + <peek-list-item value="google"> 570 + <img slot="prefix" src="favicon" alt=""> 571 + Google 572 + <span slot="suffix"> 573 + <peek-button size="sm" variant="ghost">Edit</peek-button> 574 + <peek-button size="sm" variant="danger">Remove</peek-button> 575 + </span> 576 + </peek-list-item> 577 + </peek-list> 578 + 579 + <div slot="footer"> 580 + <peek-button variant="primary" onclick="addCustomEngine()"> 581 + Add Custom Engine 582 + </peek-button> 583 + </div> 584 + </peek-card> 585 + ``` 586 + 587 + ### Engine List UI 588 + 589 + **Columns:** 590 + - Icon (16x16 favicon) 591 + - Name 592 + - Keyword (shortName for cmd) 593 + - Default (radio button) 594 + - Enabled (toggle switch) 595 + - Actions (Edit, Remove buttons) 596 + 597 + **Actions:** 598 + - **Set Default** - Radio button, one selected at a time 599 + - **Enable/Disable** - Toggle without removing 600 + - **Edit** - Opens dialog to change keyword, URL template 601 + - **Remove** - Confirmation dialog → deletes from datastore 602 + 603 + ### Add/Edit Custom Engine Dialog 604 + 605 + ```html 606 + <peek-dialog id="engineDialog" size="md"> 607 + <span slot="header">Add Custom Search Engine</span> 608 + 609 + <peek-input 610 + id="engineName" 611 + placeholder="Search engine name" 612 + required> 613 + </peek-input> 614 + 615 + <peek-input 616 + id="engineKeyword" 617 + placeholder="Keyword (e.g., 'gh' for GitHub)" 618 + pattern="[a-z0-9\-]+" 619 + required> 620 + </peek-input> 621 + 622 + <peek-input 623 + id="engineUrl" 624 + placeholder="https://example.com/search?q={searchTerms}" 625 + type="url" 626 + required> 627 + </peek-input> 628 + 629 + <peek-input 630 + id="suggestionUrl" 631 + placeholder="https://example.com/suggest?q={searchTerms} (optional)" 632 + type="url"> 633 + </peek-input> 634 + 635 + <div slot="footer"> 636 + <peek-button variant="ghost" onclick="engineDialog.close()"> 637 + Cancel 638 + </peek-button> 639 + <peek-button variant="primary" onclick="saveEngine()"> 640 + Add Engine 641 + </peek-button> 642 + </div> 643 + </peek-dialog> 644 + ``` 645 + 646 + **Validation:** 647 + - Name: Required, 1-50 chars 648 + - Keyword: Required, lowercase alphanumeric + hyphens, unique 649 + - URL: Required, valid URL with `{searchTerms}` placeholder 650 + - Suggestion URL: Optional, valid URL with `{searchTerms}` 651 + 652 + ### Settings Storage 653 + 654 + Use datastore `search_engines` table + extension_settings for prefs: 655 + 656 + ```javascript 657 + // extension_settings row 658 + { 659 + extensionId: 'search', 660 + key: 'preferences', 661 + value: JSON.stringify({ 662 + defaultEngineId: 'google', 663 + enableSuggestions: true, 664 + suggestionEngines: { /* per-engine overrides */ } 665 + }), 666 + updatedAt: Date.now() 667 + } 668 + ``` 669 + 670 + --- 671 + 672 + ## 8. Component Usage (Peek Components) 673 + 674 + ### UI Components Needed 675 + 676 + | Component | Usage | Features | 677 + |-----------|-------|----------| 678 + | `peek-card` | Grouping sections in Settings | Header, body, footer slots | 679 + | `peek-select` | Default engine dropdown | Native select with styling | 680 + | `peek-switch` | Enable/disable toggles | Checked state, change events | 681 + | `peek-list` | Installed engines list | Keyboard navigation, selection | 682 + | `peek-input` | Add/edit engine form | Validation, placeholders | 683 + | `peek-button` | Actions (add, remove, edit) | Variants (primary, ghost, danger) | 684 + | `peek-dialog` | Add/edit engine modal | Modal, close-on-escape | 685 + | `peek-dropdown` | Cmd suggestion dropdown | Auto-positioning, keyboard nav | 686 + 687 + ### Integration Example 688 + 689 + ```javascript 690 + // settings.js 691 + import 'peek://app/components/index.js'; 692 + import { signal, effect } from 'peek://app/components/signals.js'; 693 + 694 + const engines = signal([]); 695 + const defaultEngineId = signal('google'); 696 + 697 + // Load engines from datastore 698 + async function loadEngines() { 699 + const result = await api.datastore.query('search_engines', { 700 + orderBy: 'name' 701 + }); 702 + 703 + if (result.success) { 704 + engines.value = result.data; 705 + } 706 + } 707 + 708 + // Reactive UI updates 709 + effect(() => { 710 + const list = document.getElementById('engineList'); 711 + list.innerHTML = engines.value.map(engine => ` 712 + <peek-list-item value="${engine.id}"> 713 + <img slot="prefix" src="${engine.iconUrl}" width="16" height="16"> 714 + ${engine.name} 715 + <span slot="suffix">${engine.shortName}</span> 716 + </peek-list-item> 717 + `).join(''); 718 + }); 719 + 720 + // Init 721 + loadEngines(); 722 + ``` 723 + 724 + --- 725 + 726 + ## 9. Implementation Phases 727 + 728 + ### Phase 1: Core Infrastructure (2 weeks) 729 + 730 + **Goal:** Basic search command system 731 + 732 + - [ ] Create `extensions/search/` directory structure 733 + - [ ] Define datastore schema for `search_engines` table 734 + - [ ] Implement engine storage CRUD (add, remove, update, list) 735 + - [ ] Seed built-in engines (Google, DuckDuckGo, Bing, Wikipedia) 736 + - [ ] Register per-engine commands (`/google`, `/ddg`, etc.) 737 + - [ ] Test basic search command execution 738 + 739 + **Deliverables:** 740 + - Extension scaffold with manifest.json 741 + - Datastore schema migration 742 + - Command registration working for built-in engines 743 + 744 + ### Phase 2: Settings UI (2 weeks) 745 + 746 + **Goal:** User can manage engines 747 + 748 + - [ ] Build Settings UI using peek-components (card, list, button) 749 + - [ ] Default engine selection (radio buttons) 750 + - [ ] Enable/disable toggle per engine 751 + - [ ] Add custom engine dialog (form with validation) 752 + - [ ] Edit engine (keyword, URL template) 753 + - [ ] Remove engine (with confirmation) 754 + - [ ] Persist changes to datastore 755 + 756 + **Deliverables:** 757 + - Functional Settings page at `peek://ext/search/settings.html` 758 + - CRUD operations for engines 759 + - Settings schema JSON for integration 760 + 761 + ### Phase 3: OpenSearch Discovery (1 week) 762 + 763 + **Goal:** Auto-detect search engines from websites 764 + 765 + - [ ] Content script to detect `<link rel="search">` tags 766 + - [ ] Fetch and parse OpenSearch XML 767 + - [ ] Validate XML schema (ShortName, Url required) 768 + - [ ] Show install prompt (notification or cmd indicator) 769 + - [ ] User confirms → add to datastore 770 + - [ ] Test on popular sites (Wikipedia, GitHub, Stack Overflow) 771 + 772 + **Deliverables:** 773 + - content-discovery.js content script 774 + - XML parser with validation 775 + - Install prompt UI 776 + 777 + ### Phase 4: Search Suggestions (2 weeks) 778 + 779 + **Goal:** Show suggestions as user types 780 + 781 + - [ ] Implement suggestion-provider.js (fetch + parse) 782 + - [ ] Support OpenSearch JSON and Google-style formats 783 + - [ ] Debounce requests (200ms) 784 + - [ ] In-memory cache with TTL (5 min) 785 + - [ ] Integrate with cmd panel dropdown 786 + - [ ] Keyboard navigation (arrow keys, Enter) 787 + - [ ] Attribution footer ("Powered by X") 788 + 789 + **Deliverables:** 790 + - Suggestion API integration 791 + - Cache implementation 792 + - Cmd panel dropdown with suggestions 793 + 794 + ### Phase 5: Default Fallback & Polish (1 week) 795 + 796 + **Goal:** Unmatched input triggers default search 797 + 798 + - [ ] Cmd panel: detect unmatched input 799 + - [ ] Heuristic: check if it's a URL vs search query 800 + - [ ] Use default engine for non-URL input 801 + - [ ] Privacy mode: disable suggestions when enabled 802 + - [ ] Per-engine suggestion toggle 803 + - [ ] Error handling (network failures, timeouts) 804 + - [ ] Logging and telemetry 805 + 806 + **Deliverables:** 807 + - Default search fallback working 808 + - Privacy controls functional 809 + - Error states handled gracefully 810 + 811 + ### Phase 6: Testing & Documentation (1 week) 812 + 813 + **Goal:** Production-ready 814 + 815 + - [ ] Unit tests for engine CRUD 816 + - [ ] Unit tests for suggestion parsing 817 + - [ ] Integration tests: add engine, search, suggestions 818 + - [ ] E2E tests: OpenSearch discovery flow 819 + - [ ] Performance profiling (suggestion latency) 820 + - [ ] User documentation (help text in Settings) 821 + - [ ] Developer documentation (extension API) 822 + 823 + **Deliverables:** 824 + - Test suite with >80% coverage 825 + - Documentation in README or help page 826 + 827 + --- 828 + 829 + ## 10. Open Questions & Decisions 830 + 831 + ### 1. Default Search for Unmatched Input 832 + 833 + **Question:** Should the cmd bar automatically fall back to default search for unmatched input? 834 + 835 + **Options:** 836 + - A) **Always fallback** - Any unmatched text triggers default search 837 + - B) **Smart detection** - Only fallback if text looks like a query (>3 chars, has spaces) 838 + - C) **Explicit mode** - User must type `/search query` or set a "search mode" 839 + 840 + **Recommendation:** Option B (smart detection) with setting to disable. 841 + 842 + **Rationale:** Option A can be confusing if user typos a command. Option C requires extra keystrokes. Option B balances convenience and safety. 843 + 844 + ### 2. OpenSearch Auto-Install 845 + 846 + **Question:** Should Peek automatically install discovered search engines, or prompt user? 847 + 848 + **Options:** 849 + - A) **Auto-install** - Silent installation on every site with OpenSearch 850 + - B) **Prompt always** - Show notification/dialog for every discovery 851 + - C) **Smart prompt** - Prompt first time per domain, remember user choice 852 + 853 + **Recommendation:** Option C (smart prompt) with setting for auto-install. 854 + 855 + **Rationale:** Option A creates clutter (too many engines). Option B is annoying for users who visit many sites. Option C learns user preference. 856 + 857 + ### 3. Suggestion Privacy Default 858 + 859 + **Question:** Should search suggestions be enabled by default? 860 + 861 + **Options:** 862 + - A) **Enabled by default** - Opt-out in Settings 863 + - B) **Disabled by default** - Opt-in in Settings 864 + - C) **Prompt on first use** - Ask user's preference 865 + 866 + **Recommendation:** Option A (enabled) with privacy disclosures. 867 + 868 + **Rationale:** Most browsers enable suggestions by default. Users expect this feature. Privacy-conscious users can disable in Settings. 869 + 870 + ### 4. Per-Engine vs Global Suggestion Toggle 871 + 872 + **Question:** Should suggestion toggle be global, or per-engine? 873 + 874 + **Options:** 875 + - A) **Global only** - One switch for all engines 876 + - B) **Per-engine only** - Individual toggles 877 + - C) **Both** - Global + per-engine overrides 878 + 879 + **Recommendation:** Option C (both). 880 + 881 + **Rationale:** Most users want global toggle. Power users may want to disable suggestions for specific engines (e.g., privacy-focused engines). 882 + 883 + ### 5. Keyword Conflicts 884 + 885 + **Question:** What happens if two engines have the same keyword (e.g., both want "g")? 886 + 887 + **Options:** 888 + - A) **First wins** - First registered engine keeps keyword, second is rejected 889 + - B) **User resolves** - Prompt user to change keyword during installation 890 + - C) **Suffix collision** - Auto-append number (e.g., "g2") 891 + 892 + **Recommendation:** Option B (user resolves). 893 + 894 + **Rationale:** Option A silently fails. Option C creates confusing keywords. Option B gives user control. 895 + 896 + ### 6. Search Result Display 897 + 898 + **Question:** Where should search results open? 899 + 900 + **Options:** 901 + - A) **New window** - Always open in new BrowserWindow 902 + - B) **Current window** - Replace current page (if one exists) 903 + - C) **User setting** - Configurable in Settings 904 + 905 + **Recommendation:** Option C (user setting) with default to new window. 906 + 907 + **Rationale:** Different users have different preferences. Option A is safest default (doesn't disrupt current context). Option C provides flexibility. 908 + 909 + ### 7. Suggestion API Rate Limiting 910 + 911 + **Question:** How to handle search engines that rate-limit suggestions? 912 + 913 + **Options:** 914 + - A) **Ignore** - Let requests fail, show no suggestions 915 + - B) **Retry** - Exponential backoff, retry after delay 916 + - C) **Fallback** - Disable suggestions for that engine if rate-limited 917 + 918 + **Recommendation:** Option C (fallback) with retry after cooldown. 919 + 920 + **Rationale:** Option A provides poor UX. Option B can amplify rate-limiting. Option C gracefully degrades, re-enables after 5 minutes. 921 + 922 + ### 8. Sync Search Engines Across Devices 923 + 924 + **Question:** Should custom engines sync via Peek's sync system? 925 + 926 + **Options:** 927 + - A) **Yes, sync everything** - Built-in + custom engines 928 + - B) **Custom only** - Only user-added engines sync 929 + - C) **No sync** - Engines are device-local 930 + 931 + **Recommendation:** Option B (custom only). 932 + 933 + **Rationale:** Built-in engines are already on all devices. Custom engines are user-specific and should sync. Avoids conflicts with default engine preferences. 934 + 935 + --- 936 + 937 + ## 11. Security & Privacy 938 + 939 + ### Security Considerations 940 + 941 + **Injection Risks:** 942 + - Search URLs constructed from user input 943 + - Always use `encodeURIComponent()` for query params 944 + - Validate URL templates on installation (must contain `{searchTerms}`) 945 + - Never execute JavaScript in search URLs (no `javascript:` protocol) 946 + 947 + **Content Script Permissions:** 948 + - Discovery content script needs access to page HTML 949 + - Runs in isolated context (no access to page JS) 950 + - Only extracts `<link rel="search">` tags 951 + - Fetches OpenSearch XML via background fetch (not from page) 952 + 953 + **XML Parsing:** 954 + - Use DOMParser (built-in) to parse OpenSearch XML 955 + - Never use `eval()` or `Function()` on XML content 956 + - Validate schema strictly (whitelist allowed elements) 957 + - Reject XML with external entities (XXE protection) 958 + 959 + ### Privacy Protections 960 + 961 + **Suggestion Requests:** 962 + - Strip referer header 963 + - No cookies sent 964 + - Generic User-Agent (no personal identifiers) 965 + - Timeout: 2 seconds (prevents fingerprinting via timing) 966 + 967 + **Data Storage:** 968 + - Suggestions cached in-memory only (never disk) 969 + - Cache cleared on app quit 970 + - No history of search queries stored 971 + - User can disable suggestions globally 972 + 973 + **Third-Party Disclosure:** 974 + - Settings UI shows which engines provide suggestions 975 + - Link to engine's privacy policy (if available) 976 + - Warning: "Suggestions are provided by [Engine Name]. Your query is sent to their servers." 977 + 978 + --- 979 + 980 + ## 12. Performance Considerations 981 + 982 + ### Optimization Strategies 983 + 984 + **Debouncing:** 985 + - Wait 200ms after user stops typing before requesting suggestions 986 + - Cancel in-flight requests if user types again 987 + - Prevents excessive API calls 988 + 989 + **Caching:** 990 + - In-memory LRU cache (500 entries max) 991 + - 5 minute TTL per entry 992 + - Reduces redundant network requests 993 + - Cache hit rate should be >40% for common queries 994 + 995 + **Lazy Loading:** 996 + - Suggestion provider only loads when needed (first suggestion request) 997 + - Content discovery script only injected on navigation (not all frames) 998 + - Background script defers engine loading until cmd bar opens 999 + 1000 + **Network Timeouts:** 1001 + - Suggestion requests: 2 second timeout 1002 + - OpenSearch XML fetch: 5 second timeout 1003 + - Prevent hanging UI on slow networks 1004 + 1005 + ### Metrics to Track 1006 + 1007 + - Suggestion API latency (p50, p95, p99) 1008 + - Cache hit rate 1009 + - Number of engines installed (avg, max) 1010 + - Cmd execution time (p50, p95) 1011 + - OpenSearch discovery success rate 1012 + 1013 + --- 1014 + 1015 + ## 13. Alternative Approaches Considered 1016 + 1017 + ### Approach 1: Browser-Native Search API 1018 + 1019 + **Idea:** Use browser's built-in search engine list via WebExtension APIs 1020 + 1021 + **Pros:** 1022 + - No need to reimplement OpenSearch parsing 1023 + - Leverages browser's existing engine list 1024 + - Automatic updates for built-in engines 1025 + 1026 + **Cons:** 1027 + - Not available in Electron (no chrome.search.get() equivalent) 1028 + - Limited customization (can't modify engine list) 1029 + - Inconsistent across backends (Tauri, mobile) 1030 + 1031 + **Decision:** Rejected - Not portable across backends 1032 + 1033 + ### Approach 2: Third-Party Search API Aggregator 1034 + 1035 + **Idea:** Use service like Algolia or Elasticsearch to aggregate searches 1036 + 1037 + **Pros:** 1038 + - Unified API for multiple sources 1039 + - Advanced features (faceting, typo tolerance) 1040 + - Managed infrastructure (no rate limiting concerns) 1041 + 1042 + **Cons:** 1043 + - Cost (per-query pricing) 1044 + - Privacy implications (third-party data sharing) 1045 + - Vendor lock-in 1046 + - Latency (extra hop) 1047 + 1048 + **Decision:** Rejected - Violates privacy principles, not necessary for basic search 1049 + 1050 + ### Approach 3: DuckDuckGo !bang Syntax 1051 + 1052 + **Idea:** Use DuckDuckGo's !bang shortcuts (e.g., "!g query" searches Google) 1053 + 1054 + **Pros:** 1055 + - Already familiar to power users 1056 + - No need to manage engine list (DuckDuckGo handles it) 1057 + - Simple implementation (just redirect to DDG) 1058 + 1059 + **Cons:** 1060 + - Requires internet connection (DDG redirects) 1061 + - Extra network hop (latency) 1062 + - No control over engine list or settings 1063 + - No suggestions without DDG integration 1064 + 1065 + **Decision:** Considered as fallback option, but full implementation preferred for user control 1066 + 1067 + --- 1068 + 1069 + ## 14. Future Enhancements (Beyond MVP) 1070 + 1071 + ### Post-MVP Ideas 1072 + 1073 + 1. **Search History & Suggestions** 1074 + - Track recent searches per engine 1075 + - Show recent queries in dropdown 1076 + - Suggest previously searched terms 1077 + - Privacy: opt-in, clear on logout 1078 + 1079 + 2. **Search Scope Modifiers** 1080 + - `/google site:github.com query` - Search within specific site 1081 + - `/google filetype:pdf query` - Filter by file type 1082 + - Parse and apply modifiers to search URL 1083 + 1084 + 3. **Multi-Engine Meta-Search** 1085 + - `/search query` - Search multiple engines simultaneously 1086 + - Aggregate results in unified UI 1087 + - User can select which engines to include 1088 + 1089 + 4. **AI-Powered Query Refinement** 1090 + - Suggest better search queries based on context 1091 + - "Did you mean...?" for typos 1092 + - Related searches from LLM 1093 + 1094 + 5. **Search Templates & Macros** 1095 + - User-defined search shortcuts 1096 + - Example: `/bug <number>` → GitHub issue search 1097 + - Parameterized queries with placeholders 1098 + 1099 + 6. **Search Results Preview** 1100 + - Show preview of top result in cmd dropdown 1101 + - Fetch via search engine's API (if available) 1102 + - Quick answer snippets (Wikipedia) 1103 + 1104 + 7. **Voice Search Integration** 1105 + - Hotkey to activate voice input 1106 + - Speech-to-text → search query 1107 + - Hands-free search 1108 + 1109 + 8. **Contextual Search** 1110 + - Right-click selected text → "Search for [text]" 1111 + - Auto-select search engine based on content type 1112 + - Example: Code snippet → Stack Overflow, term → Wikipedia 1113 + 1114 + 9. **Search Analytics Dashboard** 1115 + - Show user's search patterns 1116 + - Most-used engines 1117 + - Query frequency over time 1118 + - Privacy: local-only, no cloud sync 1119 + 1120 + 10. **Custom Search Providers via Extensions** 1121 + - API for other extensions to register search providers 1122 + - Example: "Search my notes" extension 1123 + - Unified search across all data sources 1124 + 1125 + --- 1126 + 1127 + ## 15. Sources & References 1128 + 1129 + ### OpenSearch & Standards 1130 + - [OpenSearch description format - XML | MDN](https://developer.mozilla.org/en-US/docs/Web/XML/Guides/OpenSearch) 1131 + - [opensearch/opensearch-1-1-draft-6.md at master · dewitt/opensearch](https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md) 1132 + - [OpenSearch - IndieWeb](https://indieweb.org/OpenSearch) 1133 + - [OpenSearch (specification) - Wikipedia](https://en.wikipedia.org/wiki/OpenSearch_(specification)) 1134 + 1135 + ### Browser Implementation Patterns 1136 + - [How Chrome Detects OpenSearch Description Documents](https://prosperasoft.com/blog/enterprise-search/opensearch/opensearch-chrome-discovery/) 1137 + - [Search Engines — Firefox Source Docs documentation](https://firefox-source-docs.mozilla.org/toolkit/search/SearchEngines.html) 1138 + - [Integrate your website as a search provider in Microsoft Edge](https://www.ctrl.blog/entry/edge-search-provider.html) 1139 + 1140 + ### Browser APIs 1141 + - [search - Mozilla | MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/search) 1142 + - [chrome.search | API | Chrome for Developers](https://developer.chrome.com/docs/extensions/reference/api/search) 1143 + - [Search Service:API - MozillaWiki](https://wiki.mozilla.org/Search_Service:API) 1144 + 1145 + ### Privacy & Search APIs 1146 + - [Brave Search API | Brave](https://brave.com/search/api/) 1147 + - [Browser Privacy Policy | Brave](https://brave.com/privacy/browser/) 1148 + 1149 + ### Related Peek Documentation 1150 + - `notes/research-ui-componentry.md` - Peek component system 1151 + - `notes/extensibility.md` - Extension architecture 1152 + - `extensions/cmd/` - Command palette implementation 1153 + - `app/components/README.md` - Component library docs 1154 + 1155 + --- 1156 + 1157 + ## Critical Files for Implementation 1158 + 1159 + Based on this research, here are the most critical files for implementing the search extension: 1160 + 1161 + 1. **`extensions/search/background.js`** - Main extension logic, engine registry, command registration, OpenSearch discovery orchestration 1162 + 2. **`extensions/search/suggestion-provider.js`** - Handles API calls to search engines, caching, parsing responses, privacy controls 1163 + 3. **`extensions/search/settings.js`** - Management UI logic using peek-components, CRUD operations for engines 1164 + 4. **`extensions/cmd/panel.js`** (existing) - Integration point for search suggestions dropdown, fallback handler for unmatched input 1165 + 5. **`app/datastore/schema.js`** (existing) - Add `search_engines` table schema, migration for built-in engines 1166 + 1167 + --- 1168 + 1169 + ## Summary 1170 + 1171 + This search extension brings modern browser search capabilities to Peek through: 1172 + 1173 + 1. **OpenSearch Discovery** - Auto-detect and install search engines from websites 1174 + 2. **Command Integration** - Each engine gets a cmd (`/google`, `/ddg`) with suggestions 1175 + 3. **Management UI** - Full settings interface using peek-components 1176 + 4. **Smart Fallback** - Unmatched cmd input triggers default search 1177 + 5. **Privacy-First** - Anonymous suggestions, in-memory cache, user controls 1178 + 1179 + The implementation follows Peek's extension architecture, leverages the existing cmd system, and uses the peek-components library for consistent UI. Estimated 8-9 weeks for full MVP across 6 phases.