From 87929c98ecdf2e08db19c0ed5a653307072a0035 Mon Sep 17 00:00:00 2001 From: zhw445611 Date: Sat, 24 Jan 2026 10:02:40 +0800 Subject: [PATCH 1/2] add(index.mdx):zhw445 --- packages/docs/index.mdx | 58 ++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 39 deletions(-) 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 From 6a53d16830b2f878d98a5fca146e215818583712 Mon Sep 17 00:00:00 2001 From: zhw445611 Date: Sat, 24 Jan 2026 12:34:20 +0800 Subject: [PATCH 2/2] feat(opencode): add linux clipboard toast warnings --- packages/opencode/src/cli/cmd/tui/app.tsx | 42 ++++++-- .../cli/cmd/tui/component/dialog-provider.tsx | 13 ++- .../cmd/tui/routes/session/dialog-message.tsx | 20 +++- .../src/cli/cmd/tui/routes/session/index.tsx | 101 +++++++++++++----- .../opencode/src/cli/cmd/tui/ui/dialog.tsx | 21 +++- 5 files changed, 158 insertions(+), 39 deletions(-) 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() } }}