Skip to content
Merged
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
3 changes: 1 addition & 2 deletions github/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ inputs:
required: false

share:
description: "Share the opencode session (defaults to true for public repos)"
description: "Deprecated and ignored: session sharing was discontinued"
required: false

prompt:
Expand Down Expand Up @@ -71,7 +71,6 @@ runs:
env:
MODEL: ${{ inputs.model }}
AGENT: ${{ inputs.agent }}
SHARE: ${{ inputs.share }}
PROMPT: ${{ inputs.prompt }}
USE_GITHUB_TOKEN: ${{ inputs.use_github_token }}
MENTIONS: ${{ inputs.mentions }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ export function MessageTimeline(props: {
const titleValue = createMemo(() => info()?.title)
const titleLabel = createMemo(() => sessionTitle(titleValue()))
const shareUrl = createMemo(() => info()?.share?.url)
const shareEnabled = createMemo(() => sync().data.config.share !== "disabled")
// Session sharing was discontinued; keep the share menu and popover hidden.
const shareEnabled = () => false
const parentID = createMemo(() => info()?.parentID)
const parent = createMemo(() => {
const id = parentID()
Expand Down
112 changes: 0 additions & 112 deletions packages/app/src/pages/session/use-session-commands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,93 +147,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
if (sessionID) return permission.isAutoAccepting(sessionID, sdk().directory)
return permission.isAutoAcceptingDirectory(sdk().directory)
}
const write = async (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 true
}

const clipboard = typeof navigator === "undefined" ? undefined : navigator.clipboard
if (!clipboard?.writeText) return false
return clipboard.writeText(value).then(
() => true,
() => false,
)
}

const copyShare = async (url: string, existing: boolean) => {
if (!(await write(url))) {
showToast({
title: language.t("toast.session.share.copyFailed.title"),
variant: "error",
})
return
}

showToast({
title: existing ? language.t("session.share.copy.copied") : language.t("toast.session.share.success.title"),
description: language.t("toast.session.share.success.description"),
variant: "success",
})
}

const share = async () => {
const sessionID = params.id
if (!sessionID) return

const existing = info()?.share?.url
if (existing) {
await copyShare(existing, true)
return
}

const url = await sdk()
.client.session.share({ sessionID })
.then((res) => res.data?.share?.url)
.catch(() => undefined)
if (!url) {
showToast({
title: language.t("toast.session.share.failed.title"),
description: language.t("toast.session.share.failed.description"),
variant: "error",
})
return
}

await copyShare(url, false)
}

const unshare = async () => {
const sessionID = params.id
if (!sessionID) return

await sdk()
.client.session.unshare({ sessionID })
.then(() =>
showToast({
title: language.t("toast.session.unshare.success.title"),
description: language.t("toast.session.unshare.success.description"),
variant: "success",
}),
)
.catch(() =>
showToast({
title: language.t("toast.session.unshare.failed.title"),
description: language.t("toast.session.unshare.failed.description"),
variant: "error",
}),
)
}

const exportSession = async () => {
const sessionID = params.id
Expand Down Expand Up @@ -421,30 +334,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
)
}

const shareCmds = () => {
if (sync().data.config.share === "disabled") return []
return [
sessionCommand({
id: "session.share",
title: info()?.share?.url ? language.t("session.share.copy.copyLink") : language.t("command.session.share"),
description: info()?.share?.url
? language.t("toast.session.share.success.description")
: language.t("command.session.share.description"),
slash: "share",
disabled: !params.id,
onSelect: share,
}),
sessionCommand({
id: "session.unshare",
title: language.t("command.session.unshare"),
description: language.t("command.session.unshare.description"),
slash: "unshare",
disabled: !params.id || !info()?.share?.url,
onSelect: unshare,
}),
]
}

const sessionCmds = () => [
sessionCommand({
id: "session.new",
Expand Down Expand Up @@ -645,7 +534,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {

command.register("session", () => [
...sessionCmds(),
...shareCmds(),
...fileCmds(),
...contextCmds(),
...viewCmds(),
Expand Down
51 changes: 10 additions & 41 deletions packages/opencode/src/cli/cmd/github.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import type {
import { UI } from "../ui"
import { ModelsDev } from "@opencode-ai/core/models-dev"
import { InstanceRef } from "@/effect/instance-ref"
import { SessionShare } from "@/share/session"
import { Session } from "@/session/session"
import type { SessionID } from "../../session/schema"
import { MessageID, PartID } from "../../session/schema"
Expand Down Expand Up @@ -380,7 +379,6 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
if (!ctx) return yield* Effect.die("InstanceRef not provided")
const gitSvc = yield* Git.Service
const sessionSvc = yield* Session.Service
const sessionShare = yield* SessionShare.Service
const sessionPrompt = yield* SessionPrompt.Service
const events = yield* EventV2Bridge.Service
const runLocalEffect = <A, E>(effect: Effect.Effect<A, E>) =>
Expand All @@ -407,7 +405,6 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
const { providerID, modelID } = normalizeModel()
const variant = process.env["VARIANT"] || undefined
const runId = normalizeRunId()
const share = normalizeShare()
const oidcBaseUrl = normalizeOidcBaseUrl()
const { owner, repo } = context.repo
// For repo events (schedule, workflow_dispatch), payload has no issue/comment data
Expand All @@ -428,14 +425,12 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
? (payload as IssueCommentEvent | IssuesEvent).issue.number
: (payload as PullRequestEvent | PullRequestReviewCommentEvent).pull_request.number
const runUrl = `/${owner}/${repo}/actions/runs/${runId}`
const shareBaseUrl = isMock ? "https://dev.opencode.ai" : "https://opencode.ai"

let appToken: string
let octoRest: Octokit
let octoGraph: typeof graphql
let gitConfig: string
let session: { id: SessionID; title: string; version: string }
let shareId: string | undefined
let exitCode = 0
let githubClientReady = false
type PromptFiles = Awaited<ReturnType<typeof getUserPrompt>>["promptFiles"]
Expand Down Expand Up @@ -512,12 +507,6 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
}),
)
await subscribeSessionEvents()
shareId = await (async () => {
if (share === false) return
if (!share && repoData.data.private) return
await runLocalEffect(sessionShare.share(session.id))
return session.id.slice(-8)
})()
console.log("opencode session", session.id)

// Handle event types:
Expand Down Expand Up @@ -547,7 +536,7 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
repoData.data.default_branch,
branch,
summary,
`${response}\n\nTriggered by ${triggerType}${footer({ image: true })}`,
`${response}\n\nTriggered by ${triggerType}${footer()}`,
)
if (pr) {
console.log(`Created PR #${pr}`)
Expand Down Expand Up @@ -576,8 +565,7 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
const summary = await summarize(response)
await pushToLocalBranch(summary, uncommittedChanges)
}
const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${shareBaseUrl}/s/${shareId}`))
await createComment(`${response}${footer({ image: !hasShared })}`)
await createComment(`${response}${footer()}`)
await removeReaction(commentType)
}
// Fork PR
Expand All @@ -594,8 +582,7 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
const summary = await summarize(response)
await pushToForkBranch(summary, prData, uncommittedChanges)
}
const hasShared = prData.comments.nodes.some((c) => c.body.includes(`${shareBaseUrl}/s/${shareId}`))
await createComment(`${response}${footer({ image: !hasShared })}`)
await createComment(`${response}${footer()}`)
await removeReaction(commentType)
}
}
Expand All @@ -610,7 +597,7 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
if (switched) {
// Agent switched branches (likely created its own branch/PR).
// Don't push the stale infrastructure branch — just comment.
await createComment(`${response}${footer({ image: true })}`)
await createComment(`${response}${footer()}`)
await removeReaction(commentType)
} else if (dirty) {
const summary = await summarize(response)
Expand All @@ -619,16 +606,16 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
repoData.data.default_branch,
branch,
summary,
`${response}\n\nCloses #${issueId}${footer({ image: true })}`,
`${response}\n\nCloses #${issueId}${footer()}`,
)
if (pr) {
await createComment(`Created PR #${pr}${footer({ image: true })}`)
await createComment(`Created PR #${pr}${footer()}`)
} else {
await createComment(`${response}${footer({ image: true })}`)
await createComment(`${response}${footer()}`)
}
await removeReaction(commentType)
} else {
await createComment(`${response}${footer({ image: true })}`)
await createComment(`${response}${footer()}`)
await removeReaction(commentType)
}
}
Expand Down Expand Up @@ -677,14 +664,6 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
return value
}

function normalizeShare() {
const value = process.env["SHARE"]
if (!value) return undefined
if (value === "true") return true
if (value === "false") return false
throw new Error(`Invalid share value: ${value}. Share must be a boolean.`)
}

function normalizeUseGithubToken() {
const value = process.env["USE_GITHUB_TOKEN"]
if (!value) return false
Expand Down Expand Up @@ -1351,18 +1330,8 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?:
}
}

function footer(opts?: { image?: boolean }) {
const image = (() => {
if (!shareId) return ""
if (!opts?.image) return ""

const titleAlt = encodeURIComponent(session.title.substring(0, 50))
const title64 = Buffer.from(session.title.substring(0, 700), "utf8").toString("base64")

return `<a href="${shareBaseUrl}/s/${shareId}"><img width="200" alt="${titleAlt}" src="https://social-cards.sst.dev/opencode-share/${title64}.png?model=${providerID}/${modelID}&version=${session.version}&id=${shareId}" /></a>\n`
})()
const shareUrl = shareId ? `[opencode session](${shareBaseUrl}/s/${shareId})&nbsp;&nbsp;|&nbsp;&nbsp;` : ""
return `\n\n${image}${shareUrl}[github run](${runUrl})`
function footer() {
return `\n\n[github run](${runUrl})`
}

async function fetchRepo() {
Expand Down
Loading
Loading