diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx
index bb4d9812503..31ac6c16ba0 100644
--- a/packages/app/src/components/session/session-header.tsx
+++ b/packages/app/src/components/session/session-header.tsx
@@ -343,6 +343,22 @@ export function SessionHeader() {
.catch((err: unknown) => showRequestError(language, err))
}
+ const copySessionID = () => {
+ const id = params.id
+ if (!id) return
+ navigator.clipboard
+ .writeText(id)
+ .then(() => {
+ showToast({
+ variant: "success",
+ icon: "circle-check",
+ title: language.t("session.share.copy.copied"),
+ description: id,
+ })
+ })
+ .catch((err: unknown) => showRequestError(language, err))
+ }
+
const share = useSessionShare({
globalSDK,
currentSession,
@@ -407,6 +423,20 @@ export function SessionHeader() {
{language.t("session.header.open.copyPath")}
+
+
+
+
}
>
@@ -497,6 +527,20 @@ export function SessionHeader() {
{language.t("session.header.open.copyPath")}
+ {
+ setMenu("open", false)
+ copySessionID()
+ }}
+ disabled={!params.id}
+ >
+
+
+
+
+ {language.t("session.header.open.copySessionID")}
+
+
diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts
index 7e95fd739df..4556277c4bb 100644
--- a/packages/app/src/i18n/en.ts
+++ b/packages/app/src/i18n/en.ts
@@ -541,6 +541,7 @@ export const dict = {
"session.header.open.ariaLabel": "Open in {{app}}",
"session.header.open.menu": "Open options",
"session.header.open.copyPath": "Copy path",
+ "session.header.open.copySessionID": "Copy session ID",
"status.popover.trigger": "Status",
"status.popover.ariaLabel": "Server configurations",
diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx
index b8ddeda8235..531c4636e49 100644
--- a/packages/app/src/pages/session/use-session-commands.tsx
+++ b/packages/app/src/pages/session/use-session-commands.tsx
@@ -79,6 +79,30 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
return lines.slice(0, 2).join("\n")
}
+ const write = (value: string) => {
+ const body = typeof document === "undefined" ? undefined : document.body
+ if (body) {
+ const textarea = document.createElement("textarea")
+ textarea.value = value
+ textarea.setAttribute("readonly", "")
+ textarea.style.position = "fixed"
+ textarea.style.opacity = "0"
+ textarea.style.pointerEvents = "none"
+ body.appendChild(textarea)
+ textarea.select()
+ const copied = document.execCommand("copy")
+ body.removeChild(textarea)
+ if (copied) return Promise.resolve(true)
+ }
+
+ const clipboard = typeof navigator === "undefined" ? undefined : navigator.clipboard
+ if (!clipboard?.writeText) return Promise.resolve(false)
+ return clipboard.writeText(value).then(
+ () => true,
+ () => false,
+ )
+ }
+
const addSelectionToContext = (path: string, selection: FileSelection) => {
const preview = selectionPreview(path, selection)
prompt.context.add({ type: "file", path, selection, preview })
@@ -395,30 +419,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
onSelect: async () => {
if (!params.id) return
- const write = (value: string) => {
- const body = typeof document === "undefined" ? undefined : document.body
- if (body) {
- const textarea = document.createElement("textarea")
- textarea.value = value
- textarea.setAttribute("readonly", "")
- textarea.style.position = "fixed"
- textarea.style.opacity = "0"
- textarea.style.pointerEvents = "none"
- body.appendChild(textarea)
- textarea.select()
- const copied = document.execCommand("copy")
- body.removeChild(textarea)
- if (copied) return Promise.resolve(true)
- }
-
- const clipboard = typeof navigator === "undefined" ? undefined : navigator.clipboard
- if (!clipboard?.writeText) return Promise.resolve(false)
- return clipboard.writeText(value).then(
- () => true,
- () => false,
- )
- }
-
const copy = async (url: string, existing: boolean) => {
const ok = await write(url)
if (!ok) {