summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src
diff options
context:
space:
mode:
authorHegyi Áron Ferenc <[email protected]>2026-01-29 08:09:53 +0100
committerGitHub <[email protected]>2026-01-29 15:09:53 +0800
commit2af326606c936380c303bf56506e3c8bed04b0eb (patch)
tree2c1fe35b7f5f77f88869291168e01e7ab220b566 /packages/app/src
parent7c0067d59d318bfd6ecd473c36a9e673a4f68ff9 (diff)
downloadopencode-2af326606c936380c303bf56506e3c8bed04b0eb.tar.gz
opencode-2af326606c936380c303bf56506e3c8bed04b0eb.zip
feat(desktop): Add desktop deep link (#10072)
Co-authored-by: Brendan Allan <[email protected]>
Diffstat (limited to 'packages/app/src')
-rw-r--r--packages/app/src/app.tsx2
-rw-r--r--packages/app/src/pages/layout.tsx40
2 files changed, 41 insertions, 1 deletions
diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx
index ba0d1e7aa..11fdb5743 100644
--- a/packages/app/src/app.tsx
+++ b/packages/app/src/app.tsx
@@ -43,7 +43,7 @@ function UiI18nBridge(props: ParentProps) {
declare global {
interface Window {
- __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string }
+ __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string; deepLinks?: string[] }
}
}
diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx
index afef14c84..73480e8f2 100644
--- a/packages/app/src/pages/layout.tsx
+++ b/packages/app/src/pages/layout.tsx
@@ -1136,6 +1136,46 @@ export default function Layout(props: ParentProps) {
if (navigate) navigateToProject(directory)
}
+ const deepLinkEvent = "opencode:deep-link"
+
+ const parseDeepLink = (input: string) => {
+ if (!input.startsWith("opencode://")) return
+ const url = new URL(input)
+ if (url.hostname !== "open-project") return
+ const directory = url.searchParams.get("directory")
+ if (!directory) return
+ return directory
+ }
+
+ const handleDeepLinks = (urls: string[]) => {
+ if (!server.isLocal()) return
+ for (const input of urls) {
+ const directory = parseDeepLink(input)
+ if (!directory) continue
+ openProject(directory)
+ }
+ }
+
+ const drainDeepLinks = () => {
+ const pending = window.__OPENCODE__?.deepLinks ?? []
+ if (pending.length === 0) return
+ if (window.__OPENCODE__) window.__OPENCODE__.deepLinks = []
+ handleDeepLinks(pending)
+ }
+
+ onMount(() => {
+ const handler = (event: Event) => {
+ const detail = (event as CustomEvent<{ urls: string[] }>).detail
+ const urls = detail?.urls ?? []
+ if (urls.length === 0) return
+ handleDeepLinks(urls)
+ }
+
+ drainDeepLinks()
+ window.addEventListener(deepLinkEvent, handler as EventListener)
+ onCleanup(() => window.removeEventListener(deepLinkEvent, handler as EventListener))
+ })
+
const displayName = (project: LocalProject) => project.name || getFilename(project.worktree)
async function renameProject(project: LocalProject, next: string) {