@immediately-run/omnibox 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,260 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
3
+ import "./omnibox.css";
4
+ import { parseLaunch, PROVIDERS } from "./launch";
5
+ import { PlatformLink } from "@immediately-run/sdk/platformLink";
6
+ import { focusHeroOmnibox, registerOmniboxFocus } from "./omniboxFocus";
7
+ function useMediaQuery(query) {
8
+ const [matches, setMatches] = useState(
9
+ () => typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(query).matches : false
10
+ );
11
+ useEffect(() => {
12
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
13
+ const mq = window.matchMedia(query);
14
+ const onChange = () => setMatches(mq.matches);
15
+ onChange();
16
+ mq.addEventListener("change", onChange);
17
+ return () => mq.removeEventListener("change", onChange);
18
+ }, [query]);
19
+ return matches;
20
+ }
21
+ function appScore(hit, q) {
22
+ if (hit.name.toLowerCase().startsWith(q)) return 4;
23
+ if (hit.name.toLowerCase().includes(q)) return 3;
24
+ if (hit.repo.toLowerCase().includes(q)) return 2;
25
+ if (hit.blurb.toLowerCase().includes(q)) return 1;
26
+ if (hit.category.toLowerCase().includes(q)) return 0;
27
+ return -1;
28
+ }
29
+ const appRoute = (repo) => `/present/github/immediately-run/${repo}/main/files/src/App.tsx`;
30
+ function Omnibox({ variant, heroShortcut = false, hits, renderChip }) {
31
+ const isMobile = useMediaQuery("(max-width: 720px)");
32
+ const [query, setQuery] = useState("");
33
+ const [highlight, setHighlight] = useState(-1);
34
+ const inputRef = useRef(null);
35
+ const outerRef = useRef(null);
36
+ const listId = useId();
37
+ const inputId = `${listId}-input`;
38
+ const helperId = useId();
39
+ const noticeId = useId();
40
+ const warnedSources = useRef(/* @__PURE__ */ new Set());
41
+ const callSource = useCallback(
42
+ function callSource2(kind, source, q) {
43
+ try {
44
+ return source(q);
45
+ } catch (error) {
46
+ if (!warnedSources.current.has(kind)) {
47
+ warnedSources.current.add(kind);
48
+ console.warn(`omnibox: the "${String(kind)}" hit source threw and is disabled for this mount`, error);
49
+ }
50
+ return [];
51
+ }
52
+ },
53
+ []
54
+ );
55
+ const parsed = useMemo(() => parseLaunch(query), [query]);
56
+ const runnable = parsed.kind === "location" || parsed.kind === "platform-url";
57
+ const runPath = parsed.kind === "location" ? parsed.presentPath : parsed.kind === "platform-url" ? parsed.path : void 0;
58
+ const panelOpen = query.trim() !== "";
59
+ const [prevQuery, setPrevQuery] = useState(query);
60
+ if (prevQuery !== query) {
61
+ setPrevQuery(query);
62
+ setHighlight(-1);
63
+ }
64
+ const notice = parsed.kind === "unknown-provider" ? `${parsed.provider.charAt(0).toUpperCase()}${parsed.provider.slice(1)} is not supported yet. GitHub works today.` : "";
65
+ const helper = variant === "new" ? "the repo you just created" : "Accepts provider:namespace/repository@ref \xB7 GitHub is the first provider";
66
+ const appHits = useMemo(() => {
67
+ if (!panelOpen || !hits?.apps) return [];
68
+ const q = query.trim().toLowerCase();
69
+ return callSource("apps", hits.apps, q).map((hit) => ({ hit, score: appScore(hit, q) })).filter(({ score }) => score >= 0).sort((a, b) => b.score - a.score).map(({ hit }) => hit);
70
+ }, [panelOpen, query, hits, callSource]);
71
+ const docHits = useMemo(() => {
72
+ if (!panelOpen || !hits?.docs) return [];
73
+ return callSource("docs", hits.docs, query.trim().toLowerCase());
74
+ }, [panelOpen, query, hits, callSource]);
75
+ const locationRow = parsed.kind === "location" ? parsed : void 0;
76
+ const hasResults = Boolean(locationRow) || appHits.length > 0 || docHits.length > 0;
77
+ const options = useMemo(() => {
78
+ const list = [];
79
+ if (locationRow) list.push({ id: `${listId}-opt-location`, label: locationRow.display });
80
+ for (const hit of appHits) list.push({ id: `${listId}-opt-${hit.key}`, label: hit.name });
81
+ for (const hit of docHits) list.push({ id: `${listId}-opt-doc-${hit.key}`, label: hit.title });
82
+ return list;
83
+ }, [locationRow, appHits, docHits, listId]);
84
+ useEffect(
85
+ () => registerOmniboxFocus(variant, {
86
+ focus: () => inputRef.current?.focus(),
87
+ reveal: () => outerRef.current?.scrollIntoView({ behavior: "smooth", block: "center" })
88
+ }),
89
+ [variant]
90
+ );
91
+ const onKeyDown = useCallback(
92
+ (e) => {
93
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
94
+ if (!panelOpen || options.length === 0) return;
95
+ e.preventDefault();
96
+ setHighlight((h) => {
97
+ if (h === -1) return e.key === "ArrowDown" ? 0 : options.length - 1;
98
+ return (h + (e.key === "ArrowDown" ? 1 : -1) + options.length) % options.length;
99
+ });
100
+ return;
101
+ }
102
+ if (e.key === "Enter") {
103
+ if (highlight >= 0 && highlight < options.length) {
104
+ e.preventDefault();
105
+ document.getElementById(options[highlight].id)?.click();
106
+ return;
107
+ }
108
+ if (runnable) {
109
+ e.preventDefault();
110
+ document.getElementById(`${listId}-run`)?.click();
111
+ }
112
+ return;
113
+ }
114
+ if (e.key === "Escape") {
115
+ setQuery("");
116
+ setHighlight(-1);
117
+ inputRef.current?.blur();
118
+ }
119
+ },
120
+ [panelOpen, options, highlight, runnable, listId]
121
+ );
122
+ const chip = /* @__PURE__ */ jsx("span", { className: "omnibox-chip", "aria-hidden": Object.keys(PROVIDERS).length === 1 || void 0, children: Object.keys(PROVIDERS).length === 1 ? (
123
+ // One provider: a static label with no caret — NOT a dropdown of
124
+ // providers that do not exist.
125
+ /* @__PURE__ */ jsx("span", { className: "omnibox-chip-label", children: "github" })
126
+ ) : /* @__PURE__ */ jsx("select", { className: "omnibox-chip-select", "aria-label": "Provider", children: Object.keys(PROVIDERS).map((p) => /* @__PURE__ */ jsx("option", { value: p, children: p }, p)) }) });
127
+ const run = runPath !== void 0 ? /* @__PURE__ */ jsxs(
128
+ PlatformLink,
129
+ {
130
+ id: `${listId}-run`,
131
+ className: "omnibox-run",
132
+ path: runPath,
133
+ "aria-label": "Run",
134
+ children: [
135
+ /* @__PURE__ */ jsx("span", { className: "omnibox-run-label", children: "Run" }),
136
+ /* @__PURE__ */ jsx("span", { className: "omnibox-run-arrow", "aria-hidden": "true", children: "\u2192" })
137
+ ]
138
+ }
139
+ ) : /* @__PURE__ */ jsxs(
140
+ "button",
141
+ {
142
+ id: `${listId}-run`,
143
+ type: "button",
144
+ className: "omnibox-run",
145
+ "aria-disabled": "true",
146
+ "aria-describedby": `${helperId} ${noticeId}`,
147
+ onClick: (e) => e.preventDefault(),
148
+ children: [
149
+ /* @__PURE__ */ jsx("span", { className: "omnibox-run-label", children: "Run" }),
150
+ /* @__PURE__ */ jsx("span", { className: "omnibox-run-arrow", "aria-hidden": "true", children: "\u2192" })
151
+ ]
152
+ }
153
+ );
154
+ const field = /* @__PURE__ */ jsxs("div", { className: `omnibox omnibox--${variant}`, children: [
155
+ /* @__PURE__ */ jsxs("div", { className: "omnibox-row", children: [
156
+ chip,
157
+ /* @__PURE__ */ jsx(
158
+ "input",
159
+ {
160
+ ref: inputRef,
161
+ id: inputId,
162
+ className: "omnibox-input",
163
+ type: "text",
164
+ role: "combobox",
165
+ "aria-autocomplete": "list",
166
+ "aria-expanded": panelOpen,
167
+ "aria-controls": panelOpen ? listId : void 0,
168
+ "aria-activedescendant": highlight >= 0 ? options[highlight]?.id : void 0,
169
+ "aria-describedby": `${helperId} ${noticeId}`,
170
+ "aria-invalid": notice ? true : void 0,
171
+ placeholder: isMobile ? "Paste a repo or an app name" : "owner/repo@branch, a GitHub URL, or an app name",
172
+ value: query,
173
+ onChange: (e) => setQuery(e.target.value),
174
+ onKeyDown
175
+ }
176
+ ),
177
+ run
178
+ ] }),
179
+ /* @__PURE__ */ jsx("p", { className: "omnibox-helper", id: helperId, children: notice || helper }),
180
+ /* @__PURE__ */ jsx("p", { className: "omnibox-visually-hidden", id: noticeId, "aria-live": "polite", children: notice }),
181
+ panelOpen && /* @__PURE__ */ jsx("div", { className: "omnibox-panel", id: listId, role: "listbox", "aria-label": "Results", children: hasResults ? /* @__PURE__ */ jsxs(Fragment, { children: [
182
+ locationRow && /* @__PURE__ */ jsx("div", { className: "omnibox-group", role: "group", "aria-label": "Run from source", children: /* @__PURE__ */ jsxs(
183
+ PlatformLink,
184
+ {
185
+ id: `${listId}-opt-location`,
186
+ className: "omnibox-option",
187
+ role: "option",
188
+ "aria-selected": highlight === 0,
189
+ path: locationRow.presentPath,
190
+ children: [
191
+ /* @__PURE__ */ jsx("span", { className: "omnibox-option-name", children: locationRow.display }),
192
+ /* @__PURE__ */ jsx("span", { className: "omnibox-option-action", children: "Run" })
193
+ ]
194
+ }
195
+ ) }),
196
+ appHits.length > 0 && /* @__PURE__ */ jsx("div", { className: "omnibox-group", role: "group", "aria-label": "Apps in the directory", children: appHits.map((hit) => {
197
+ const idx = options.findIndex((o) => o.id === `${listId}-opt-${hit.key}`);
198
+ return /* @__PURE__ */ jsxs(
199
+ PlatformLink,
200
+ {
201
+ id: `${listId}-opt-${hit.key}`,
202
+ className: "omnibox-option",
203
+ role: "option",
204
+ "aria-selected": highlight === idx,
205
+ path: appRoute(hit.repo),
206
+ children: [
207
+ /* @__PURE__ */ jsx("span", { className: "omnibox-option-name", children: hit.name }),
208
+ /* @__PURE__ */ jsx("span", { className: "omnibox-option-cat", children: hit.category }),
209
+ /* @__PURE__ */ jsx("span", { className: "omnibox-option-blurb", children: hit.blurb }),
210
+ renderChip?.(hit)
211
+ ]
212
+ },
213
+ hit.key
214
+ );
215
+ }) }),
216
+ docHits.length > 0 && /* @__PURE__ */ jsx("div", { className: "omnibox-group", role: "group", "aria-label": "Docs and tutorials", children: docHits.map((hit) => {
217
+ const idx = options.findIndex((o) => o.id === `${listId}-opt-doc-${hit.key}`);
218
+ return /* @__PURE__ */ jsxs(
219
+ "a",
220
+ {
221
+ id: `${listId}-opt-doc-${hit.key}`,
222
+ className: "omnibox-option",
223
+ role: "option",
224
+ "aria-selected": highlight === idx,
225
+ href: hit.href,
226
+ children: [
227
+ /* @__PURE__ */ jsx("span", { className: "omnibox-option-name", children: hit.title }),
228
+ /* @__PURE__ */ jsx("span", { className: "omnibox-option-blurb", children: hit.lead })
229
+ ]
230
+ },
231
+ hit.key
232
+ );
233
+ }) })
234
+ ] }) : /* @__PURE__ */ jsx("div", { className: "omnibox-empty", children: "Nothing matched. Try an app name, or paste a repo." }) })
235
+ ] });
236
+ if (variant === "nav" && heroShortcut) {
237
+ return /* @__PURE__ */ jsxs(
238
+ "button",
239
+ {
240
+ type: "button",
241
+ className: "omnibox-nav-button",
242
+ onClick: () => focusHeroOmnibox(),
243
+ "aria-label": "Search apps and docs, or paste a repo",
244
+ children: [
245
+ /* @__PURE__ */ jsx("span", { className: "omnibox-nav-button-label", children: "Search" }),
246
+ /* @__PURE__ */ jsx("span", { className: "kbd", children: "\u2318K" })
247
+ ]
248
+ }
249
+ );
250
+ }
251
+ return /* @__PURE__ */ jsxs("div", { className: `omnibox-outer omnibox-outer--${variant}`, ref: outerRef, children: [
252
+ /* @__PURE__ */ jsx("label", { className: "omnibox-visually-hidden", htmlFor: inputId, children: "Paste a repo, or search apps and docs" }),
253
+ field
254
+ ] });
255
+ }
256
+ var Omnibox_default = Omnibox;
257
+ export {
258
+ Omnibox_default as default
259
+ };
260
+ //# sourceMappingURL=Omnibox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Omnibox.tsx"],"sourcesContent":["import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { KeyboardEvent as ReactKeyboardEvent, ReactNode } from 'react';\nimport './omnibox.css';\nimport { parseLaunch, PROVIDERS, type Launch } from './launch';\nimport { PlatformLink } from '@immediately-run/sdk/platformLink';\nimport { focusHeroOmnibox, registerOmniboxFocus } from './omniboxFocus';\nimport type { OmniboxVariant } from './omniboxFocus';\n\n// The omnibox (R3-512; FRONT_DOOR_IA §5) — the front door's primary control. It\n// does W1 (run a repo by URL or tuple) and W2 (find an app) in one place, as a\n// WAI-ARIA list-autocomplete combobox with three result groups of ONE action per\n// row. Run and Open rows render through `PlatformLink`, which resolves the\n// host-space href and escapes the frame: a platform route navigates the HOST\n// document, and a root-relative href inside the sandboxed frame would resolve\n// against the sandbox origin and land nowhere.\n//\n// The package owns the component and the launch grammar; it owns NO data. The\n// app-directory and docs hit sources are injected per app (`hits`), because the\n// package cannot depend on a consumer's records (R3-530).\n\nfunction useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(() =>\n typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia(query).matches\n : false,\n );\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return;\n const mq = window.matchMedia(query);\n const onChange = () => setMatches(mq.matches);\n onChange();\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, [query]);\n return matches;\n}\n\n/* ── the hit vocabulary a consumer's sources speak ──────────────────────── */\n\nexport interface AppHit {\n key: string;\n name: string;\n category: string;\n blurb: string;\n /** The repository the row opens — an org repo under immediately-run. */\n repo: string;\n /** Opaque to the package: a consumer's `renderChip` reads it back. */\n provenance?: unknown;\n}\n\nexport interface DocHit {\n key: string;\n title: string;\n lead: string;\n /** A real href — copy-link, middle-click and open-in-new-tab all resolve it. */\n href: string;\n}\n\n/** The data seams. Absent sources simply yield no rows of their kind; an omnibox\n * with no `hits` at all is the launch grammar only (what the Home app renders). */\nexport interface OmniboxHitSources {\n /** Candidate app hits for a query; the package ranks, filters and orders them. */\n apps?: (query: string) => AppHit[];\n /** Matched doc hits for a query, best-first, capped by the source. */\n docs?: (query: string) => DocHit[];\n}\n\n/* ── ranking ────────────────────────────────────────────────────────────── */\n\n/** name-prefix > name-substring > repo > blurb > category (FRONT_DOOR_IA §5.3).\n * Internal: the ranking is the package's policy, not part of the surface. */\nfunction appScore(hit: AppHit, q: string): number {\n if (hit.name.toLowerCase().startsWith(q)) return 4;\n if (hit.name.toLowerCase().includes(q)) return 3;\n if (hit.repo.toLowerCase().includes(q)) return 2;\n if (hit.blurb.toLowerCase().includes(q)) return 1;\n if (hit.category.toLowerCase().includes(q)) return 0;\n return -1;\n}\n\n/** The platform path an app row opens. The directory's apps are org repos that\n * open at their entry — the one shape an injected `apps` source feeds. */\nconst appRoute = (repo: string) => `/present/github/immediately-run/${repo}/main/files/src/App.tsx`;\n\n/* ── the component ──────────────────────────────────────────────────────── */\n\nexport interface OmniboxProps {\n variant: OmniboxVariant;\n /** Nav variant only: true while the hero omnibox is mounted (`/`), so the\n * nav field renders as the shortcut that focuses it. Derived by the caller\n * from the route — render-time data, not an effect. */\n heroShortcut?: boolean;\n /** App-directory and docs hit sources. Absent → the launch grammar only. */\n hits?: OmniboxHitSources;\n /** Renders the app row's trailing chip (e.g. a provenance chip). The chip is a\n * site component with site data types, so the package renders what it is given. */\n renderChip?: (hit: AppHit) => ReactNode;\n}\n\nfunction Omnibox({ variant, heroShortcut = false, hits, renderChip }: OmniboxProps) {\n const isMobile = useMediaQuery('(max-width: 720px)');\n const [query, setQuery] = useState('');\n const [highlight, setHighlight] = useState(-1);\n const inputRef = useRef<HTMLInputElement>(null);\n const outerRef = useRef<HTMLDivElement>(null);\n const listId = useId();\n const inputId = `${listId}-input`;\n const helperId = useId();\n const noticeId = useId();\n // A source that throws is degraded, not fatal: logged ONCE per source, then\n // that group stays empty — the location row still renders.\n const warnedSources = useRef<Set<keyof OmniboxHitSources>>(new Set());\n const callSource = useCallback(\n function callSource<K extends keyof OmniboxHitSources>(\n kind: K,\n source: OmniboxHitSources[K],\n q: string,\n ): ReturnType<NonNullable<OmniboxHitSources[K]>> | [] {\n try {\n return source!(q) as ReturnType<NonNullable<OmniboxHitSources[K]>>;\n } catch (error) {\n if (!warnedSources.current.has(kind)) {\n warnedSources.current.add(kind);\n console.warn(`omnibox: the \"${String(kind)}\" hit source threw and is disabled for this mount`, error);\n }\n return [];\n }\n },\n [],\n );\n\n const parsed: Launch = useMemo(() => parseLaunch(query), [query]);\n const runnable = parsed.kind === 'location' || parsed.kind === 'platform-url';\n const runPath =\n parsed.kind === 'location'\n ? parsed.presentPath\n : parsed.kind === 'platform-url'\n ? parsed.path\n : undefined;\n\n const panelOpen = query.trim() !== '';\n\n // Adjusting state during render (the sanctioned pattern): the highlight must\n // not survive the option set changing under it, and an effect would cascade.\n const [prevQuery, setPrevQuery] = useState(query);\n if (prevQuery !== query) {\n setPrevQuery(query);\n setHighlight(-1);\n }\n\n // Unknown provider → the notice replaces the helper line's text and is\n // announced through the live region.\n const notice =\n parsed.kind === 'unknown-provider'\n ? `${parsed.provider.charAt(0).toUpperCase()}${parsed.provider.slice(1)} is not supported yet. GitHub works today.`\n : '';\n\n const helper =\n variant === 'new' ? 'the repo you just created' : 'Accepts provider:namespace/repository@ref · GitHub is the first provider';\n\n const appHits = useMemo(() => {\n if (!panelOpen || !hits?.apps) return [];\n const q = query.trim().toLowerCase();\n return callSource('apps', hits.apps, q)\n .map((hit) => ({ hit, score: appScore(hit, q) }))\n .filter(({ score }) => score >= 0)\n .sort((a, b) => b.score - a.score)\n .map(({ hit }) => hit);\n }, [panelOpen, query, hits, callSource]);\n\n const docHits = useMemo(() => {\n if (!panelOpen || !hits?.docs) return [];\n return callSource('docs', hits.docs, query.trim().toLowerCase());\n }, [panelOpen, query, hits, callSource]);\n\n const locationRow = parsed.kind === 'location' ? parsed : undefined;\n const hasResults = Boolean(locationRow) || appHits.length > 0 || docHits.length > 0;\n\n // Flattened options, in group order — the arrow-key walk and the highlight id\n // both read this list.\n const options = useMemo(() => {\n const list: { id: string; label: string }[] = [];\n if (locationRow) list.push({ id: `${listId}-opt-location`, label: locationRow.display });\n for (const hit of appHits) list.push({ id: `${listId}-opt-${hit.key}`, label: hit.name });\n for (const hit of docHits) list.push({ id: `${listId}-opt-doc-${hit.key}`, label: hit.title });\n return list;\n }, [locationRow, appHits, docHits, listId]);\n\n // Register with the focus registry (⌘K, the nav shortcut and the \"paste a repo\"\n // CTAs all land here). `reveal` is what lets those CTAs scroll this field into\n // view without any component querying for its CSS class.\n useEffect(\n () =>\n registerOmniboxFocus(variant, {\n focus: () => inputRef.current?.focus(),\n reveal: () => outerRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' }),\n }),\n [variant],\n );\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n if (!panelOpen || options.length === 0) return;\n e.preventDefault();\n setHighlight((h) => {\n if (h === -1) return e.key === 'ArrowDown' ? 0 : options.length - 1;\n return (h + (e.key === 'ArrowDown' ? 1 : -1) + options.length) % options.length;\n });\n return;\n }\n if (e.key === 'Enter') {\n if (highlight >= 0 && highlight < options.length) {\n e.preventDefault();\n document.getElementById(options[highlight].id)?.click();\n return;\n }\n if (runnable) {\n e.preventDefault();\n document.getElementById(`${listId}-run`)?.click();\n }\n return;\n }\n if (e.key === 'Escape') {\n // Close the panel, then clear the highlight, then blur — in that order.\n setQuery('');\n setHighlight(-1);\n inputRef.current?.blur();\n }\n },\n [panelOpen, options, highlight, runnable, listId],\n );\n\n const chip = (\n <span className=\"omnibox-chip\" aria-hidden={Object.keys(PROVIDERS).length === 1 || undefined}>\n {Object.keys(PROVIDERS).length === 1 ? (\n // One provider: a static label with no caret — NOT a dropdown of\n // providers that do not exist.\n <span className=\"omnibox-chip-label\">github</span>\n ) : (\n <select className=\"omnibox-chip-select\" aria-label=\"Provider\">\n {Object.keys(PROVIDERS).map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n )}\n </span>\n );\n\n const run = runPath !== undefined ? (\n <PlatformLink\n id={`${listId}-run`}\n className=\"omnibox-run\"\n path={runPath}\n aria-label=\"Run\"\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </PlatformLink>\n ) : (\n <button\n id={`${listId}-run`}\n type=\"button\"\n className=\"omnibox-run\"\n aria-disabled=\"true\"\n aria-describedby={`${helperId} ${noticeId}`}\n onClick={(e) => e.preventDefault()}\n >\n <span className=\"omnibox-run-label\">Run</span>\n <span className=\"omnibox-run-arrow\" aria-hidden=\"true\">\n →\n </span>\n </button>\n );\n\n const field = (\n <div className={`omnibox omnibox--${variant}`}>\n <div className=\"omnibox-row\">\n {chip}\n <input\n ref={inputRef}\n id={inputId}\n className=\"omnibox-input\"\n type=\"text\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-expanded={panelOpen}\n aria-controls={panelOpen ? listId : undefined}\n aria-activedescendant={highlight >= 0 ? options[highlight]?.id : undefined}\n aria-describedby={`${helperId} ${noticeId}`}\n aria-invalid={notice ? true : undefined}\n placeholder={isMobile ? 'Paste a repo or an app name' : 'owner/repo@branch, a GitHub URL, or an app name'}\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n />\n {run}\n </div>\n <p className=\"omnibox-helper\" id={helperId}>\n {notice || helper}\n </p>\n {/* The live region announces the notice; empty in the common case. */}\n <p className=\"omnibox-visually-hidden\" id={noticeId} aria-live=\"polite\">\n {notice}\n </p>\n {panelOpen && (\n <div className=\"omnibox-panel\" id={listId} role=\"listbox\" aria-label=\"Results\">\n {hasResults ? (\n <>\n {locationRow && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Run from source\">\n <PlatformLink\n id={`${listId}-opt-location`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === 0}\n path={locationRow.presentPath}\n >\n <span className=\"omnibox-option-name\">{locationRow.display}</span>\n <span className=\"omnibox-option-action\">Run</span>\n </PlatformLink>\n </div>\n )}\n {appHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Apps in the directory\">\n {appHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-${hit.key}`);\n return (\n <PlatformLink\n key={hit.key}\n id={`${listId}-opt-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n path={appRoute(hit.repo)}\n >\n <span className=\"omnibox-option-name\">{hit.name}</span>\n <span className=\"omnibox-option-cat\">{hit.category}</span>\n <span className=\"omnibox-option-blurb\">{hit.blurb}</span>\n {renderChip?.(hit)}\n </PlatformLink>\n );\n })}\n </div>\n )}\n {docHits.length > 0 && (\n <div className=\"omnibox-group\" role=\"group\" aria-label=\"Docs and tutorials\">\n {docHits.map((hit) => {\n const idx = options.findIndex((o) => o.id === `${listId}-opt-doc-${hit.key}`);\n return (\n <a\n key={hit.key}\n id={`${listId}-opt-doc-${hit.key}`}\n className=\"omnibox-option\"\n role=\"option\"\n aria-selected={highlight === idx}\n href={hit.href}\n >\n <span className=\"omnibox-option-name\">{hit.title}</span>\n <span className=\"omnibox-option-blurb\">{hit.lead}</span>\n </a>\n );\n })}\n </div>\n )}\n </>\n ) : (\n <div className=\"omnibox-empty\">Nothing matched. Try an app name, or paste a repo.</div>\n )}\n </div>\n )}\n </div>\n );\n\n // The nav variant collapses to a shortcut button while the hero omnibox is\n // mounted (on `/`): activating it focuses the hero field. On every other\n // route the field expands in place.\n if (variant === 'nav' && heroShortcut) {\n return (\n <button\n type=\"button\"\n className=\"omnibox-nav-button\"\n onClick={() => focusHeroOmnibox()}\n aria-label=\"Search apps and docs, or paste a repo\"\n >\n <span className=\"omnibox-nav-button-label\">Search</span>\n <span className=\"kbd\">⌘K</span>\n </button>\n );\n }\n\n return (\n <div className={`omnibox-outer omnibox-outer--${variant}`} ref={outerRef}>\n <label className=\"omnibox-visually-hidden\" htmlFor={inputId}>\n Paste a repo, or search apps and docs\n </label>\n {field}\n </div>\n );\n}\n\nexport default Omnibox;\n"],"mappings":"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","names":["callSource"]}
package/dist/index.cjs ADDED
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var index_exports = {};
30
+ __export(index_exports, {
31
+ Omnibox: () => import_Omnibox.default,
32
+ PROVIDERS: () => import_launch.PROVIDERS,
33
+ focusHeroOmnibox: () => import_omniboxFocus.focusHeroOmnibox,
34
+ focusOmnibox: () => import_omniboxFocus.focusOmnibox,
35
+ parseLaunch: () => import_launch.parseLaunch,
36
+ registerOmniboxFocus: () => import_omniboxFocus.registerOmniboxFocus,
37
+ revealHeroOmnibox: () => import_omniboxFocus.revealHeroOmnibox
38
+ });
39
+ module.exports = __toCommonJS(index_exports);
40
+ var import_Omnibox = __toESM(require("./Omnibox"), 1);
41
+ var import_launch = require("./launch");
42
+ var import_omniboxFocus = require("./omniboxFocus");
43
+ // Annotate the CommonJS export names for ESM import in node:
44
+ 0 && (module.exports = {
45
+ Omnibox,
46
+ PROVIDERS,
47
+ focusHeroOmnibox,
48
+ focusOmnibox,
49
+ parseLaunch,
50
+ registerOmniboxFocus,
51
+ revealHeroOmnibox
52
+ });
53
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { default as Omnibox } from './Omnibox';\nexport type { OmniboxProps, OmniboxHitSources, AppHit, DocHit } from './Omnibox';\nexport { parseLaunch, PROVIDERS } from './launch';\nexport type { Launch } from './launch';\nexport { focusHeroOmnibox, revealHeroOmnibox, focusOmnibox, registerOmniboxFocus } from './omniboxFocus';\nexport type { OmniboxVariant, OmniboxHandle } from './omniboxFocus';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAmC;AAEnC,oBAAuC;AAEvC,0BAAwF;","names":[]}
@@ -0,0 +1,4 @@
1
+ export { AppHit, DocHit, default as Omnibox, OmniboxHitSources, OmniboxProps } from './Omnibox.cjs';
2
+ export { Launch, PROVIDERS, parseLaunch } from './launch.cjs';
3
+ export { OmniboxHandle, OmniboxVariant, focusHeroOmnibox, focusOmnibox, registerOmniboxFocus, revealHeroOmnibox } from './omniboxFocus.cjs';
4
+ import 'react';
@@ -0,0 +1,4 @@
1
+ export { AppHit, DocHit, default as Omnibox, OmniboxHitSources, OmniboxProps } from './Omnibox.js';
2
+ export { Launch, PROVIDERS, parseLaunch } from './launch.js';
3
+ export { OmniboxHandle, OmniboxVariant, focusHeroOmnibox, focusOmnibox, registerOmniboxFocus, revealHeroOmnibox } from './omniboxFocus.js';
4
+ import 'react';
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ import { default as default2 } from "./Omnibox";
2
+ import { parseLaunch, PROVIDERS } from "./launch";
3
+ import { focusHeroOmnibox, revealHeroOmnibox, focusOmnibox, registerOmniboxFocus } from "./omniboxFocus";
4
+ export {
5
+ default2 as Omnibox,
6
+ PROVIDERS,
7
+ focusHeroOmnibox,
8
+ focusOmnibox,
9
+ parseLaunch,
10
+ registerOmniboxFocus,
11
+ revealHeroOmnibox
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { default as Omnibox } from './Omnibox';\nexport type { OmniboxProps, OmniboxHitSources, AppHit, DocHit } from './Omnibox';\nexport { parseLaunch, PROVIDERS } from './launch';\nexport type { Launch } from './launch';\nexport { focusHeroOmnibox, revealHeroOmnibox, focusOmnibox, registerOmniboxFocus } from './omniboxFocus';\nexport type { OmniboxVariant, OmniboxHandle } from './omniboxFocus';\n"],"mappings":"AAAA,SAAoB,WAAXA,gBAA0B;AAEnC,SAAS,aAAa,iBAAiB;AAEvC,SAAS,kBAAkB,mBAAmB,cAAc,4BAA4B;","names":["default"]}
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var launch_exports = {};
20
+ __export(launch_exports, {
21
+ PROVIDERS: () => PROVIDERS,
22
+ parseLaunch: () => parseLaunch
23
+ });
24
+ module.exports = __toCommonJS(launch_exports);
25
+ const PROVIDERS = {
26
+ github: "github.com"
27
+ };
28
+ const DEFAULT_PROVIDER = "github";
29
+ function presentPathOf(provider, namespace, repository, ref) {
30
+ const base = `/present/${provider}/${namespace}/${repository}`;
31
+ return ref ? `${base}/${encodeURIComponent(ref)}` : base;
32
+ }
33
+ function location(provider, namespace, repository, ref) {
34
+ const display = ref ? `${provider}:${namespace}/${repository}@${ref}` : `${provider}:${namespace}/${repository}`;
35
+ return { kind: "location", provider, namespace, repository, ...ref ? { ref } : {}, display, presentPath: presentPathOf(provider, namespace, repository, ref) };
36
+ }
37
+ function providerLabel(hostname) {
38
+ return hostname.replace(/^www\./, "").split(".")[0];
39
+ }
40
+ function parseTuple(rest, provider) {
41
+ const slash = rest.indexOf("/");
42
+ if (slash <= 0) return null;
43
+ const namespace = rest.slice(0, slash);
44
+ const tail = rest.slice(slash + 1);
45
+ if (!namespace || !tail) return null;
46
+ const at = tail.indexOf("@");
47
+ const repository = at === -1 ? tail : tail.slice(0, at);
48
+ const ref = at === -1 ? void 0 : tail.slice(at + 1);
49
+ if (!repository || repository.includes("/")) return null;
50
+ if (ref !== void 0 && !ref) return null;
51
+ return location(provider, namespace, repository, ref);
52
+ }
53
+ function parseLaunch(input, defaultProvider = DEFAULT_PROVIDER) {
54
+ const raw = input.trim();
55
+ if (!raw) return { kind: "text", query: raw };
56
+ if (/^https?:\/\//i.test(raw)) {
57
+ let url;
58
+ try {
59
+ url = new URL(raw);
60
+ } catch {
61
+ return { kind: "text", query: raw };
62
+ }
63
+ const host = url.hostname.toLowerCase();
64
+ if (host === "immediately.run" || host.endsWith(".immediately.run")) {
65
+ if (/^\/(present|edit)(\/|$)/.test(url.pathname)) {
66
+ return { kind: "platform-url", path: url.pathname + url.search + url.hash };
67
+ }
68
+ return { kind: "text", query: raw };
69
+ }
70
+ const providerEntry = Object.entries(PROVIDERS).find(([, urlHost]) => urlHost === host);
71
+ if (providerEntry) {
72
+ const [provider] = providerEntry;
73
+ const segs2 = url.pathname.split("/").filter(Boolean);
74
+ if (segs2.length < 2) return { kind: "text", query: raw };
75
+ const [namespace, repo0] = segs2;
76
+ const repo = repo0.endsWith(".git") ? repo0.slice(0, -4) : repo0;
77
+ if (!repo) return { kind: "text", query: raw };
78
+ if (segs2.length > 2) {
79
+ const [marker, ...extra] = segs2.slice(2);
80
+ if (marker === "tree" && extra.length > 0) {
81
+ return location(provider, namespace, repo, extra.join("/"));
82
+ }
83
+ if (marker === "blob" && extra.length > 0) {
84
+ return location(provider, namespace, repo, extra[0]);
85
+ }
86
+ return { kind: "text", query: raw };
87
+ }
88
+ return location(provider, namespace, repo);
89
+ }
90
+ const segs = url.pathname.split("/").filter(Boolean);
91
+ if (segs.length >= 2) return { kind: "unknown-provider", provider: providerLabel(host) };
92
+ return { kind: "text", query: raw };
93
+ }
94
+ const colon = raw.indexOf(":");
95
+ if (colon > 0 && !raw.slice(0, colon).includes("/")) {
96
+ const provider = raw.slice(0, colon).toLowerCase();
97
+ const rest = raw.slice(colon + 1);
98
+ if (provider in PROVIDERS) {
99
+ const parsed = parseTuple(rest, provider);
100
+ return parsed ?? { kind: "text", query: raw };
101
+ }
102
+ return { kind: "unknown-provider", provider };
103
+ }
104
+ const tuple = parseTuple(raw, defaultProvider);
105
+ if (tuple) return tuple;
106
+ return { kind: "text", query: raw };
107
+ }
108
+ // Annotate the CommonJS export names for ESM import in node:
109
+ 0 && (module.exports = {
110
+ PROVIDERS,
111
+ parseLaunch
112
+ });
113
+ //# sourceMappingURL=launch.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/launch.ts"],"sourcesContent":["// The launch parser (R3-511; FRONT_DOOR_IA §5.2) — turns what a visitor types\n// into the omnibox into a present route, a typed rejection for an unknown\n// provider, or free text. Pure: no React, no SDK, no network. The site cannot\n// check that a repo EXISTS — existence is the host's job after navigation.\n//\n// Grammar, in the order the parser tries them:\n// 1. a platform URL (any *.immediately.run host with a /present/ or /edit/\n// path) — passed through; the caller resolves it against the current host\n// origin.\n// 2. a provider-prefixed tuple (`github:acme/todo@dev` — the corpus location\n// grammar) or a bare tuple (`acme/todo@feat/x`) with the default provider.\n// 3. a provider URL (`https://github.com/acme/todo/tree/feat/x`).\n// 4. anything else is free text (search only).\n\n/** The known providers: the prefix/spelling a user may type, and the URL host\n * that names the same provider. A second provider is a row here (FRONT_DOOR_IA\n * §5.1 — the chip renders one static option per row). */\nexport const PROVIDERS: Readonly<Record<string, string>> = {\n github: 'github.com',\n};\n\nconst DEFAULT_PROVIDER = 'github';\n\nexport type Launch =\n | {\n kind: 'location';\n provider: string;\n namespace: string;\n repository: string;\n ref?: string;\n /** What the results row shows, e.g. `github:acme/todo@feat/x`. */\n display: string;\n /** A root-relative platform path, e.g. `/present/github/acme/todo/feat%2Fx`. */\n presentPath: string;\n }\n | { kind: 'platform-url'; path: string }\n | { kind: 'unknown-provider'; provider: string }\n | { kind: 'text'; query: string };\n\n/** The `/present/…` path for a location. The ref is encoded ONCE — matching the\n * host's `encodeRef` (site-main `src/editor/shared.ts`), so a ref containing\n * `/` stays one segment. `/files/{entry}` is deliberately never appended: the\n * host resolves the app's entry from `package.json`. */\nfunction presentPathOf(provider: string, namespace: string, repository: string, ref?: string): string {\n const base = `/present/${provider}/${namespace}/${repository}`;\n return ref ? `${base}/${encodeURIComponent(ref)}` : base;\n}\n\nfunction location(provider: string, namespace: string, repository: string, ref?: string): Launch {\n const display = ref\n ? `${provider}:${namespace}/${repository}@${ref}`\n : `${provider}:${namespace}/${repository}`;\n return { kind: 'location', provider, namespace, repository, ...(ref ? { ref } : {}), display, presentPath: presentPathOf(provider, namespace, repository, ref) };\n}\n\n/** `gitlab.com` → `gitlab`: the label we can honestly name for a repo-URL on a\n * host we do not support. Documented shorthand, not a claim about the host. */\nfunction providerLabel(hostname: string): string {\n return hostname.replace(/^www\\./, '').split('.')[0];\n}\n\n/** Parse a `<ns>/<repo>[@<ref>]` tuple. Returns null when the input is not one\n * (wrong shape, missing pieces). The REF may contain `/` (`@feat/x`), so the\n * tail after the namespace is parsed left-to-right, not split on `/`. */\nfunction parseTuple(rest: string, provider: string): Launch | null {\n const slash = rest.indexOf('/');\n if (slash <= 0) return null; // need `<ns>/<repo>`; `acme/` and `acme` are text.\n const namespace = rest.slice(0, slash);\n const tail = rest.slice(slash + 1);\n if (!namespace || !tail) return null;\n const at = tail.indexOf('@');\n const repository = at === -1 ? tail : tail.slice(0, at);\n const ref = at === -1 ? undefined : tail.slice(at + 1);\n if (!repository || repository.includes('/')) return null; // only the ref may span segments\n if (ref !== undefined && !ref) return null; // `ns/repo@` — dangling @.\n return location(provider, namespace, repository, ref);\n}\n\nexport function parseLaunch(input: string, defaultProvider: string = DEFAULT_PROVIDER): Launch {\n const raw = input.trim();\n if (!raw) return { kind: 'text', query: raw };\n\n // 1. URLs.\n if (/^https?:\\/\\//i.test(raw)) {\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return { kind: 'text', query: raw };\n }\n const host = url.hostname.toLowerCase();\n\n // This platform: pass the path (with search/hash) through; the caller\n // resolves it against the current host origin.\n if (host === 'immediately.run' || host.endsWith('.immediately.run')) {\n if (/^\\/(present|edit)(\\/|$)/.test(url.pathname)) {\n return { kind: 'platform-url', path: url.pathname + url.search + url.hash };\n }\n return { kind: 'text', query: raw };\n }\n\n const providerEntry = Object.entries(PROVIDERS).find(([, urlHost]) => urlHost === host);\n if (providerEntry) {\n const [provider] = providerEntry;\n const segs = url.pathname.split('/').filter(Boolean);\n if (segs.length < 2) return { kind: 'text', query: raw };\n const [namespace, repo0] = segs;\n const repo = repo0!.endsWith('.git') ? repo0!.slice(0, -4) : repo0!;\n if (!repo) return { kind: 'text', query: raw };\n // `/tree/<rest>` → the ref is the WHOLE remainder (a ref may contain `/`);\n // `/blob/<first>` → the ref is the FIRST segment; the file path is dropped.\n // Documented limitation: a /blob/ URL on a ref containing `/` is misread —\n // the interpreted location is shown in the results row so it can be\n // corrected. Any other extra segment is not a repo root → free text.\n if (segs.length > 2) {\n const [marker, ...extra] = segs.slice(2);\n if (marker === 'tree' && extra.length > 0) {\n return location(provider, namespace, repo, extra.join('/'));\n }\n if (marker === 'blob' && extra.length > 0) {\n return location(provider, namespace, repo, extra[0]);\n }\n return { kind: 'text', query: raw };\n }\n return location(provider, namespace, repo);\n }\n\n // A repo-shaped URL on a host we cannot reach: name what was understood.\n const segs = url.pathname.split('/').filter(Boolean);\n if (segs.length >= 2) return { kind: 'unknown-provider', provider: providerLabel(host) };\n return { kind: 'text', query: raw };\n }\n\n // 2. Provider-prefixed tuple (`github:acme/todo@dev`).\n const colon = raw.indexOf(':');\n if (colon > 0 && !raw.slice(0, colon).includes('/')) {\n const provider = raw.slice(0, colon).toLowerCase();\n const rest = raw.slice(colon + 1);\n if (provider in PROVIDERS) {\n const parsed = parseTuple(rest, provider);\n return parsed ?? { kind: 'text', query: raw };\n }\n return { kind: 'unknown-provider', provider };\n }\n\n // 3. Bare tuple with the default provider.\n const tuple = parseTuple(raw, defaultProvider);\n if (tuple) return tuple;\n\n // 4. Free text — search only.\n return { kind: 'text', query: raw };\n}\n"],"mappings":"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","names":["segs"]}
@@ -0,0 +1,27 @@
1
+ /** The known providers: the prefix/spelling a user may type, and the URL host
2
+ * that names the same provider. A second provider is a row here (FRONT_DOOR_IA
3
+ * §5.1 — the chip renders one static option per row). */
4
+ declare const PROVIDERS: Readonly<Record<string, string>>;
5
+ type Launch = {
6
+ kind: 'location';
7
+ provider: string;
8
+ namespace: string;
9
+ repository: string;
10
+ ref?: string;
11
+ /** What the results row shows, e.g. `github:acme/todo@feat/x`. */
12
+ display: string;
13
+ /** A root-relative platform path, e.g. `/present/github/acme/todo/feat%2Fx`. */
14
+ presentPath: string;
15
+ } | {
16
+ kind: 'platform-url';
17
+ path: string;
18
+ } | {
19
+ kind: 'unknown-provider';
20
+ provider: string;
21
+ } | {
22
+ kind: 'text';
23
+ query: string;
24
+ };
25
+ declare function parseLaunch(input: string, defaultProvider?: string): Launch;
26
+
27
+ export { type Launch, PROVIDERS, parseLaunch };
@@ -0,0 +1,27 @@
1
+ /** The known providers: the prefix/spelling a user may type, and the URL host
2
+ * that names the same provider. A second provider is a row here (FRONT_DOOR_IA
3
+ * §5.1 — the chip renders one static option per row). */
4
+ declare const PROVIDERS: Readonly<Record<string, string>>;
5
+ type Launch = {
6
+ kind: 'location';
7
+ provider: string;
8
+ namespace: string;
9
+ repository: string;
10
+ ref?: string;
11
+ /** What the results row shows, e.g. `github:acme/todo@feat/x`. */
12
+ display: string;
13
+ /** A root-relative platform path, e.g. `/present/github/acme/todo/feat%2Fx`. */
14
+ presentPath: string;
15
+ } | {
16
+ kind: 'platform-url';
17
+ path: string;
18
+ } | {
19
+ kind: 'unknown-provider';
20
+ provider: string;
21
+ } | {
22
+ kind: 'text';
23
+ query: string;
24
+ };
25
+ declare function parseLaunch(input: string, defaultProvider?: string): Launch;
26
+
27
+ export { type Launch, PROVIDERS, parseLaunch };