summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/pages/layout
diff options
context:
space:
mode:
authorBrendan Allan <[email protected]>2026-03-05 17:15:14 +0800
committerGitHub <[email protected]>2026-03-05 09:15:14 +0000
commit4e26b0aec7052b9daf1f1d26906198775cd3ad66 (patch)
tree3161089461eed754faa2c493cf91916b11db9339 /packages/app/src/pages/layout
parent6531cfc521f069ad86eb22990fc42924d161d0d9 (diff)
downloadopencode-4e26b0aec7052b9daf1f1d26906198775cd3ad66.tar.gz
opencode-4e26b0aec7052b9daf1f1d26906198775cd3ad66.zip
desktop: new-session deeplink (#15322)
Diffstat (limited to 'packages/app/src/pages/layout')
-rw-r--r--packages/app/src/pages/layout/deep-links.ts32
-rw-r--r--packages/app/src/pages/layout/helpers.test.ts41
2 files changed, 55 insertions, 18 deletions
diff --git a/packages/app/src/pages/layout/deep-links.ts b/packages/app/src/pages/layout/deep-links.ts
index 7bdb002a3..5dca421f7 100644
--- a/packages/app/src/pages/layout/deep-links.ts
+++ b/packages/app/src/pages/layout/deep-links.ts
@@ -1,15 +1,17 @@
export const deepLinkEvent = "opencode:deep-link"
-export const parseDeepLink = (input: string) => {
+const parseUrl = (input: string) => {
if (!input.startsWith("opencode://")) return
if (typeof URL.canParse === "function" && !URL.canParse(input)) return
- const url = (() => {
- try {
- return new URL(input)
- } catch {
- return undefined
- }
- })()
+ try {
+ return new URL(input)
+ } catch {
+ return
+ }
+}
+
+export const parseDeepLink = (input: string) => {
+ const url = parseUrl(input)
if (!url) return
if (url.hostname !== "open-project") return
const directory = url.searchParams.get("directory")
@@ -17,9 +19,23 @@ export const parseDeepLink = (input: string) => {
return directory
}
+export const parseNewSessionDeepLink = (input: string) => {
+ const url = parseUrl(input)
+ if (!url) return
+ if (url.hostname !== "new-session") return
+ const directory = url.searchParams.get("directory")
+ if (!directory) return
+ const prompt = url.searchParams.get("prompt") || undefined
+ if (!prompt) return { directory }
+ return { directory, prompt }
+}
+
export const collectOpenProjectDeepLinks = (urls: string[]) =>
urls.map(parseDeepLink).filter((directory): directory is string => !!directory)
+export const collectNewSessionDeepLinks = (urls: string[]) =>
+ urls.map(parseNewSessionDeepLink).filter((link): link is { directory: string; prompt?: string } => !!link)
+
type OpenCodeWindow = Window & {
__OPENCODE__?: {
deepLinks?: string[]
diff --git a/packages/app/src/pages/layout/helpers.test.ts b/packages/app/src/pages/layout/helpers.test.ts
index 29517b624..d1569dbd9 100644
--- a/packages/app/src/pages/layout/helpers.test.ts
+++ b/packages/app/src/pages/layout/helpers.test.ts
@@ -1,15 +1,14 @@
import { describe, expect, test } from "bun:test"
-import { type Session } from "@opencode-ai/sdk/v2/client"
-import { collectOpenProjectDeepLinks, drainPendingDeepLinks, parseDeepLink } from "./deep-links"
import {
- displayName,
- errorMessage,
- getDraggableId,
- hasProjectPermissions,
- latestRootSession,
- syncWorkspaceOrder,
- workspaceKey,
-} from "./helpers"
+ collectNewSessionDeepLinks,
+ collectOpenProjectDeepLinks,
+ drainPendingDeepLinks,
+ parseDeepLink,
+ parseNewSessionDeepLink,
+} from "./deep-links"
+import { displayName, errorMessage, getDraggableId, syncWorkspaceOrder, workspaceKey } from "./helpers"
+import { type Session } from "@opencode-ai/sdk/v2/client"
+import { hasProjectPermissions, latestRootSession } from "./helpers"
const session = (input: Partial<Session> & Pick<Session, "id" | "directory">) =>
({
@@ -62,6 +61,28 @@ describe("layout deep links", () => {
expect(result).toEqual(["/a", "/c"])
})
+ test("parses new-session deep links with optional prompt", () => {
+ expect(parseNewSessionDeepLink("opencode://new-session?directory=/tmp/demo")).toEqual({ directory: "/tmp/demo" })
+ expect(parseNewSessionDeepLink("opencode://new-session?directory=/tmp/demo&prompt=hello%20world")).toEqual({
+ directory: "/tmp/demo",
+ prompt: "hello world",
+ })
+ })
+
+ test("ignores new-session deep links without directory", () => {
+ expect(parseNewSessionDeepLink("opencode://new-session")).toBeUndefined()
+ expect(parseNewSessionDeepLink("opencode://new-session?directory=")).toBeUndefined()
+ })
+
+ test("collects only valid new-session deep links", () => {
+ const result = collectNewSessionDeepLinks([
+ "opencode://new-session?directory=/a",
+ "opencode://open-project?directory=/b",
+ "opencode://new-session?directory=/c&prompt=ship%20it",
+ ])
+ expect(result).toEqual([{ directory: "/a" }, { directory: "/c", prompt: "ship it" }])
+ })
+
test("drains global deep links once", () => {
const target = {
__OPENCODE__: {