diff --git a/packages/docs/index.mdx b/packages/docs/index.mdx
index 19a09f890cdf..e138987046c0 100644
--- a/packages/docs/index.mdx
+++ b/packages/docs/index.mdx
@@ -1,56 +1,36 @@
---
title: "Introduction"
-description: "Welcome to the new home for your documentation"
+description: "OpenCode is the open source AI coding agent for the terminal."
---
-## Setting up
+## What is OpenCode
-Get your documentation site up and running in minutes.
+OpenCode is an open source AI coding agent focused on the terminal experience.
+It runs locally, supports multiple model providers, and offers both a TUI and API-based workflows.
+You can use it to explore codebases, make changes, run tests, and automate common engineering tasks.
-
- Follow our three step quickstart guide.
-
-
-## Make it yours
+## Quick start
-Design a docs site that looks great and empowers your users.
+
+ One command installation for macOS, Linux, and Windows.
+
-
- Edit your docs locally and preview them in real time.
+
+ Launch OpenCode and start a session in minutes.
-
- Customize the design and colors of your site to match your brand.
-
-
- Organize your docs to help users find what they need and succeed with your product.
-
-
- Auto-generate API documentation from OpenAPI specifications.
+
+ Preview docs locally and learn the basics.
-## Create beautiful pages
-
-Everything you need to create world-class documentation.
+## Community & source
-
- Use MDX to style your docs pages.
+
+ Issues, roadmap, and pull requests live here.
-
- Add sample code to demonstrate how to use your product.
+
+ Ask questions, share tips, and get help from the community.
-
- Display images and other media.
-
-
- Write once and reuse across your docs.
-
-
-
-## Need inspiration?
-
-
- Browse our showcase of exceptional documentation sites.
-
+
\ No newline at end of file
diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx
index c5f88a7c672e..d5568fb5cdb9 100644
--- a/packages/opencode/src/cli/cmd/tui/app.tsx
+++ b/packages/opencode/src/cli/cmd/tui/app.tsx
@@ -204,9 +204,24 @@ function App() {
renderer.console.onCopySelection = async (text: string) => {
if (!text || text.length === 0) return
- await Clipboard.copy(text)
- .then(() => toast.show({ message: "Copied to clipboard", variant: "info" }))
- .catch(toast.error)
+ const result = await Clipboard.copy(text).catch((error) => {
+ toast.error(error)
+ })
+ if (!result) {
+ renderer.clearSelection()
+ return
+ }
+ if (result.warning) {
+ toast.show({ message: result.warning, variant: "warning" })
+ renderer.clearSelection()
+ return
+ }
+ if (result.notice) {
+ toast.show({ message: result.notice, variant: "info" })
+ renderer.clearSelection()
+ return
+ }
+ toast.show({ message: "Copied to clipboard", variant: "info" })
renderer.clearSelection()
}
const [terminalTitleEnabled, setTerminalTitleEnabled] = createSignal(kv.get("terminal_title_enabled", true))
@@ -673,9 +688,24 @@ function App() {
}
const text = renderer.getSelection()?.getSelectedText()
if (text && text.length > 0) {
- await Clipboard.copy(text)
- .then(() => toast.show({ message: "Copied to clipboard", variant: "info" }))
- .catch(toast.error)
+ const result = await Clipboard.copy(text).catch((error) => {
+ toast.error(error)
+ })
+ if (!result) {
+ renderer.clearSelection()
+ return
+ }
+ if (result.warning) {
+ toast.show({ message: result.warning, variant: "warning" })
+ renderer.clearSelection()
+ return
+ }
+ if (result.notice) {
+ toast.show({ message: result.notice, variant: "info" })
+ renderer.clearSelection()
+ return
+ }
+ toast.show({ message: "Copied to clipboard", variant: "info" })
renderer.clearSelection()
}
}}
diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
index dc3f337370ae..53419e903229 100644
--- a/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
@@ -129,7 +129,18 @@ function AutoMethod(props: AutoMethodProps) {
if (evt.name === "c" && !evt.ctrl && !evt.meta) {
const code = props.authorization.instructions.match(/[A-Z0-9]{4}-[A-Z0-9]{4,5}/)?.[0] ?? props.authorization.url
Clipboard.copy(code)
- .then(() => toast.show({ message: "Copied to clipboard", variant: "info" }))
+ .then((result) => {
+ if (!result) return
+ if (result.warning) {
+ toast.show({ message: result.warning, variant: "warning" })
+ return
+ }
+ if (result.notice) {
+ toast.show({ message: result.notice, variant: "info" })
+ return
+ }
+ toast.show({ message: "Copied to clipboard", variant: "info" })
+ })
.catch(toast.error)
}
})
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx
index ff17b5567ebd..3847bddd1e46 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-message.tsx
@@ -4,6 +4,7 @@ import { DialogSelect } from "@tui/ui/dialog-select"
import { useSDK } from "@tui/context/sdk"
import { useRoute } from "@tui/context/route"
import { Clipboard } from "@tui/util/clipboard"
+import { useToast } from "@tui/ui/toast"
import type { PromptInfo } from "@tui/component/prompt/history"
export function DialogMessage(props: {
@@ -15,6 +16,7 @@ export function DialogMessage(props: {
const sdk = useSDK()
const message = createMemo(() => sync.data.message[props.sessionID]?.find((x) => x.id === props.messageID))
const route = useRoute()
+ const toast = useToast()
return (
{
+ toast.error(error)
+ })
+ if (!result) {
+ dialog.clear()
+ return
+ }
+ if (result.warning) {
+ toast.show({ message: result.warning, variant: "warning" })
+ dialog.clear()
+ return
+ }
+ if (result.notice) {
+ toast.show({ message: result.notice, variant: "info" })
+ dialog.clear()
+ return
+ }
dialog.clear()
},
},
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
index 9a000f953c06..313d7090b1ea 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
@@ -324,17 +324,35 @@ export function Session() {
name: "share",
},
onSelect: async (dialog) => {
- await sdk.client.session
+ const response = await sdk.client.session
.share({
sessionID: route.sessionID,
})
- .then((res) =>
- Clipboard.copy(res.data!.share!.url).catch(() =>
- toast.show({ message: "Failed to copy URL to clipboard", variant: "error" }),
- ),
- )
- .then(() => toast.show({ message: "Share URL copied to clipboard!", variant: "success" }))
- .catch(() => toast.show({ message: "Failed to share session", variant: "error" }))
+ .catch(() => {
+ toast.show({ message: "Failed to share session", variant: "error" })
+ })
+ if (!response) {
+ dialog.clear()
+ return
+ }
+ const result = await Clipboard.copy(response.data!.share!.url).catch(() => {
+ toast.show({ message: "Failed to copy URL to clipboard", variant: "error" })
+ })
+ if (!result) {
+ dialog.clear()
+ return
+ }
+ if (result.warning) {
+ toast.show({ message: result.warning, variant: "warning" })
+ dialog.clear()
+ return
+ }
+ if (result.notice) {
+ toast.show({ message: result.notice, variant: "info" })
+ dialog.clear()
+ return
+ }
+ toast.show({ message: "Share URL copied to clipboard!", variant: "success" })
dialog.clear()
},
},
@@ -717,7 +735,7 @@ export function Session() {
value: "messages.copy",
keybind: "messages_copy",
category: "Session",
- onSelect: (dialog) => {
+ onSelect: async (dialog) => {
const revertID = session()?.revert?.messageID
const lastAssistantMessage = messages().findLast(
(msg) => msg.role === "assistant" && (!revertID || msg.id < revertID),
@@ -749,9 +767,24 @@ export function Session() {
return
}
- Clipboard.copy(text)
- .then(() => toast.show({ message: "Message copied to clipboard!", variant: "success" }))
- .catch(() => toast.show({ message: "Failed to copy to clipboard", variant: "error" }))
+ const result = await Clipboard.copy(text).catch(() => {
+ toast.show({ message: "Failed to copy to clipboard", variant: "error" })
+ })
+ if (!result) {
+ dialog.clear()
+ return
+ }
+ if (result.warning) {
+ toast.show({ message: result.warning, variant: "warning" })
+ dialog.clear()
+ return
+ }
+ if (result.notice) {
+ toast.show({ message: result.notice, variant: "info" })
+ dialog.clear()
+ return
+ }
+ toast.show({ message: "Message copied to clipboard!", variant: "success" })
dialog.clear()
},
},
@@ -763,24 +796,36 @@ export function Session() {
name: "copy",
},
onSelect: async (dialog) => {
- try {
- const sessionData = session()
- if (!sessionData) return
- const sessionMessages = messages()
- const transcript = formatTranscript(
- sessionData,
- sessionMessages.map((msg) => ({ info: msg, parts: sync.data.part[msg.id] ?? [] })),
- {
- thinking: showThinking(),
- toolDetails: showDetails(),
- assistantMetadata: showAssistantMetadata(),
- },
- )
- await Clipboard.copy(transcript)
- toast.show({ message: "Session transcript copied to clipboard!", variant: "success" })
- } catch (error) {
+ const sessionData = session()
+ if (!sessionData) return
+ const sessionMessages = messages()
+ const transcript = formatTranscript(
+ sessionData,
+ sessionMessages.map((msg) => ({ info: msg, parts: sync.data.part[msg.id] ?? [] })),
+ {
+ thinking: showThinking(),
+ toolDetails: showDetails(),
+ assistantMetadata: showAssistantMetadata(),
+ },
+ )
+ const result = await Clipboard.copy(transcript).catch(() => {
toast.show({ message: "Failed to copy session transcript", variant: "error" })
+ })
+ if (!result) {
+ dialog.clear()
+ return
+ }
+ if (result.warning) {
+ toast.show({ message: result.warning, variant: "warning" })
+ dialog.clear()
+ return
+ }
+ if (result.notice) {
+ toast.show({ message: result.notice, variant: "info" })
+ dialog.clear()
+ return
}
+ toast.show({ message: "Session transcript copied to clipboard!", variant: "success" })
dialog.clear()
},
},
diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx
index 57375ba09db4..939abcb75266 100644
--- a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx
+++ b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx
@@ -141,9 +141,24 @@ export function DialogProvider(props: ParentProps) {
onMouseUp={async () => {
const text = renderer.getSelection()?.getSelectedText()
if (text && text.length > 0) {
- await Clipboard.copy(text)
- .then(() => toast.show({ message: "Copied to clipboard", variant: "info" }))
- .catch(toast.error)
+ const result = await Clipboard.copy(text).catch((error) => {
+ toast.error(error)
+ })
+ if (!result) {
+ renderer.clearSelection()
+ return
+ }
+ if (result.warning) {
+ toast.show({ message: result.warning, variant: "warning" })
+ renderer.clearSelection()
+ return
+ }
+ if (result.notice) {
+ toast.show({ message: result.notice, variant: "info" })
+ renderer.clearSelection()
+ return
+ }
+ toast.show({ message: "Copied to clipboard", variant: "info" })
renderer.clearSelection()
}
}}