summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-11-11 18:01:16 -0500
committerFrank <[email protected]>2025-11-11 18:50:28 -0500
commitf13c17e65424ac45a995b29a1f70ba8d5210ee23 (patch)
treec19d6f76a5aa43e8abbea6fd300cc84ae6b3e0ce
parenta0611d92e472c4f1b4d66056b86f28f6b58064b1 (diff)
downloadopencode-f13c17e65424ac45a995b29a1f70ba8d5210ee23.tar.gz
opencode-f13c17e65424ac45a995b29a1f70ba8d5210ee23.zip
wip: poc pr command
-rw-r--r--packages/opencode/src/cli/cmd/pr.ts85
-rw-r--r--packages/opencode/src/index.ts2
2 files changed, 87 insertions, 0 deletions
diff --git a/packages/opencode/src/cli/cmd/pr.ts b/packages/opencode/src/cli/cmd/pr.ts
new file mode 100644
index 000000000..fb6171a71
--- /dev/null
+++ b/packages/opencode/src/cli/cmd/pr.ts
@@ -0,0 +1,85 @@
+import { UI } from "../ui"
+import { cmd } from "./cmd"
+import { Instance } from "@/project/instance"
+import { $ } from "bun"
+
+export const PrCommand = cmd({
+ command: "pr <number>",
+ describe: "fetch and checkout a GitHub PR branch, then run opencode",
+ builder: (yargs) =>
+ yargs.positional("number", {
+ type: "number",
+ describe: "PR number to checkout",
+ demandOption: true,
+ }),
+ async handler(args) {
+ await Instance.provide({
+ directory: process.cwd(),
+ async fn() {
+ const project = Instance.project
+ if (project.vcs !== "git") {
+ UI.error("Could not find git repository. Please run this command from a git repository.")
+ process.exit(1)
+ }
+
+ const prNumber = args.number
+ const localBranchName = `pr/${prNumber}`
+ UI.println(`Fetching and checking out PR #${prNumber}...`)
+
+ // Use gh pr checkout with custom branch name
+ const result = await $`gh pr checkout ${prNumber} --branch ${localBranchName} --force`.nothrow()
+
+ if (result.exitCode !== 0) {
+ UI.error(`Failed to checkout PR #${prNumber}. Make sure you have gh CLI installed and authenticated.`)
+ process.exit(1)
+ }
+
+ // For fork PRs, add the fork as a remote to enable pushing
+ const prInfoResult =
+ await $`gh pr view ${prNumber} --json headRepository,headRepositoryOwner,isCrossRepository,headRefName`.nothrow()
+ if (prInfoResult.exitCode === 0) {
+ const prInfoText = prInfoResult.text()
+ if (prInfoText.trim()) {
+ const prInfo = JSON.parse(prInfoText)
+ if (prInfo && prInfo.isCrossRepository && prInfo.headRepository && prInfo.headRepositoryOwner) {
+ const forkOwner = prInfo.headRepositoryOwner.login
+ const forkName = prInfo.headRepository.name
+ const remoteName = forkOwner
+
+ // Check if remote already exists
+ const remotes = (await $`git remote`.nothrow().text()).trim()
+ if (!remotes.split("\n").includes(remoteName)) {
+ await $`git remote add ${remoteName} https://github.com/${forkOwner}/${forkName}.git`.nothrow()
+ UI.println(`Added fork remote: ${remoteName}`)
+ }
+
+ // Set upstream to the fork so pushes go there
+ const headRefName = prInfo.headRefName
+ await $`git branch --set-upstream-to=${remoteName}/${headRefName} ${localBranchName}`.nothrow()
+ }
+ }
+ }
+
+ UI.println(`Successfully checked out PR #${prNumber} as branch '${localBranchName}'`)
+ UI.println()
+ UI.println("Starting opencode...")
+ UI.println()
+
+ // Launch opencode TUI
+ const { spawn } = await import("child_process")
+ const opencodeProcess = spawn("opencode", [], {
+ stdio: "inherit",
+ cwd: process.cwd(),
+ })
+
+ await new Promise<void>((resolve, reject) => {
+ opencodeProcess.on("exit", (code) => {
+ if (code === 0) resolve()
+ else reject(new Error(`opencode exited with code ${code}`))
+ })
+ opencodeProcess.on("error", reject)
+ })
+ },
+ })
+ },
+})
diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts
index 015806997..acd7ee1c0 100644
--- a/packages/opencode/src/index.ts
+++ b/packages/opencode/src/index.ts
@@ -24,6 +24,7 @@ import { TuiSpawnCommand } from "./cli/cmd/tui/spawn"
import { AcpCommand } from "./cli/cmd/acp"
import { EOL } from "os"
import { WebCommand } from "./cli/cmd/web"
+import { PrCommand } from "./cli/cmd/pr"
process.on("unhandledRejection", (e) => {
Log.Default.error("rejection", {
@@ -90,6 +91,7 @@ const cli = yargs(hideBin(process.argv))
.command(ExportCommand)
.command(ImportCommand)
.command(GithubCommand)
+ .command(PrCommand)
.fail((msg) => {
if (
msg.startsWith("Unknown argument") ||