Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 19 additions & 39 deletions packages/docs/index.mdx
Original file line number Diff line number Diff line change
@@ -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.

<Card title="Start here" icon="rocket" href="/quickstart" horizontal>
Follow our three step quickstart guide.
</Card>

## Make it yours
## Quick start

Design a docs site that looks great and empowers your users.
<Card title="Install OpenCode" icon="rocket" href="https://opencode.ai/install" horizontal>
One command installation for macOS, Linux, and Windows.
</Card>

<Columns cols={2}>
<Card title="Edit locally" icon="pen-to-square" href="/development">
Edit your docs locally and preview them in real time.
<Card title="Run the TUI" icon="terminal" href="/quickstart">
Launch OpenCode and start a session in minutes.
</Card>
<Card title="Customize your site" icon="palette" href="/essentials/settings">
Customize the design and colors of your site to match your brand.
</Card>
<Card title="Set up navigation" icon="map" href="/essentials/navigation">
Organize your docs to help users find what they need and succeed with your product.
</Card>
<Card title="API documentation" icon="terminal" href="/api-reference/introduction">
Auto-generate API documentation from OpenAPI specifications.
<Card title="Local development" icon="wrench" href="/development">
Preview docs locally and learn the basics.
</Card>
</Columns>

## Create beautiful pages

Everything you need to create world-class documentation.
## Community & source

<Columns cols={2}>
<Card title="Write with MDX" icon="pen-fancy" href="/essentials/markdown">
Use MDX to style your docs pages.
<Card title="GitHub" icon="github" href="https://github.com/anomalyco/opencode">
Issues, roadmap, and pull requests live here.
</Card>
<Card title="Code samples" icon="code" href="/essentials/code">
Add sample code to demonstrate how to use your product.
<Card title="Discord" icon="comments" href="https://opencode.ai/discord">
Ask questions, share tips, and get help from the community.
</Card>
<Card title="Images" icon="image" href="/essentials/images">
Display images and other media.
</Card>
<Card title="Reusable snippets" icon="recycle" href="/essentials/reusable-snippets">
Write once and reuse across your docs.
</Card>
</Columns>

## Need inspiration?

<Card title="See complete examples" icon="stars" href="https://mintlify.com/customers">
Browse our showcase of exceptional documentation sites.
</Card>
</Columns>
42 changes: 36 additions & 6 deletions packages/opencode/src/cli/cmd/tui/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,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))
Expand Down Expand Up @@ -659,9 +674,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()
}
}}
Expand Down
13 changes: 12 additions & 1 deletion packages/opencode/src/cli/cmd/tui/component/dialog-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}/)?.[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)
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -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 (
<DialogSelect
Expand Down Expand Up @@ -67,7 +69,23 @@ export function DialogMessage(props: {
return agg
}, "")

await Clipboard.copy(text)
const result = await Clipboard.copy(text).catch((error) => {
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()
},
},
Expand Down
101 changes: 73 additions & 28 deletions packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -306,17 +306,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()
},
},
Expand Down Expand Up @@ -720,7 +738,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),
Expand Down Expand Up @@ -752,9 +770,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()
},
},
Expand All @@ -766,24 +799,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()
},
},
Expand Down
21 changes: 18 additions & 3 deletions packages/opencode/src/cli/cmd/tui/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}}
Expand Down
Loading