SPB Git

spb/zyquo-atlas Public License

The AI-native macOS web browser — every surface, intelligent.

Swift 75.2% JavaScript 22% Shell 2% Makefile 0.9%
3.1 KB · 84 lines swift
Raw Blame History
1//2//  OmniIntent.swift3//  Zyquo Atlas4//5//  Author: Simon-Pierre Boucher6//  Mail: contact@spboucher.ai7//8//  Resolves omnibox input into a navigable URL: direct navigation vs. web9//  search. This is the Phase 2 URL-vs-search half of the smart omnibox; the10//  Phase 3 "ask AI" intent (docs/AI-BROWSER-RESEARCH.md §4.1) layers on top as a11//  third route with explicit affordances — deliberately not auto-hijacking12//  navigate/search here.13//1415import Foundation1617enum OmniIntent: Equatable {18    /// Navigate directly to this URL.19    case navigate(URL)20    /// Run a web search for this query.21    case search(String)2223    /// The default search engine query template (`%@` replaced by the escaped query).24    static let searchTemplate = "https://duckduckgo.com/?q=%@"2526    /// Classify raw omnibox text. Bias toward navigate/search (reversible,27    /// cheap) per the research; the AI "ask" route is opt-in elsewhere.28    static func resolve(_ raw: String) -> OmniIntent {29        let text = raw.trimmingCharacters(in: .whitespacesAndNewlines)30        guard !text.isEmpty else { return .search("") }3132        // Explicit scheme (http/https/file/about/data) → navigate.33        if let url = URL(string: text), let scheme = url.scheme?.lowercased(),34           ["http", "https", "file", "about", "data"].contains(scheme) {35            return .navigate(url)36        }3738        // localhost / IP[:port] / bare host with a known-looking TLD and no39        // spaces → treat as a URL, defaulting to https.40        if !text.contains(" "), looksLikeHost(text) {41            if let url = URL(string: "https://\(text)") {42                return .navigate(url)43            }44        }4546        return .search(text)47    }4849    /// The URL to actually load for this intent.50    var url: URL? {51        switch self {52        case .navigate(let url):53            return url54        case .search(let query):55            let escaped = query.addingPercentEncoding(56                withAllowedCharacters: .urlQueryAllowed57            ) ?? query58            return URL(string: String(format: OmniIntent.searchTemplate, escaped))59        }60    }6162    // MARK: - Heuristics6364    private static func looksLikeHost(_ text: String) -> Bool {65        let host = text.split(separator: "/", maxSplits: 1).first.map(String.init) ?? text66        let bare = host.split(separator: ":", maxSplits: 1).first.map(String.init) ?? host67        if bare == "localhost" { return true }68        if isIPAddress(bare) { return true }69        // host.tld shape: at least one dot, a plausible TLD, no whitespace.70        guard let lastDot = bare.lastIndex(of: "."), lastDot != bare.startIndex else { return false }71        let tld = bare[bare.index(after: lastDot)...]72        return tld.count >= 2 && tld.allSatisfy { $0.isLetter }73    }7475    private static func isIPAddress(_ s: String) -> Bool {76        let parts = s.split(separator: ".")77        guard parts.count == 4 else { return false }78        return parts.allSatisfy { part in79            guard let n = Int(part) else { return false }80            return (0...255).contains(n)81        }82    }83}84