Add flow-launcher:// deep link protocol, .flowplugin file association, and --query command line argument

GA
3mo ago
+713-20

What

Adds a flow-launcher:// deep link protocol and .flowplugin file association, plus a --query "text" (also -query) command-line flag, so scripts, browsers, and other apps can open/focus Flow Launcher to run a query, open settings, or install a plugin.

  • --query "text" / -q "text": opens/focuses Flow Launcher with the query pre-filled and searched.
  • flow-launcher://query?q=..., flow-launcher://settings, flow-launcher://plugin/install?path=|id=|url=: routed through a general verb-dispatch framework. Plugin installs always show the existing Yes/No confirmation dialog — never silent, whether triggered by a local .flowplugin double-click, a store id, or an https download URL.
  • .flowplugin file association and the flow-launcher:// URI scheme are self-healing HKCU registrations applied at every startup (no admin rights required), with a new Settings toggle, "Allow websites to open Flow Launcher", to opt out.
  • Cold start (no instance running): the deep link is dispatched right after plugin initialization, then the main window is shown.
  • Warm start (instance already running): the second process normalizes its args to a flow-launcher:// URI and sends it to the first instance over the existing single-instance named pipe, then exits; the first instance dispatches it.
  • No args: behavior is unchanged — a second launch just shows/focuses the window.

How

  • Flow.Launcher/Helper/DeepLink.cs: normalizes command-line args (--query, .flowplugin paths, raw flow-launcher:// URIs) into a single URI string, parses a URI into a verb + query parameters, and dispatches to handlers for query, settings, and plugin/install.
  • Flow.Launcher/Helper/DeepLinkRegistration.cs: idempotent HKCU registration for the .flowplugin ProgID and the flow-launcher:// scheme, called on every startup so stale executable paths self-heal after updates.
  • Flow.Launcher.Core/Plugin/PluginInstaller.cs: adds InstallPluginFromWebAndCheckRestartAsync(url), reusing the existing unknown-source warning and the always-prompting InstallPluginAndCheckRestartAsync.
  • App.xaml.cs: Main(string[] args) normalizes args via DeepLink.FromCommandLineArgs; the pending deep link is dispatched after PluginManager.InitializePluginsAsync, before the home-page refresh check; OnSecondAppStarted(string payload) dispatches the warm-path payload (or just shows the window when empty).
  • SingleInstance.cs: the named pipe now carries an optional payload — the normalized deep link URI (or legacy plain query text). The client writes it as a newline-terminated UTF-8 line and blocks (up to 3 s) since the process exits immediately after; the server reads one line guarded by a 2 s timeout and try/catch, so a client that connects but never writes degrades to a plain activation and can never hang the server loop.
  • Settings.EnableDeepLinkProtocol (default true) gates the URI scheme registration; toggling it in Settings registers/unregisters the scheme immediately via DeepLinkRegistration.

Test matrix (manual, Windows)

  1. No args, cold start — unchanged behavior (home page etc.)
  2. --query "foo" / -query "foo", cold and warm — window opens/focuses with "foo" searched
  3. Warm start, no args — window just shows/focuses (regression check)
  4. --query "" — treated as no query
  5. Double-click a .flowplugin (Flow running and not running) — confirmation dialog, install only on Yes
  6. flow-launcher://query?q=foo, flow-launcher://settings, flow-launcher://plugin/install?id=... / ?path=... / ?url=https://...zip from a browser — routed correctly, every install prompts
  7. ?url=http://... (non-https) — rejected with an https-only message
  8. flow-launcher://nope — error notification, no crash
  9. Settings toggle off — HKCU\Software\Classes\flow-launcher removed, browser links no longer open Flow; .flowplugin double-click and --query still work. Toggle on — restored
  10. Corrupt the registered command path manually, relaunch — self-healed
  11. Robustness: a client that connects to the pipe without writing/closing — server loop recovers after the 2 s read timeout and keeps accepting connections

Summary by cubic

Summary of changes
Adds a flow-launcher:// deep link and .flowplugin association plus a --query/-q flag so scripts and websites can open Flow Launcher, run searches, open settings, or install plugins. When the URI scheme is disabled or no args are provided, launch behavior is unchanged; second-instance invocations forward a normalized deep link to the running app over IPC.

  • Changed
    • Single-instance IPC now carries an optional UTF-8 deep-link payload; server cancels the read after 2s, client connect waits up to 3s, and the outer delivery wait is 5s so payloads are not dropped; dispatcher activation exceptions are observed.
    • Pipe read timeouts become plain activations; genuine read failures are logged.
    • App.Main(string[] args) normalizes args to a deep link; dispatch happens after plugins initialize. Links received during startup are queued so none are lost. OnSecondAppStarted(string payload) routes a payload; empty payload focuses the window.
    • CLI supports --query and -q; empty queries are ignored.
    • Deep link protocol toggle updates registry immediately and reverts the toggle if registration fails.
    • Logging keeps full deep-link payloads at Debug; Warn logs only the actionable fact.
  • Added
    • Deep link parser/dispatcher with verbs: query, settings, and plugin/install (by .flowplugin path, store id, or https URL). Helper HasExactlyOneInstallIdentifier validates install links.
    • HKCU registration for .flowplugin and the flow-launcher:// scheme, gated by a new General Settings toggle “Allow websites to open Flow Launcher”; registration is ensured at startup.
    • PluginInstaller.InstallPluginFromWebAndCheckRestartAsync with unknown-source confirmation; DerivePluginNameFromUrl sanitizes filenames and falls back to a safe default; TryPopulateIdFromZip recovers the real plugin ID for URL installs to keep modified-plugin tracking correct.
    • UI strings and a General Settings toggle. Unit tests: DeepLinkTest (arg normalization, scheme-disabled behavior, URI parsing) and PluginInstallerTest (URL filename derivation edge cases).
  • Removed
    • Old OnSecondAppStarted() overload; no user-visible features removed.
  • Memory
    • Negligible: short-lived strings and small stream buffers; no persistent allocations.
  • Security
    • URI scheme is opt-in and per-user (HKCU). Named pipe remains per-user. Deep links are parsed/validated; plugin installs require https URLs or an existing local file; store-id installs validate against the manifest. Payload logging is minimized; IPC timeouts prevent hangs.
  • Tests
    • Added DeepLinkTest and PluginInstallerTest; manual verification of cold/warm starts, empty queries, startup-queued links, and all plugin install paths.

Release Note
Open Flow Launcher from your browser or scripts to search, open settings, or install plugins using special links or the new --query option.