mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-11 19:36:25 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2f58b891a | ||
|
|
bb564f96a3 |
@@ -168,7 +168,7 @@ jobs:
|
||||
fi
|
||||
|
||||
found=0
|
||||
for file in packages/cli/dist/cli-darwin-*/bin/opencode2; do
|
||||
for file in packages/cli/dist/cli-darwin-*/bin/opencode; do
|
||||
if [ ! -f "$file" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
## Live V2 TUI Testing
|
||||
|
||||
- Run `bun run dev:live` from a development worktree to test its TUI against the currently elected `opencode2` background server and live sessions.
|
||||
- Run `bun run dev:live` from a development worktree to test its TUI against the currently elected `opencode` background server and live sessions.
|
||||
- Pass a directory after the script when needed, for example `bun run dev:live /path/to/project`.
|
||||
- The script discovers the server with `opencode2 service status`, injects its private local credential from `opencode2 service get password`, and uses the `dev` TUI storage channel so tabs and other client-local state match the installed client.
|
||||
- The script discovers the server with `opencode service status`, injects its private local credential from `opencode service get password`, and uses the `dev` TUI storage channel so tabs and other client-local state match the installed client.
|
||||
- Prefer `dev:live` over plain `bun run dev` for this workflow. An implicit managed-service connection may replace the live server when the worktree client version differs; explicit `--server` warns and continues without replacing it.
|
||||
|
||||
## V2 TUI Stories
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
APP=opencode2
|
||||
APP=opencode
|
||||
SOURCE_APP=opencode
|
||||
|
||||
MUTED='\033[0;2m'
|
||||
RED='\033[0;31m'
|
||||
@@ -22,7 +23,7 @@ Options:
|
||||
Examples:
|
||||
curl -fsSL https://opencode.ai/v2/install | bash
|
||||
curl -fsSL https://opencode.ai/v2/install | bash -s -- --version 0.0.0-beta-17236
|
||||
./install --binary /path/to/opencode2
|
||||
./install --binary /path/to/opencode
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -201,9 +202,9 @@ else
|
||||
|
||||
filename="cli-$target-$specific_version.tgz"
|
||||
url="https://registry.npmjs.org/$package_name/-/$filename"
|
||||
binary_name="$APP"
|
||||
binary_name="$SOURCE_APP"
|
||||
if [ "$os" = "windows" ]; then
|
||||
binary_name="$APP.exe"
|
||||
binary_name="$SOURCE_APP.exe"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -230,12 +231,7 @@ check_version() {
|
||||
installed_version="${installed_version##* }"
|
||||
installed_version="${installed_version#v}"
|
||||
|
||||
if [[ "$installed_version" != "$specific_version" ]]; then
|
||||
print_message info "${MUTED}Installed version: ${NC}$installed_version."
|
||||
else
|
||||
print_message info "${MUTED}Version ${NC}$specific_version${MUTED} already installed"
|
||||
exit 0
|
||||
fi
|
||||
print_message info "${MUTED}Installed version: ${NC}$installed_version."
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -340,15 +336,47 @@ download_and_install() {
|
||||
fi
|
||||
|
||||
tar -xzf "$tmp_dir/$filename" -C "$tmp_dir"
|
||||
mv "$tmp_dir/package/bin/$binary_name" "$INSTALL_DIR"
|
||||
chmod 755 "${INSTALL_DIR}/$binary_name"
|
||||
local installed_binary="$APP"
|
||||
if [ "$os" = "windows" ]; then
|
||||
installed_binary="$APP.exe"
|
||||
fi
|
||||
mv "$tmp_dir/package/bin/$binary_name" "$INSTALL_DIR/$installed_binary"
|
||||
chmod 755 "$INSTALL_DIR/$installed_binary"
|
||||
rm -rf "$tmp_dir"
|
||||
}
|
||||
|
||||
install_from_binary() {
|
||||
print_message info "\n${MUTED}Installing ${NC}$APP ${MUTED}from: ${NC}$binary_path"
|
||||
cp "$binary_path" "${INSTALL_DIR}/$APP"
|
||||
chmod 755 "${INSTALL_DIR}/$APP"
|
||||
local installed_binary="$APP"
|
||||
case "$(uname -s)" in
|
||||
MINGW*|MSYS*|CYGWIN*) installed_binary="$APP.exe" ;;
|
||||
esac
|
||||
cp "$binary_path" "$INSTALL_DIR/$installed_binary"
|
||||
chmod 755 "$INSTALL_DIR/$installed_binary"
|
||||
}
|
||||
|
||||
install_legacy_shim() {
|
||||
local shim_os="${os:-}"
|
||||
if [[ -z "$shim_os" ]]; then
|
||||
case "$(uname -s)" in
|
||||
MINGW*|MSYS*|CYGWIN*) shim_os="windows" ;;
|
||||
esac
|
||||
fi
|
||||
rm -f "$INSTALL_DIR/opencode2" "$INSTALL_DIR/opencode2.exe" "$INSTALL_DIR/opencode2.cmd"
|
||||
if [[ "$shim_os" == "windows" ]]; then
|
||||
cat > "$INSTALL_DIR/opencode2.cmd" <<'EOF'
|
||||
@echo off
|
||||
echo opencode2 is now just opencode. run opencode
|
||||
exit /b 1
|
||||
EOF
|
||||
return
|
||||
fi
|
||||
cat > "$INSTALL_DIR/opencode2" <<'EOF'
|
||||
#!/bin/sh
|
||||
echo 'opencode2 is now just opencode. run opencode'
|
||||
exit 1
|
||||
EOF
|
||||
chmod 755 "$INSTALL_DIR/opencode2"
|
||||
}
|
||||
|
||||
if [ -n "$binary_path" ]; then
|
||||
@@ -357,6 +385,7 @@ else
|
||||
check_version
|
||||
download_and_install
|
||||
fi
|
||||
install_legacy_shim
|
||||
|
||||
|
||||
add_to_path() {
|
||||
@@ -453,7 +482,7 @@ echo -e ""
|
||||
echo -e "${MUTED}OpenCode includes free models, to start:${NC}"
|
||||
echo -e ""
|
||||
echo -e "cd <project> ${MUTED}# Open directory${NC}"
|
||||
echo -e "opencode2 ${MUTED}# Run command${NC}"
|
||||
echo -e "opencode ${MUTED}# Run command${NC}"
|
||||
echo -e ""
|
||||
echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/v2/docs"
|
||||
echo -e ""
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@
|
||||
"packageManager": "bun@1.4.2",
|
||||
"scripts": {
|
||||
"dev": "bun run --cwd packages/cli src/index.ts",
|
||||
"dev:live": "sh -c 'OPENCODE_TUI_CHANNEL=dev OPENCODE_PASSWORD=\"$(opencode2 service get password)\" exec bun run dev \"$@\" --server \"$(opencode2 service status)\"' --",
|
||||
"dev:live": "sh -c 'OPENCODE_TUI_CHANNEL=dev OPENCODE_PASSWORD=\"$(opencode service get password)\" exec bun run dev \"$@\" --server \"$(opencode service status)\"' --",
|
||||
"dev:vite": "bun run --cwd packages/cli --conditions=browser dev/vite.ts",
|
||||
"dev:vite:live": "sh -c 'OPENCODE_TUI_CHANNEL=dev OPENCODE_PASSWORD=\"$(opencode2 service get password)\" exec bun run dev:vite \"$@\" --server \"$(opencode2 service status)\"' --",
|
||||
"dev:vite:live": "sh -c 'OPENCODE_TUI_CHANNEL=dev OPENCODE_PASSWORD=\"$(opencode service get password)\" exec bun run dev:vite \"$@\" --server \"$(opencode service status)\"' --",
|
||||
"dev:desktop": "bun --cwd packages/desktop dev",
|
||||
"dev:web": "bun --cwd packages/app dev",
|
||||
"dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev",
|
||||
|
||||
@@ -285,7 +285,7 @@ export const DESKTOP_NATIVE_ENGLISH = {
|
||||
"desktop.updater.dialog.later": "Later",
|
||||
|
||||
"desktop.cli.installed.title": "CLI Installed",
|
||||
"desktop.cli.installed.message": "CLI installed to {{path}}\n\nRestart your terminal to use the 'opencode2' command.",
|
||||
"desktop.cli.installed.message": "CLI installed to {{path}}\n\nRestart your terminal to use the 'opencode' command.",
|
||||
"desktop.cli.failed.title": "Installation Failed",
|
||||
"desktop.cli.failed.message": "Failed to install CLI: {{error}}",
|
||||
|
||||
|
||||
Executable
+135
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const childProcess = require("child_process")
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const os = require("os")
|
||||
|
||||
const forwardedSignals =
|
||||
process.platform === "win32" ? ["SIGINT", "SIGTERM", "SIGHUP"] : ["SIGINT", "SIGTERM", "SIGHUP", "SIGUSR1"]
|
||||
|
||||
function run(target) {
|
||||
const child = childProcess.spawn(target, process.argv.slice(2), { stdio: "inherit" })
|
||||
child.on("error", (error) => {
|
||||
console.error(error.message)
|
||||
process.exit(1)
|
||||
})
|
||||
const forwarders = {}
|
||||
for (const signal of forwardedSignals) {
|
||||
forwarders[signal] = () => {
|
||||
try {
|
||||
child.kill(signal)
|
||||
} catch {}
|
||||
}
|
||||
process.on(signal, forwarders[signal])
|
||||
}
|
||||
child.on("exit", (code, signal) => {
|
||||
for (const forwardedSignal of forwardedSignals) process.removeListener(forwardedSignal, forwarders[forwardedSignal])
|
||||
if (signal) return process.kill(process.pid, signal)
|
||||
process.exit(typeof code === "number" ? code : 0)
|
||||
})
|
||||
}
|
||||
|
||||
const envPath = process.env.OPENCODE_BIN_PATH
|
||||
const scriptDir = path.dirname(fs.realpathSync(__filename))
|
||||
const command = path.basename(__filename).replace(/\.cjs$/, "")
|
||||
const nodeBuild = command === "opencode-node"
|
||||
const sourceCommand = nodeBuild ? "opencode2-node" : "opencode"
|
||||
const cached = path.join(scriptDir, `.${command}`)
|
||||
const platform = { darwin: "darwin", linux: "linux", win32: "windows" }[os.platform()] || os.platform()
|
||||
const arch = { x64: "x64", arm64: "arm64", arm: "arm" }[os.arch()] || os.arch()
|
||||
const base = `@opencode/cli${nodeBuild ? "-node" : ""}-` + platform + "-" + arch
|
||||
const binary = platform === "windows" ? `${sourceCommand}.exe` : sourceCommand
|
||||
|
||||
function supportsAvx2() {
|
||||
if (arch !== "x64") return false
|
||||
if (platform === "linux") {
|
||||
try {
|
||||
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (platform === "darwin") {
|
||||
try {
|
||||
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], { encoding: "utf8", timeout: 1500 })
|
||||
return result.status === 0 && (result.stdout || "").trim() === "1"
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (platform === "windows") {
|
||||
const command =
|
||||
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
||||
for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
||||
try {
|
||||
const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
|
||||
encoding: "utf8",
|
||||
timeout: 3000,
|
||||
windowsHide: true,
|
||||
})
|
||||
if (result.status !== 0) continue
|
||||
const output = (result.stdout || "").trim().toLowerCase()
|
||||
if (output === "true" || output === "1") return true
|
||||
if (output === "false" || output === "0") return false
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const names = (() => {
|
||||
if (nodeBuild) return [base]
|
||||
const baseline = arch === "x64" && !supportsAvx2()
|
||||
if (platform === "linux") {
|
||||
const musl = (() => {
|
||||
try {
|
||||
if (fs.existsSync("/etc/alpine-release")) return true
|
||||
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
||||
return ((result.stdout || "") + (result.stderr || "")).toLowerCase().includes("musl")
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
})()
|
||||
if (musl)
|
||||
return arch === "x64"
|
||||
? baseline
|
||||
? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
||||
: [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
||||
: [`${base}-musl`, base]
|
||||
return arch === "x64"
|
||||
? baseline
|
||||
? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
||||
: [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
||||
: [base, `${base}-musl`]
|
||||
}
|
||||
return arch === "x64" ? (baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]) : [base]
|
||||
})()
|
||||
|
||||
function findBinary(startDir) {
|
||||
let current = startDir
|
||||
for (;;) {
|
||||
const modules = path.join(current, "node_modules")
|
||||
if (fs.existsSync(modules))
|
||||
for (const name of names) {
|
||||
const candidate = path.join(modules, name, "bin", binary)
|
||||
if (fs.existsSync(candidate)) return candidate
|
||||
}
|
||||
const parent = path.dirname(current)
|
||||
if (parent === current) return
|
||||
current = parent
|
||||
}
|
||||
}
|
||||
|
||||
const resolved = envPath || (fs.existsSync(cached) ? cached : findBinary(scriptDir))
|
||||
if (!resolved) {
|
||||
console.error(
|
||||
`It seems that your package manager failed to install the right ${command} CLI package. Try manually installing ` +
|
||||
names.map((name) => `"${name}"`).join(" or ") +
|
||||
" package",
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
run(resolved)
|
||||
@@ -1,134 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const childProcess = require("child_process")
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const os = require("os")
|
||||
|
||||
const forwardedSignals =
|
||||
process.platform === "win32" ? ["SIGINT", "SIGTERM", "SIGHUP"] : ["SIGINT", "SIGTERM", "SIGHUP", "SIGUSR1"]
|
||||
|
||||
function run(target) {
|
||||
const child = childProcess.spawn(target, process.argv.slice(2), { stdio: "inherit" })
|
||||
child.on("error", (error) => {
|
||||
console.error(error.message)
|
||||
process.exit(1)
|
||||
})
|
||||
const forwarders = {}
|
||||
for (const signal of forwardedSignals) {
|
||||
forwarders[signal] = () => {
|
||||
try {
|
||||
child.kill(signal)
|
||||
} catch {}
|
||||
}
|
||||
process.on(signal, forwarders[signal])
|
||||
}
|
||||
child.on("exit", (code, signal) => {
|
||||
for (const forwardedSignal of forwardedSignals) process.removeListener(forwardedSignal, forwarders[forwardedSignal])
|
||||
if (signal) return process.kill(process.pid, signal)
|
||||
process.exit(typeof code === "number" ? code : 0)
|
||||
})
|
||||
}
|
||||
|
||||
const envPath = process.env.OPENCODE_BIN_PATH
|
||||
const scriptDir = path.dirname(fs.realpathSync(__filename))
|
||||
const command = path.basename(__filename).replace(/\.cjs$/, "")
|
||||
const nodeBuild = command === "opencode2-node"
|
||||
const cached = path.join(scriptDir, `.${command}`)
|
||||
const platform = { darwin: "darwin", linux: "linux", win32: "windows" }[os.platform()] || os.platform()
|
||||
const arch = { x64: "x64", arm64: "arm64", arm: "arm" }[os.arch()] || os.arch()
|
||||
const base = `@opencode/cli${nodeBuild ? "-node" : ""}-` + platform + "-" + arch
|
||||
const binary = platform === "windows" ? `${command}.exe` : command
|
||||
|
||||
function supportsAvx2() {
|
||||
if (arch !== "x64") return false
|
||||
if (platform === "linux") {
|
||||
try {
|
||||
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (platform === "darwin") {
|
||||
try {
|
||||
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], { encoding: "utf8", timeout: 1500 })
|
||||
return result.status === 0 && (result.stdout || "").trim() === "1"
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (platform === "windows") {
|
||||
const command =
|
||||
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
||||
for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
||||
try {
|
||||
const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
|
||||
encoding: "utf8",
|
||||
timeout: 3000,
|
||||
windowsHide: true,
|
||||
})
|
||||
if (result.status !== 0) continue
|
||||
const output = (result.stdout || "").trim().toLowerCase()
|
||||
if (output === "true" || output === "1") return true
|
||||
if (output === "false" || output === "0") return false
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const names = (() => {
|
||||
if (nodeBuild) return [base]
|
||||
const baseline = arch === "x64" && !supportsAvx2()
|
||||
if (platform === "linux") {
|
||||
const musl = (() => {
|
||||
try {
|
||||
if (fs.existsSync("/etc/alpine-release")) return true
|
||||
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
||||
return ((result.stdout || "") + (result.stderr || "")).toLowerCase().includes("musl")
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
})()
|
||||
if (musl)
|
||||
return arch === "x64"
|
||||
? baseline
|
||||
? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
||||
: [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
||||
: [`${base}-musl`, base]
|
||||
return arch === "x64"
|
||||
? baseline
|
||||
? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
||||
: [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
||||
: [base, `${base}-musl`]
|
||||
}
|
||||
return arch === "x64" ? (baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]) : [base]
|
||||
})()
|
||||
|
||||
function findBinary(startDir) {
|
||||
let current = startDir
|
||||
for (;;) {
|
||||
const modules = path.join(current, "node_modules")
|
||||
if (fs.existsSync(modules))
|
||||
for (const name of names) {
|
||||
const candidate = path.join(modules, name, "bin", binary)
|
||||
if (fs.existsSync(candidate)) return candidate
|
||||
}
|
||||
const parent = path.dirname(current)
|
||||
if (parent === current) return
|
||||
current = parent
|
||||
}
|
||||
}
|
||||
|
||||
const resolved = envPath || (fs.existsSync(cached) ? cached : findBinary(scriptDir))
|
||||
if (!resolved) {
|
||||
console.error(
|
||||
`It seems that your package manager failed to install the right ${command} CLI package. Try manually installing ` +
|
||||
names.map((name) => `"${name}"`).join(" or ") +
|
||||
" package",
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
run(resolved)
|
||||
console.log("opencode2 is now just opencode. run opencode")
|
||||
process.exit(1)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode.cjs",
|
||||
"opencode2": "./bin/opencode2.cjs"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -12,7 +12,7 @@ import { verifyArtifact, verifySimulationGraph } from "./verify-artifact"
|
||||
import { resolveOpencodePty } from "./opencode-pty"
|
||||
|
||||
const dir = path.resolve(import.meta.dirname, "..")
|
||||
const binary = "opencode2"
|
||||
const binary = "opencode"
|
||||
const outdir = path.resolve(
|
||||
dir,
|
||||
process.argv.find((arg) => arg.startsWith("--outdir="))?.slice("--outdir=".length) ?? "dist",
|
||||
@@ -149,7 +149,7 @@ export default { path: file, version: ${JSON.stringify(opencodePty.version)}, sh
|
||||
},
|
||||
define: {
|
||||
OPENCODE_VERSION: `'${Script.version}'`,
|
||||
OPENCODE_CLI_NAME: `'${binary}'`,
|
||||
OPENCODE_CLI_NAME: "'opencode'",
|
||||
OPENCODE_CHANNEL: `'${Script.channel}'`,
|
||||
OPENCODE_ARTIFACT: `'cli'`,
|
||||
OPENCODE_LIBC: item.os === "linux" ? `'${item.abi ?? "glibc"}'` : "undefined",
|
||||
|
||||
@@ -12,10 +12,11 @@ const require = createRequire(import.meta.url)
|
||||
const packageJson = JSON.parse(fs.readFileSync(path.join(directory, "package.json"), "utf8"))
|
||||
const command = Object.keys(packageJson.bin ?? {})[0]
|
||||
if (!command) throw new Error("OpenCode package does not declare a binary")
|
||||
const sourceCommand = packageJson.opencodeSourceBinary ?? command
|
||||
|
||||
const platform = { darwin: "darwin", linux: "linux", win32: "windows" }[os.platform()] ?? os.platform()
|
||||
const arch = { x64: "x64", arm64: "arm64", arm: "arm" }[os.arch()] ?? os.arch()
|
||||
const sourceBinary = platform === "windows" ? `${command}.exe` : command
|
||||
const sourceBinary = platform === "windows" ? `${sourceCommand}.exe` : sourceCommand
|
||||
const targetBinary = path.resolve(directory, packageJson.bin[command])
|
||||
const dependencies = packageJson.optionalDependencies ?? {}
|
||||
const base = Object.keys(dependencies).find((name) => name.endsWith(`-${platform}-${arch}`))
|
||||
|
||||
@@ -6,15 +6,10 @@ import path from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
import { UpdateArtifact } from "../../../script/update-artifact"
|
||||
|
||||
if (Script.channel !== "beta" && Script.channel !== "latest") {
|
||||
throw new Error("AUR publishing requires the beta or latest channel")
|
||||
}
|
||||
const beta = Script.channel === "beta"
|
||||
const name = beta ? "opencode-beta" : "opencode-bin"
|
||||
const command = beta ? "opencode2" : "opencode"
|
||||
if (!(beta ? /^\d+\.\d+\.\d+-beta[.-]\d+(?:\.\d+)?$/ : /^\d+\.\d+\.\d+$/).test(Script.version)) {
|
||||
throw new Error(`Expected a ${Script.channel} release version`)
|
||||
}
|
||||
if (Script.channel !== "beta") throw new Error("AUR publishing requires the beta channel")
|
||||
const name = "opencode-beta"
|
||||
const command = "opencode"
|
||||
if (!/^\d+\.\d+\.\d+-beta[.-]\d+(?:\.\d+)?$/.test(Script.version)) throw new Error("Expected a beta release version")
|
||||
|
||||
const dir = fileURLToPath(new URL("..", import.meta.url))
|
||||
const root = path.resolve(process.env.OPENCODE_CLI_DIST ?? path.join(dir, "dist"))
|
||||
@@ -22,6 +17,7 @@ const outdir = path.join(root, `aur-${name}`)
|
||||
const dryRun = process.argv.includes("--dry-run")
|
||||
const pkgver = Script.version.replaceAll("-", ".")
|
||||
const license = Bun.file(path.join(dir, "..", "..", "LICENSE"))
|
||||
const shim = "#!/bin/sh\necho 'opencode2 is now just opencode. run opencode'\nexit 1\n"
|
||||
|
||||
await rm(outdir, { recursive: true, force: true })
|
||||
await mkdir(path.dirname(outdir), { recursive: true })
|
||||
@@ -48,6 +44,7 @@ const sources = await Promise.all(
|
||||
)
|
||||
|
||||
await Bun.write(path.join(outdir, "LICENSE"), license)
|
||||
await Bun.write(path.join(outdir, "opencode2"), shim)
|
||||
await Bun.write(
|
||||
path.join(outdir, "PKGBUILD"),
|
||||
[
|
||||
@@ -55,21 +52,22 @@ await Bun.write(
|
||||
`pkgname=${name}`,
|
||||
`pkgver=${pkgver}`,
|
||||
"pkgrel=1",
|
||||
`pkgdesc='OpenCode${beta ? " V2 beta" : ""} - the AI coding agent for the terminal'`,
|
||||
"pkgdesc='OpenCode beta - the AI coding agent for the terminal'",
|
||||
"url='https://github.com/anomalyco/opencode'",
|
||||
"arch=('x86_64' 'aarch64')",
|
||||
"license=('MIT')",
|
||||
"depends=('glibc' 'gcc-libs' 'ripgrep')",
|
||||
`provides=('${command}')`,
|
||||
`conflicts=('${command}')`,
|
||||
`provides=('${command}' 'opencode2')`,
|
||||
`conflicts=('${command}' 'opencode2')`,
|
||||
// Stripping a compiled Bun executable can damage its embedded application.
|
||||
"options=('!strip' '!debug')",
|
||||
"source=('LICENSE')",
|
||||
`sha256sums=('${new Bun.CryptoHasher("sha256").update(await license.arrayBuffer()).digest("hex")}')`,
|
||||
"source=('LICENSE' 'opencode2')",
|
||||
`sha256sums=('${new Bun.CryptoHasher("sha256").update(await license.arrayBuffer()).digest("hex")}' '${new Bun.CryptoHasher("sha256").update(shim).digest("hex")}')`,
|
||||
...sources,
|
||||
"",
|
||||
"package() {",
|
||||
` install -Dm755 "$srcdir/package/bin/opencode2" "$pkgdir/usr/bin/${command}"`,
|
||||
` install -Dm755 "$srcdir/package/bin/opencode" "$pkgdir/usr/bin/${command}"`,
|
||||
' install -Dm755 "$srcdir/opencode2" "$pkgdir/usr/bin/opencode2"',
|
||||
' install -Dm644 "$srcdir/LICENSE" "$pkgdir/usr/share/licenses/$pkgname/LICENSE"',
|
||||
"}",
|
||||
"",
|
||||
@@ -79,7 +77,7 @@ await Bun.write(path.join(outdir, ".SRCINFO"), await $`makepkg --printsrcinfo`.c
|
||||
console.log(`Prepared ${name} ${pkgver} in ${outdir}`)
|
||||
if (dryRun) process.exit(0)
|
||||
|
||||
await $`git add PKGBUILD .SRCINFO LICENSE`.cwd(outdir)
|
||||
await $`git add PKGBUILD .SRCINFO LICENSE opencode2`.cwd(outdir)
|
||||
if ((await $`git diff --cached --quiet`.cwd(outdir).nothrow()).exitCode !== 0) {
|
||||
await $`git commit -m ${`chore: update ${name} to ${pkgver}`}`.cwd(outdir)
|
||||
await $`git push origin master`.cwd(outdir)
|
||||
|
||||
@@ -29,6 +29,8 @@ async function publish(dir: string, name: string, version: string) {
|
||||
async function publishDistribution(input: {
|
||||
root: string
|
||||
name: string
|
||||
command: string
|
||||
legacyCommand?: string
|
||||
binary: string
|
||||
packagePrefix: string
|
||||
artifact: string
|
||||
@@ -48,7 +50,7 @@ async function publishDistribution(input: {
|
||||
|
||||
await $`mkdir -p ${input.root}/${input.name}/bin`
|
||||
await $`cp ./script/postinstall.mjs ${input.root}/${input.name}/postinstall.mjs`
|
||||
await Bun.file(`${input.root}/${input.name}/bin/${input.binary}.exe`).write(
|
||||
await Bun.file(`${input.root}/${input.name}/bin/${input.command}.exe`).write(
|
||||
[
|
||||
`echo "Error: ${input.name}'s postinstall script was not run." >&2`,
|
||||
'echo "" >&2',
|
||||
@@ -58,11 +60,19 @@ async function publishDistribution(input: {
|
||||
"",
|
||||
].join("\n"),
|
||||
)
|
||||
if (input.legacyCommand)
|
||||
await Bun.file(`${input.root}/${input.name}/bin/${input.legacyCommand}.cjs`).write(
|
||||
`#!/usr/bin/env node\n\nconsole.log(${JSON.stringify(`opencode2 is now just opencode. run ${input.command}`)})\nprocess.exit(1)\n`,
|
||||
)
|
||||
await Bun.file(`${input.root}/${input.name}/package.json`).write(
|
||||
JSON.stringify(
|
||||
{
|
||||
name: input.name,
|
||||
bin: { [input.binary]: `./bin/${input.binary}.exe` },
|
||||
bin: {
|
||||
[input.command]: `./bin/${input.command}.exe`,
|
||||
...(input.legacyCommand ? { [input.legacyCommand]: `./bin/${input.legacyCommand}.cjs` } : {}),
|
||||
},
|
||||
...(input.command !== input.binary ? { opencodeSourceBinary: input.binary } : {}),
|
||||
scripts: { postinstall: "node ./postinstall.mjs" },
|
||||
version,
|
||||
license: pkg.license,
|
||||
@@ -120,7 +130,9 @@ async function publishDistribution(input: {
|
||||
await publishDistribution({
|
||||
root,
|
||||
name: pkg.name,
|
||||
binary: "opencode2",
|
||||
command: "opencode",
|
||||
legacyCommand: "opencode2",
|
||||
binary: "opencode",
|
||||
packagePrefix: "@opencode/cli-",
|
||||
artifact: "cli",
|
||||
})
|
||||
@@ -128,13 +140,14 @@ if (existsSync(path.join(root, "node"))) {
|
||||
await publishDistribution({
|
||||
root: path.join(root, "node"),
|
||||
name: "@opencode/cli-node",
|
||||
command: "opencode2-node",
|
||||
binary: "opencode2-node",
|
||||
packagePrefix: "@opencode/cli-node-",
|
||||
artifact: "cli-node",
|
||||
})
|
||||
}
|
||||
|
||||
if ((Script.channel === "beta" || Script.channel === "latest") && Script.release) {
|
||||
if (Script.channel === "beta" && Script.release) {
|
||||
await $`bun ./script/publish-aur.ts ${dryRun ? ["--dry-run"] : []}`.env({ ...process.env, OPENCODE_CLI_DIST: root })
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ import path from "node:path"
|
||||
const nodeBuild = process.argv.includes("--node")
|
||||
const target = `cli${nodeBuild ? "-node" : ""}-${process.platform === "win32" ? "windows" : process.platform}-${process.arch}`
|
||||
const directory = path.join(import.meta.dir, "..", "dist", ...(nodeBuild ? ["node"] : []), target, "bin")
|
||||
const binary = path.join(directory, `opencode2${nodeBuild ? "-node" : ""}${process.platform === "win32" ? ".exe" : ""}`)
|
||||
const binary = path.join(
|
||||
directory,
|
||||
`${nodeBuild ? "opencode2-node" : "opencode"}${process.platform === "win32" ? ".exe" : ""}`,
|
||||
)
|
||||
if (!(await Bun.file(binary).exists())) throw new Error(`Missing compiled CLI in ${directory}`)
|
||||
|
||||
const root = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), "opencode-service-smoke-")))
|
||||
|
||||
@@ -36,7 +36,7 @@ const PermissionParams = {
|
||||
}
|
||||
|
||||
const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME : "opencode", {
|
||||
description: "OpenCode 2.0 preview command line interface",
|
||||
description: "OpenCode command line interface",
|
||||
params: {
|
||||
...ServerParams,
|
||||
...PermissionParams,
|
||||
|
||||
@@ -105,7 +105,7 @@ const make = Effect.gen(function* () {
|
||||
global.home,
|
||||
".opencode",
|
||||
"bin",
|
||||
process.platform === "win32" ? "opencode2.exe" : "opencode2",
|
||||
process.platform === "win32" ? "opencode.exe" : "opencode",
|
||||
)
|
||||
if (path.resolve(process.execPath) === path.resolve(binary)) return "curl"
|
||||
if (!installedPackage) return
|
||||
@@ -186,7 +186,10 @@ const make = Effect.gen(function* () {
|
||||
"npm",
|
||||
"install",
|
||||
"--global",
|
||||
...(installedPackage && packageName !== installedPackage ? ["--force"] : []),
|
||||
...((OPENCODE_ARTIFACT === "cli" && !installedPackage?.endsWith("/cli-node")) ||
|
||||
(installedPackage && packageName !== installedPackage)
|
||||
? ["--force"]
|
||||
: []),
|
||||
target,
|
||||
],
|
||||
pnpm: ["pnpm", "add", "--global", `--allow-build=${packageName}`, target],
|
||||
|
||||
@@ -100,7 +100,7 @@ function fixture(
|
||||
}
|
||||
|
||||
const installs = [
|
||||
{ method: "npm", command: ["npm", "install", "--global", "@opencode/cli@2.3.4-beta.1"] },
|
||||
{ method: "npm", command: ["npm", "install", "--global", "--force", "@opencode/cli@2.3.4-beta.1"] },
|
||||
{
|
||||
method: "pnpm",
|
||||
command: ["pnpm", "add", "--global", "--allow-build=@opencode/cli", "@opencode/cli@2.3.4-beta.1"],
|
||||
|
||||
@@ -111,13 +111,13 @@ for themselves without limiting it to the current project; omit it when they
|
||||
explicitly want project-local configuration.
|
||||
|
||||
```sh
|
||||
opencode2 mcp add <name> --global --url <remote-url>
|
||||
opencode2 mcp list
|
||||
opencode mcp add <name> --global --url <remote-url>
|
||||
opencode mcp list
|
||||
```
|
||||
|
||||
Remote servers use OAuth by default. If `mcp list` reports that a server needs
|
||||
authentication, tell the user to run `/mcps`, select the server, and sign in.
|
||||
Do not run `opencode2 mcp auth` through the shell tool: it starts an interactive
|
||||
Do not run `opencode mcp auth` through the shell tool: it starts an interactive
|
||||
flow whose authorization link can be hidden in background process output.
|
||||
Use the user-facing MCP interface instead.
|
||||
|
||||
@@ -168,13 +168,13 @@ OpenCode normally discovers or starts the shared background service
|
||||
automatically. If the service is stuck or unhealthy, restart it:
|
||||
|
||||
```sh
|
||||
opencode2 service restart
|
||||
opencode service restart
|
||||
```
|
||||
|
||||
Check its status after restarting:
|
||||
|
||||
```sh
|
||||
opencode2 service status
|
||||
opencode service status
|
||||
```
|
||||
|
||||
## [API](https://opencode.ai/v2/docs/api)
|
||||
@@ -190,15 +190,15 @@ HTTP method and path or an OpenAPI operation ID.
|
||||
Call an endpoint with an HTTP method and path:
|
||||
|
||||
```sh
|
||||
opencode2 api get /api/health
|
||||
opencode api get /api/health
|
||||
```
|
||||
|
||||
Pass a request body with `--data` or `-d`, and additional headers with
|
||||
`--header` or `-H`:
|
||||
|
||||
```sh
|
||||
opencode2 api post /api/example --data '{"key":"value"}'
|
||||
opencode2 api get /api/example --header 'X-Example:value'
|
||||
opencode api post /api/example --data '{"key":"value"}'
|
||||
opencode api get /api/example --header 'X-Example:value'
|
||||
```
|
||||
|
||||
Request bodies default to `Content-Type: application/json`. When OpenCode is
|
||||
@@ -240,9 +240,9 @@ Effect applications. For Cloudflare Durable Objects, use the
|
||||
OpenCode runs a client and a background server. Start by determining whether a
|
||||
problem belongs to the client, the shared server, or one project.
|
||||
|
||||
- Check the service with `opencode2 service status` and verify the API with
|
||||
`opencode2 api get /api/health`.
|
||||
- Compare with `opencode2 --standalone`, which runs the TUI with a private
|
||||
- Check the service with `opencode service status` and verify the API with
|
||||
`opencode api get /api/health`.
|
||||
- Compare with `opencode --standalone`, which runs the TUI with a private
|
||||
server, to isolate shared-service issues.
|
||||
- Inspect `~/.local/share/opencode/log/opencode.log`. Filter `role=cli` for
|
||||
client startup and `role=server` for sessions, providers, plugins,
|
||||
|
||||
@@ -26,8 +26,7 @@ title/body for the user.
|
||||
|
||||
Collect these values when possible:
|
||||
|
||||
- opencode version: run `opencode --version` or `opencode2 --version`,
|
||||
depending on the executable in use.
|
||||
- opencode version: run `opencode --version`.
|
||||
- Operating system: run `uname -a` on Unix-like systems, or `ver` on Windows.
|
||||
- Terminal: inspect `$TERM`, `$TERM_PROGRAM`, `$COLORTERM`, and any obvious
|
||||
terminal app context the user provides.
|
||||
|
||||
@@ -76,7 +76,7 @@ export async function downloadCliToResources(version = CLI_VERSION, dest = windo
|
||||
try {
|
||||
await $`bun install --no-save --cwd ${directory} ${`${cli.package}@${version}`} ${`--os=${cli.os}`} ${`--cpu=${cli.cpu}`}`
|
||||
await copyCliToResources(
|
||||
join(directory, "node_modules", cli.package, "bin", cli.os === "win32" ? "opencode2.exe" : "opencode2"),
|
||||
join(directory, "node_modules", cli.package, "bin", cli.os === "win32" ? "opencode.exe" : "opencode"),
|
||||
dest,
|
||||
)
|
||||
} finally {
|
||||
@@ -89,7 +89,7 @@ export async function downloadCliToResources(version = CLI_VERSION, dest = windo
|
||||
export async function copyBuiltCliToResources(root: string, dest = windowsify("resources/opencode-cli")) {
|
||||
const cli = getCurrentCli()
|
||||
const directory = cli.package.replace("@opencode/", "")
|
||||
await copyCliToResources(join(root, directory, "bin", cli.os === "win32" ? "opencode2.exe" : "opencode2"), dest)
|
||||
await copyCliToResources(join(root, directory, "bin", cli.os === "win32" ? "opencode.exe" : "opencode"), dest)
|
||||
}
|
||||
|
||||
async function copyCliToResources(source: string, dest: string) {
|
||||
|
||||
@@ -44,8 +44,8 @@ posix(
|
||||
const home = path.join(dir, "home with ' quotes")
|
||||
yield* fs.makeDirectory(path.join(home, ".opencode/bin"), { recursive: true })
|
||||
yield* fs.makeDirectory(path.join(dir, "bin"))
|
||||
const managed = path.join(home, ".opencode/bin/opencode2")
|
||||
const external = path.join(dir, "bin/opencode2")
|
||||
const managed = path.join(home, ".opencode/bin/opencode")
|
||||
const external = path.join(dir, "bin/opencode")
|
||||
yield* fs.writeFileString(managed, "#!/bin/sh\nprintf 'OpenCode v2.0.0\\n'\n", { mode: 0o755 })
|
||||
yield* fs.writeFileString(external, "#!/bin/sh\nprintf 'OpenCode v2.1.0\\n'\n", { mode: 0o755 })
|
||||
const run = (script: string) =>
|
||||
@@ -79,7 +79,7 @@ posix(
|
||||
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
||||
const dir = yield* fs.makeTempDirectoryScoped({ prefix: "remote-install-" })
|
||||
yield* fs.makeDirectory(path.join(dir, "package/bin"), { recursive: true })
|
||||
yield* fs.writeFileString(path.join(dir, "package/bin/opencode2"), "#!/bin/sh\nprintf 'OpenCode v2.0.0\\n'\n", {
|
||||
yield* fs.writeFileString(path.join(dir, "package/bin/opencode"), "#!/bin/sh\nprintf 'OpenCode v2.0.0\\n'\n", {
|
||||
mode: 0o755,
|
||||
})
|
||||
const archive = path.join(dir, "archive.tgz")
|
||||
@@ -101,13 +101,13 @@ posix(
|
||||
}),
|
||||
)
|
||||
expect(yield* run({ version: "2.0.0", source: { type: "download", url: server.url.href } })).toBe(0)
|
||||
expect(yield* fs.readFileString(path.join(dir, ".opencode/bin/opencode2"))).toContain("2.0.0")
|
||||
expect(yield* fs.readFileString(path.join(dir, ".opencode/bin/opencode"))).toContain("2.0.0")
|
||||
expect(
|
||||
yield* run({ version: "2.0.0", directory: ".opencode/desktop-ssh/2.0.0", source: { type: "archive" } }),
|
||||
).toBe(0)
|
||||
expect(yield* fs.readFileString(path.join(dir, ".opencode/desktop-ssh/2.0.0/opencode2"))).toContain("2.0.0")
|
||||
expect(yield* fs.readFileString(path.join(dir, ".opencode/desktop-ssh/2.0.0/opencode"))).toContain("2.0.0")
|
||||
expect(yield* run({ version: "2.1.0", source: { type: "archive" } })).not.toBe(0)
|
||||
expect(yield* fs.readFileString(path.join(dir, ".opencode/bin/opencode2"))).toContain("2.0.0")
|
||||
expect(yield* fs.readDirectory(path.join(dir, ".opencode/bin"))).toEqual(["opencode2"])
|
||||
expect(yield* fs.readFileString(path.join(dir, ".opencode/bin/opencode"))).toContain("2.0.0")
|
||||
expect(yield* fs.readDirectory(path.join(dir, ".opencode/bin"))).toEqual(["opencode"])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -24,12 +24,12 @@ export function requireVersion(version: string) {
|
||||
}
|
||||
|
||||
export function discoverScript(options: { fromPath?: boolean; cache?: { directory: string; prefix: string } } = {}) {
|
||||
return `cli=${options.fromPath ? "$(command -v opencode2 || true)" : '""'}
|
||||
if [ -z "$cli" ] && [ -x "$HOME/.opencode/bin/opencode2" ]; then cli="$HOME/.opencode/bin/opencode2"; fi
|
||||
return `cli=${options.fromPath ? "$(command -v opencode || true)" : '""'}
|
||||
if [ -z "$cli" ] && [ -x "$HOME/.opencode/bin/opencode" ]; then cli="$HOME/.opencode/bin/opencode"; fi
|
||||
${
|
||||
options.cache
|
||||
? `if [ -z "$cli" ]; then
|
||||
for binary in "$HOME"/${quote(options.cache.directory)}/${quote(options.cache.prefix)}*/opencode2; do
|
||||
for binary in "$HOME"/${quote(options.cache.directory)}/${quote(options.cache.prefix)}*/opencode; do
|
||||
if [ -x "$binary" ]; then cli="$binary"; fi
|
||||
done
|
||||
fi
|
||||
@@ -80,18 +80,18 @@ export function installScript(input: { version: string; directory?: string; sour
|
||||
if (input.source.type === "installer")
|
||||
return `set -eu
|
||||
curl -fsSL https://raw.githubusercontent.com/anomalyco/opencode/v2/install | bash -s -- ${input.source.binary ? `--binary ${input.source.binary}` : `--version ${quote(version)}`}
|
||||
${verifyScript('"$HOME/.opencode/bin/opencode2"', version)}
|
||||
${verifyScript('"$HOME/.opencode/bin/opencode"', version)}
|
||||
`
|
||||
return `set -eu
|
||||
umask 077
|
||||
destination="$HOME"/${quote(`${input.directory ?? ".opencode/bin"}/opencode2`)}
|
||||
destination="$HOME"/${quote(`${input.directory ?? ".opencode/bin"}/opencode`)}
|
||||
mkdir -p "$(dirname "$destination")"
|
||||
stage=$(mktemp -d "$(dirname "$destination")/.install-XXXXXX")
|
||||
trap 'rm -rf "$stage"' EXIT
|
||||
${stageBinary(input.source)}
|
||||
chmod 755 "$stage/package/bin/opencode2"
|
||||
${verifyScript('"$stage/package/bin/opencode2"', version)}
|
||||
mv "$stage/package/bin/opencode2" "$destination"
|
||||
chmod 755 "$stage/package/bin/opencode"
|
||||
${verifyScript('"$stage/package/bin/opencode"', version)}
|
||||
mv "$stage/package/bin/opencode" "$destination"
|
||||
`
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ export const layer = Layer.effect(
|
||||
if (!cli.binary) return yield* Effect.fail(new Error("Bundled CLI executable is unavailable"))
|
||||
const home = app.getPath("home")
|
||||
yield* runInstaller(cli.binary, home)
|
||||
return path.join(home, ".opencode", "bin", "opencode2")
|
||||
return path.join(home, ".opencode", "bin", "opencode")
|
||||
})
|
||||
return Service.of({ resolve, install })
|
||||
}),
|
||||
|
||||
@@ -20,7 +20,7 @@ posix(
|
||||
const bin = path.join(dir, ".opencode/desktop-ssh", version)
|
||||
yield* fs.makeDirectory(bin, { recursive: true })
|
||||
yield* fs.writeFileString(
|
||||
path.join(bin, "opencode2"),
|
||||
path.join(bin, "opencode"),
|
||||
`#!/bin/sh
|
||||
set -eu
|
||||
case "$1 $2" in
|
||||
@@ -69,7 +69,7 @@ posix(
|
||||
yield* fs.makeDirectory(path.join(dir, ".opencode/bin"), { recursive: true })
|
||||
yield* fs.makeDirectory(path.join(dir, "state/opencode"), { recursive: true })
|
||||
yield* fs.writeFileString(
|
||||
path.join(dir, ".opencode/bin/opencode2"),
|
||||
path.join(dir, ".opencode/bin/opencode"),
|
||||
'#!/bin/sh\n[ "$1 $2" = "service status" ] || exit 66\nprintf "http://0.0.0.0:49374\\n"\n',
|
||||
{ mode: 0o755 },
|
||||
)
|
||||
|
||||
@@ -53,7 +53,7 @@ export function parseRegistration(output: string) {
|
||||
}
|
||||
|
||||
export function binaryPath(version: string) {
|
||||
return `$HOME/.opencode/desktop-ssh/${RemoteCli.requireVersion(version)}/opencode2`
|
||||
return `$HOME/.opencode/desktop-ssh/${RemoteCli.requireVersion(version)}/opencode`
|
||||
}
|
||||
|
||||
function connectionAddress(address: string, password: string) {
|
||||
|
||||
@@ -27,7 +27,7 @@ const make = Effect.fn("Ssh.make")(function* (cli: DesktopCli.Resolved) {
|
||||
const controller = yield* createSshController({
|
||||
version: cli.version,
|
||||
development: !app.isPackaged && cli.binary === undefined,
|
||||
binary: cli.binary ?? cli.command[0] ?? "opencode2",
|
||||
binary: cli.binary ?? cli.command[0] ?? "opencode",
|
||||
command: cli.command,
|
||||
configs: stored._tag === "Some" ? stored.value : [],
|
||||
save: (configs) => Effect.try({ try: () => getStore().set("ssh.servers", configs), catch: SshFailure.from }),
|
||||
|
||||
@@ -33,7 +33,7 @@ export const buildLocalWslCli = Effect.fn("Wsl.buildLocalCli")(function* (input:
|
||||
[
|
||||
packageManager,
|
||||
input.script,
|
||||
`--target=opencode2-${target}`,
|
||||
`--target=opencode-${target}`,
|
||||
"--skip-install",
|
||||
"--skip-web-ui",
|
||||
`--outdir=${directory}`,
|
||||
@@ -41,7 +41,7 @@ export const buildLocalWslCli = Effect.fn("Wsl.buildLocalCli")(function* (input:
|
||||
{ cwd: root, env: { ...process.env, OPENCODE_VERSION: input.version }, windowsHide: true },
|
||||
),
|
||||
)
|
||||
yield* fs.copyFile(path.join(directory, `cli-${target}`, "bin", "opencode2"), input.output)
|
||||
yield* fs.copyFile(path.join(directory, `cli-${target}`, "bin", "opencode"), input.output)
|
||||
return input.output
|
||||
})
|
||||
return yield* build.pipe(Effect.ensuring(fs.remove(directory, { recursive: true, force: true }).pipe(Effect.orDie)))
|
||||
|
||||
@@ -32,7 +32,7 @@ posix(
|
||||
'#!/bin/sh\n[ "$1" = "-a" ] || exit 1\nprintf "%s" "$2" > "$HOME/wslpath-input"\nprintf "%s\\n" "$LOCAL_BINARY"\n',
|
||||
{ mode: 0o755 },
|
||||
)
|
||||
const windows = "C:\\local build's\\opencode2"
|
||||
const windows = "C:\\local build's\\opencode"
|
||||
const command = wslCliInstallCommand({ version: "0.0.0-dev-16365", binary: windows })
|
||||
expect(
|
||||
yield* spawner.exitCode(
|
||||
@@ -42,8 +42,8 @@ posix(
|
||||
),
|
||||
).toBe(0)
|
||||
expect(yield* fs.readFileString(path.join(dir, "wslpath-input"))).toBe(windows)
|
||||
expect(yield* fs.readFileString(path.join(dir, ".opencode/bin/opencode2"))).toContain("0.0.0-dev-16365")
|
||||
expect(yield* fs.readDirectory(path.join(dir, ".opencode/bin"))).toEqual(["opencode2"])
|
||||
expect(yield* fs.readFileString(path.join(dir, ".opencode/bin/opencode"))).toContain("0.0.0-dev-16365")
|
||||
expect((yield* fs.readDirectory(path.join(dir, ".opencode/bin"))).toSorted()).toEqual(["opencode", "opencode2"])
|
||||
expect(yield* fs.readFileString(path.join(dir, ".bashrc"))).toContain(`export PATH=${dir}/.opencode/bin:$PATH`)
|
||||
}),
|
||||
)
|
||||
@@ -57,7 +57,7 @@ test("installs and verifies the bundled CLI version", async () => {
|
||||
installCli: async (distro, cli) => {
|
||||
installs.push([distro, cli.version])
|
||||
},
|
||||
resolveCli: async () => "/home/me/.opencode/bin/opencode2",
|
||||
resolveCli: async () => "/home/me/.opencode/bin/opencode",
|
||||
}),
|
||||
),
|
||||
)
|
||||
@@ -74,7 +74,7 @@ test("rejects a WSL CLI version that differs from the bundled version", async ()
|
||||
createWslServersController(
|
||||
testControllerOptions({
|
||||
installCli: async () => undefined,
|
||||
resolveCli: async () => "/home/me/.opencode/bin/opencode2",
|
||||
resolveCli: async () => "/home/me/.opencode/bin/opencode",
|
||||
readCliVersion: async () => "0.0.0-dev-older",
|
||||
}),
|
||||
),
|
||||
@@ -166,7 +166,7 @@ test("probes addable distros in parallel before checking OpenCode", async () =>
|
||||
},
|
||||
resolveCli: async (distro) => {
|
||||
opencode.push(distro)
|
||||
return "/home/me/.opencode/bin/opencode2"
|
||||
return "/home/me/.opencode/bin/opencode"
|
||||
},
|
||||
}),
|
||||
),
|
||||
@@ -201,7 +201,7 @@ test("does not check OpenCode in addable distros that cannot execute commands",
|
||||
}),
|
||||
resolveCli: async (distro) => {
|
||||
opencode.push(distro)
|
||||
return "/home/me/.opencode/bin/opencode2"
|
||||
return "/home/me/.opencode/bin/opencode"
|
||||
},
|
||||
}),
|
||||
),
|
||||
@@ -238,7 +238,7 @@ function testControllerOptions(overrides: Partial<ControllerOptions> = {}): Cont
|
||||
persistedServers = servers
|
||||
},
|
||||
readCliVersion: async () => "0.0.0-dev-16365",
|
||||
resolveCli: async () => "/home/me/.opencode/bin/opencode2",
|
||||
resolveCli: async () => "/home/me/.opencode/bin/opencode",
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1171,10 +1171,12 @@ function App(props: { pair?: DialogPairCredentials }) {
|
||||
{
|
||||
name: "permission.mode",
|
||||
title:
|
||||
local.permission.mode === "auto" ? "Disable auto-approve permissions" : "Enable auto-approve permissions",
|
||||
category: "System",
|
||||
local.permission.mode === "autoaccept"
|
||||
? "Disable auto-approve permissions"
|
||||
: "Enable auto-approve permissions",
|
||||
category: "Session",
|
||||
run: () => {
|
||||
local.permission.toggle()
|
||||
void local.permission.toggle().catch(toast.error)
|
||||
dialog.clear()
|
||||
},
|
||||
},
|
||||
|
||||
@@ -120,6 +120,15 @@ export const settings: Setting[] = [
|
||||
labels: ["launch directory", "active session"],
|
||||
keywords: ["directory", "cwd", "inherit"],
|
||||
},
|
||||
{
|
||||
title: "Permissions",
|
||||
category: "Session",
|
||||
path: ["session", "permissions"],
|
||||
default: "prompt",
|
||||
values: ["prompt", "autoaccept"],
|
||||
labels: ["prompt", "auto accept"],
|
||||
keywords: ["approve", "accept", "permission requests"],
|
||||
},
|
||||
{
|
||||
title: "Enabled",
|
||||
category: "Tabs",
|
||||
|
||||
@@ -1849,7 +1849,7 @@ export function Prompt(props: PromptProps) {
|
||||
<PromptMetadataRow
|
||||
mode={store.mode}
|
||||
agent={agentLabel()}
|
||||
auto={local.permission.mode === "auto"}
|
||||
auto={local.permission.mode === "autoaccept"}
|
||||
model={promptDisplay().modelLabel}
|
||||
provider={promptDisplay().providerLabel}
|
||||
variant={promptDisplay().variant}
|
||||
|
||||
@@ -168,6 +168,9 @@ export const Info = Schema.Struct({
|
||||
new_location: Schema.optional(Schema.Literals(["launch", "inherit"])).annotate({
|
||||
description: "Start new sessions in the TUI launch directory or inherit the active session location",
|
||||
}),
|
||||
permissions: Schema.optional(Schema.Literals(["prompt", "autoaccept"])).annotate({
|
||||
description: "Prompt for permission requests or accept them automatically",
|
||||
}),
|
||||
}),
|
||||
).annotate({ description: "Session transcript presentation settings" }),
|
||||
tabs: Schema.optional(
|
||||
@@ -254,8 +257,9 @@ export type Resolved = Omit<Info, "attention" | "cursor" | "keybinds" | "leader"
|
||||
style: "block" | "underline" | "line" | "default"
|
||||
blinking: boolean
|
||||
}
|
||||
session: Omit<NonNullable<Info["session"]>, "new_location" | "tps"> & {
|
||||
session: Omit<NonNullable<Info["session"]>, "new_location" | "permissions" | "tps"> & {
|
||||
new_location: "launch" | "inherit"
|
||||
permissions: "prompt" | "autoaccept"
|
||||
tps: boolean
|
||||
}
|
||||
tabs: {
|
||||
@@ -302,6 +306,7 @@ export function resolve(input: Info, options: { terminalSuspend: boolean }): Res
|
||||
session: {
|
||||
...input.session,
|
||||
new_location: input.session?.new_location ?? "launch",
|
||||
permissions: input.session?.permissions ?? "prompt",
|
||||
// Persistent terminal panes need the opencode-pty daemon, which does not ship Windows binaries.
|
||||
terminal: input.session?.terminal ?? process.platform !== "win32",
|
||||
tps: input.session?.tps ?? true,
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
import { createStore } from "solid-js/store"
|
||||
import { createEffect } from "solid-js"
|
||||
import { useConfig } from "../config"
|
||||
import { useArgs } from "./args"
|
||||
import { createSimpleContext } from "./helper"
|
||||
|
||||
export type PermissionMode = "auto" | "normal"
|
||||
export type PermissionMode = "prompt" | "autoaccept"
|
||||
|
||||
export const { use: usePermission, provider: PermissionProvider } = createSimpleContext({
|
||||
name: "Permission",
|
||||
init: () => {
|
||||
const args = useArgs()
|
||||
const [store, setStore] = createStore<{ mode: PermissionMode }>({
|
||||
mode: args.auto ? "auto" : "normal",
|
||||
const config = useConfig()
|
||||
const [store, setStore] = createStore<{ mode: PermissionMode; configured: PermissionMode }>({
|
||||
mode: args.auto ? "autoaccept" : config.data.session.permissions,
|
||||
configured: config.data.session.permissions,
|
||||
})
|
||||
createEffect(() => {
|
||||
const mode = config.data.session.permissions
|
||||
if (mode === store.configured) return
|
||||
setStore({ mode, configured: mode })
|
||||
})
|
||||
return {
|
||||
get mode() {
|
||||
@@ -17,9 +26,12 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple
|
||||
},
|
||||
set(mode: PermissionMode) {
|
||||
setStore("mode", mode)
|
||||
return config.update((draft) => {
|
||||
draft.session = { ...draft.session, permissions: mode }
|
||||
})
|
||||
},
|
||||
toggle() {
|
||||
setStore("mode", (mode) => (mode === "auto" ? "normal" : "auto"))
|
||||
return this.set(store.mode === "autoaccept" ? "prompt" : "autoaccept")
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -185,7 +185,7 @@ export function Session(props: {
|
||||
(sessionID) => data.session.permission.list(sessionID) ?? [],
|
||||
)
|
||||
})
|
||||
const promptedPermissions = createMemo(() => (local.permission.mode === "auto" ? [] : permissions()))
|
||||
const promptedPermissions = createMemo(() => (local.permission.mode === "autoaccept" ? [] : permissions()))
|
||||
const forms = createMemo(() => {
|
||||
const global = data.session.form.list("global", location()) ?? []
|
||||
if (session()?.parentID) return global
|
||||
@@ -235,7 +235,7 @@ export function Session(props: {
|
||||
const client = useClient()
|
||||
const autoApproved = new Set<string>()
|
||||
createEffect(() => {
|
||||
if (local.permission.mode !== "auto") return
|
||||
if (local.permission.mode !== "autoaccept") return
|
||||
permissions().forEach((request) => {
|
||||
if (autoApproved.has(request.id)) return
|
||||
autoApproved.add(request.id)
|
||||
@@ -2660,7 +2660,7 @@ function useToolPermission(part: () => SessionMessageAssistantTool | undefined)
|
||||
const data = useData()
|
||||
const local = useLocal()
|
||||
return createMemo(() => {
|
||||
if (local.permission.mode === "auto") return false
|
||||
if (local.permission.mode === "autoaccept") return false
|
||||
const request = data.session.permission.list(ctx.sessionID)?.[0]
|
||||
return request?.source?.type === "tool" && request.source.id === part()?.id
|
||||
})
|
||||
|
||||
@@ -29,7 +29,7 @@ export function sessionEpilogue(input: { title: string; sessionID?: string }) {
|
||||
...wordmark(" "),
|
||||
"",
|
||||
` ${weak("Session")}${bold}${input.title}${reset}`,
|
||||
` ${weak("Continue")}${bold}opencode2 -s ${input.sessionID}${reset}`,
|
||||
` ${weak("Continue")}${bold}opencode -s ${input.sessionID}${reset}`,
|
||||
"",
|
||||
].join("\n")
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ test("session lifecycle updates the terminal title and prints the epilogue after
|
||||
await task
|
||||
|
||||
expect(stdout).toContain("Renamed session")
|
||||
expect(stdout).toContain("opencode2 -s dummy")
|
||||
expect(stdout).toContain("opencode -s dummy")
|
||||
expect(promptRequests).toBe(0)
|
||||
} finally {
|
||||
process.stdout.write = originalWrite
|
||||
|
||||
@@ -4,5 +4,5 @@ import { sessionEpilogue } from "../../src/util/presentation"
|
||||
test("formats session continuation summary", () => {
|
||||
const epilogue = sessionEpilogue({ title: "A session", sessionID: "ses_123" })
|
||||
expect(epilogue).toContain("A session")
|
||||
expect(epilogue).toContain("opencode2 -s ses_123")
|
||||
expect(epilogue).toContain("opencode -s ses_123")
|
||||
})
|
||||
|
||||
@@ -8,8 +8,8 @@ import config from "../../../config.mjs"
|
||||
export const console = config.console
|
||||
|
||||
:::note
|
||||
OpenCode 1 installs and runs as `opencode`. OpenCode 2 installs separately as `opencode2`, so you can keep both versions
|
||||
installed and run them side by side. See the [OpenCode 2 docs](https://opencode.ai/v2/docs/) to install V2.
|
||||
OpenCode 1 and OpenCode 2 both use the `opencode` command and cannot be installed side by side under their default command.
|
||||
See the [OpenCode 2 docs](https://opencode.ai/v2/docs/) to migrate to V2.
|
||||
:::
|
||||
|
||||
[**OpenCode**](/) is an open source AI coding agent. It's available as a terminal-based interface, desktop app, or IDE extension.
|
||||
@@ -37,7 +37,7 @@ To use OpenCode in your terminal, you'll need:
|
||||
## Install
|
||||
|
||||
The easiest way to install OpenCode 1 is through the install script. These installation methods provide the `opencode`
|
||||
binary and do not replace an `opencode2` installation.
|
||||
binary and can conflict with or replace an OpenCode 2 installation.
|
||||
|
||||
```bash
|
||||
curl -fsSL https://opencode.ai/install | bash
|
||||
|
||||
@@ -77,8 +77,8 @@ Both publishers upload signed/packaged outputs to the production bucket for
|
||||
every release channel:
|
||||
|
||||
```text
|
||||
R2 key: bin/0.0.0-dev-123/opencode2-linux-x64.tar.gz
|
||||
URL: https://opencode.ai/files/bin/0.0.0-dev-123/opencode2-linux-x64.tar.gz
|
||||
R2 key: bin/0.0.0-dev-123/opencode-linux-x64.tar.gz
|
||||
URL: https://opencode.ai/files/bin/0.0.0-dev-123/opencode-linux-x64.tar.gz
|
||||
|
||||
R2 key: bin/2.0.0/opencode-desktop-mac-arm64.dmg
|
||||
URL: https://opencode.ai/files/bin/2.0.0/opencode-desktop-mac-arm64.dmg
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
title: "ACP"
|
||||
description: "Use OpenCode with an Agent Client Protocol client."
|
||||
---
|
||||
|
||||
Configure your ACP client to launch `opencode acp`. For example, add OpenCode to Zed's
|
||||
`~/.config/zed/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_servers": {
|
||||
"OpenCode": {
|
||||
"command": "opencode",
|
||||
"args": ["acp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Other ACP clients use the same executable and `acp` argument, but their configuration file and field names may differ.
|
||||
If a graphical client cannot find `opencode`, set `command` to the absolute path reported by `which opencode`.
|
||||
|
||||
## Transport
|
||||
|
||||
`opencode acp` is an [Agent Client Protocol](https://agentclientprotocol.com) agent. The client starts it as a child
|
||||
process and exchanges newline-delimited JSON-RPC messages over stdin and stdout using ACP protocol version 1.
|
||||
|
||||
The command starts a private OpenCode server for that ACP process. It does not connect to the shared background service,
|
||||
and it does not expose an ACP network port.
|
||||
|
||||
The process can serve multiple ACP sessions. It runs until the client closes stdin, then exits and stops its private
|
||||
server.
|
||||
|
||||
## Sessions
|
||||
|
||||
When the client creates a session, it supplies the working directory. OpenCode loads that directory's configuration,
|
||||
plugins, models, agents, commands, skills, instructions, and MCP configuration before creating the session.
|
||||
|
||||
The ACP session lifecycle supports:
|
||||
|
||||
- Creating, listing, loading, resuming, forking, closing, and deleting sessions
|
||||
- Replaying saved messages when a client loads or forks a session
|
||||
- Cancelling an active prompt without closing the session
|
||||
- Streaming text, reasoning, tool calls, permission requests, and usage updates
|
||||
|
||||
The directory stored on an existing OpenCode session is authoritative. Loading, resuming, or forking that session uses
|
||||
its stored directory rather than a different directory supplied by the client.
|
||||
|
||||
Closing a session interrupts active work and detaches it from the ACP process, but keeps the saved session. Deleting a
|
||||
session removes it from OpenCode storage.
|
||||
|
||||
## Models
|
||||
|
||||
New sessions use the configured default model and primary agent for their directory. The client receives session options
|
||||
for all enabled models and all visible agents that are not subagents.
|
||||
|
||||
ACP clients can change these options during a session:
|
||||
|
||||
- **Model** selects an enabled model as `provider/model`.
|
||||
- **Effort** appears when the selected model provides variants.
|
||||
- **Mode** selects a visible agent that is not a subagent.
|
||||
|
||||
Model, effort, and mode changes are applied to the OpenCode session, so later prompts use the new selection.
|
||||
|
||||
## Content
|
||||
|
||||
Prompts can contain text, images, embedded resources, and file resource links. OpenCode also advertises available slash
|
||||
commands and skills to the client; `/compact` runs session compaction.
|
||||
|
||||
Clients may pass local or HTTP MCP servers when they create, load, resume, or fork a session. MCP over SSE and MCP over
|
||||
ACP are not supported by this command.
|
||||
|
||||
## Authentication
|
||||
|
||||
ACP authentication uses the provider credentials already available to OpenCode. Sign in from a terminal before starting
|
||||
the ACP client:
|
||||
|
||||
```bash
|
||||
opencode auth login
|
||||
```
|
||||
|
||||
Clients that support ACP terminal authentication can offer the OpenCode login command reported during initialization.
|
||||
The ACP `authenticate` request does not collect credentials itself.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Running `opencode acp` directly appears to wait because it expects ACP messages on stdin. Start it through an ACP client
|
||||
for normal use.
|
||||
|
||||
If the client reports that the process exited or returned invalid protocol output, enable ACP and private-server logs on
|
||||
stderr:
|
||||
|
||||
```bash
|
||||
opencode --print-logs acp
|
||||
```
|
||||
|
||||
Add `--print-logs` before `acp` in the client's argument list while diagnosing the problem. Stdout remains reserved for
|
||||
ACP messages.
|
||||
@@ -1,548 +1,567 @@
|
||||
---
|
||||
title: "Commands"
|
||||
description: "Reference for the opencode2 command line."
|
||||
description: "Reference for the opencode command line."
|
||||
---
|
||||
|
||||
Every command accepts `--help` for its full flag list, for example `opencode2 run --help`. Commands that talk to a server also accept `--standalone` to run a private server and `--server <url>` to target a specific one.
|
||||
Every command accepts `--help` for its full flag list, for example `opencode run --help`. Commands that talk to a server also accept `--standalone` to run a private server and `--server <url>` to target a specific one.
|
||||
|
||||
## run
|
||||
|
||||
`opencode2 run` sends a message and prints the reply without opening the interactive interface.
|
||||
`opencode run` sends a message and prints the reply without opening the interactive interface.
|
||||
|
||||
```bash
|
||||
$ opencode2 run "Explain this repository"
|
||||
$ opencode run "Explain this repository"
|
||||
```
|
||||
|
||||
### CI
|
||||
|
||||
In CI, pass a provider API key as a secret and use standalone mode so the private server receives it. For example, this GitHub Actions job reviews the checked-out repository:
|
||||
|
||||
```yaml
|
||||
name: OpenCode review
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: npm install --global @opencode/cli@beta
|
||||
- run: opencode run --standalone --model anthropic/claude-sonnet-4-5 "Review this repository for correctness and summarize any issues."
|
||||
env:
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
```
|
||||
|
||||
Choose a model.
|
||||
|
||||
```bash
|
||||
$ opencode2 run --model anthropic/claude-sonnet-4-5 "Refactor parseToken"
|
||||
$ opencode run --model anthropic/claude-sonnet-4-5 "Refactor parseToken"
|
||||
```
|
||||
|
||||
Continue the last session.
|
||||
|
||||
```bash
|
||||
$ opencode2 run --continue "Now handle the expired case"
|
||||
$ opencode run --continue "Now handle the expired case"
|
||||
```
|
||||
|
||||
Emit newline-delimited JSON for scripts.
|
||||
|
||||
```bash
|
||||
$ opencode2 run --format json "List the TODO comments"
|
||||
$ opencode run --format json "List the TODO comments"
|
||||
```
|
||||
|
||||
Attach files to the message.
|
||||
|
||||
```bash
|
||||
$ opencode2 run --file src/server.ts --file src/client.ts "Review these for bugs"
|
||||
$ opencode run --file src/server.ts --file src/client.ts "Review these for bugs"
|
||||
```
|
||||
|
||||
Run with a specific agent.
|
||||
|
||||
```bash
|
||||
$ opencode2 run --agent build "Fix the failing test"
|
||||
$ opencode run --agent build "Fix the failing test"
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 run --help
|
||||
$ opencode run --help
|
||||
```
|
||||
|
||||
## mini
|
||||
|
||||
`opencode2 mini` starts the minimal interactive interface instead of the full-screen TUI.
|
||||
`opencode mini` starts the minimal interactive interface instead of the full-screen TUI.
|
||||
|
||||
```bash
|
||||
$ opencode2 mini
|
||||
$ opencode mini
|
||||
```
|
||||
|
||||
Continue the last session.
|
||||
|
||||
```bash
|
||||
$ opencode2 mini --continue
|
||||
$ opencode mini --continue
|
||||
```
|
||||
|
||||
Start with a model and an initial prompt.
|
||||
|
||||
```bash
|
||||
$ opencode2 mini --model anthropic/claude-sonnet-4-5 --prompt "Summarize this repository"
|
||||
$ opencode mini --model anthropic/claude-sonnet-4-5 --prompt "Summarize this repository"
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 mini --help
|
||||
$ opencode mini --help
|
||||
```
|
||||
|
||||
## session
|
||||
|
||||
`opencode2 session` manages sessions.
|
||||
`opencode session` manages sessions.
|
||||
|
||||
```bash
|
||||
$ opencode2 session list
|
||||
$ opencode session list
|
||||
```
|
||||
|
||||
Limit the list and print JSON.
|
||||
|
||||
```bash
|
||||
$ opencode2 session list --max-count 20 --format json
|
||||
$ opencode session list --max-count 20 --format json
|
||||
```
|
||||
|
||||
Delete a session and its child sessions.
|
||||
|
||||
```bash
|
||||
$ opencode2 session delete ses_9c1b08
|
||||
$ opencode session delete ses_9c1b08
|
||||
```
|
||||
|
||||
Export session data as JSON.
|
||||
|
||||
```bash
|
||||
$ opencode2 session export ses_4f2a1c
|
||||
$ opencode session export ses_4f2a1c
|
||||
```
|
||||
|
||||
Redact sensitive transcript and file data when exporting.
|
||||
|
||||
```bash
|
||||
$ opencode2 session export ses_4f2a1c --sanitize
|
||||
$ opencode session export ses_4f2a1c --sanitize
|
||||
```
|
||||
|
||||
Import session data from a JSON file or URL.
|
||||
|
||||
```bash
|
||||
$ opencode2 session import session.json
|
||||
$ opencode session import session.json
|
||||
```
|
||||
|
||||
Import into a specific directory.
|
||||
|
||||
```bash
|
||||
$ opencode2 session import session.json --directory ~/code/project
|
||||
$ opencode session import session.json --directory ~/code/project
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 session --help
|
||||
$ opencode session --help
|
||||
```
|
||||
|
||||
## auth
|
||||
|
||||
`opencode2 auth` manages AI providers and credentials.
|
||||
`opencode auth` manages AI providers and credentials.
|
||||
|
||||
```bash
|
||||
$ opencode2 auth list
|
||||
$ opencode auth list
|
||||
```
|
||||
|
||||
List them as JSON.
|
||||
|
||||
```bash
|
||||
$ opencode2 auth list --format json
|
||||
$ opencode auth list --format json
|
||||
```
|
||||
|
||||
Log in to a provider.
|
||||
|
||||
```bash
|
||||
$ opencode2 auth login anthropic
|
||||
$ opencode auth login anthropic
|
||||
```
|
||||
|
||||
Log in with a specific authentication method.
|
||||
|
||||
```bash
|
||||
$ opencode2 auth login anthropic --method api-key
|
||||
$ opencode auth login anthropic --method api-key
|
||||
```
|
||||
|
||||
Log out of a saved account.
|
||||
|
||||
```bash
|
||||
$ opencode2 auth logout anthropic work
|
||||
$ opencode auth logout anthropic work
|
||||
```
|
||||
|
||||
Switch the active account for an integration.
|
||||
|
||||
```bash
|
||||
$ opencode2 auth switch anthropic work
|
||||
$ opencode auth switch anthropic work
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 auth --help
|
||||
$ opencode auth --help
|
||||
```
|
||||
|
||||
## models
|
||||
|
||||
`opencode2 models` lists every available model.
|
||||
`opencode models` lists every available model.
|
||||
|
||||
```bash
|
||||
$ opencode2 models
|
||||
$ opencode models
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 models --help
|
||||
$ opencode models --help
|
||||
```
|
||||
|
||||
## mcp
|
||||
|
||||
`opencode2 mcp` manages MCP (Model Context Protocol) servers.
|
||||
`opencode mcp` manages MCP (Model Context Protocol) servers.
|
||||
|
||||
```bash
|
||||
$ opencode2 mcp list
|
||||
$ opencode mcp list
|
||||
```
|
||||
|
||||
Add a remote server.
|
||||
|
||||
```bash
|
||||
$ opencode2 mcp add context7 --url https://mcp.context7.com/mcp
|
||||
$ opencode mcp add context7 --url https://mcp.context7.com/mcp
|
||||
```
|
||||
|
||||
Add a local server to the global config.
|
||||
|
||||
```bash
|
||||
$ opencode2 mcp add everything --global -- npx -y @modelcontextprotocol/server-everything
|
||||
$ opencode mcp add everything --global -- npx -y @modelcontextprotocol/server-everything
|
||||
```
|
||||
|
||||
Add a local server with an environment variable.
|
||||
|
||||
```bash
|
||||
$ opencode2 mcp add everything --env LOG_LEVEL=debug -- npx -y @modelcontextprotocol/server-everything
|
||||
$ opencode mcp add everything --env LOG_LEVEL=debug -- npx -y @modelcontextprotocol/server-everything
|
||||
```
|
||||
|
||||
Add a remote server with a header.
|
||||
|
||||
```bash
|
||||
$ opencode2 mcp add context7 --url https://mcp.context7.com/mcp --header CONTEXT7_API_KEY=secret
|
||||
$ opencode mcp add context7 --url https://mcp.context7.com/mcp --header CONTEXT7_API_KEY=secret
|
||||
```
|
||||
|
||||
Authenticate with an OAuth-capable remote server.
|
||||
|
||||
```bash
|
||||
$ opencode2 mcp auth sentry
|
||||
$ opencode mcp auth sentry
|
||||
```
|
||||
|
||||
Remove stored OAuth credentials for a server.
|
||||
|
||||
```bash
|
||||
$ opencode2 mcp logout sentry
|
||||
$ opencode mcp logout sentry
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 mcp --help
|
||||
$ opencode mcp --help
|
||||
```
|
||||
|
||||
## plugin
|
||||
|
||||
`opencode2 plugin` manages plugins.
|
||||
`opencode plugin` manages plugins.
|
||||
|
||||
```bash
|
||||
$ opencode2 plugin list
|
||||
$ opencode plugin list
|
||||
```
|
||||
|
||||
Include built-in server plugins.
|
||||
|
||||
```bash
|
||||
$ opencode2 plugin list --builtin
|
||||
$ opencode plugin list --builtin
|
||||
```
|
||||
|
||||
Install a plugin and add it to the global configuration.
|
||||
|
||||
```bash
|
||||
$ opencode2 plugin add @example/opencode-tui
|
||||
$ opencode plugin add @example/opencode-tui
|
||||
```
|
||||
|
||||
Check package plugins for updates.
|
||||
|
||||
```bash
|
||||
$ opencode2 plugin check
|
||||
$ opencode plugin check
|
||||
```
|
||||
|
||||
Update package plugins.
|
||||
|
||||
```bash
|
||||
$ opencode2 plugin update
|
||||
$ opencode plugin update
|
||||
```
|
||||
|
||||
Remove a plugin from global configuration.
|
||||
|
||||
```bash
|
||||
$ opencode2 plugin remove @example/opencode-tui
|
||||
$ opencode plugin remove @example/opencode-tui
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 plugin --help
|
||||
$ opencode plugin --help
|
||||
```
|
||||
|
||||
## stats
|
||||
|
||||
`opencode2 stats` shows shareable usage statistics.
|
||||
`opencode stats` shows shareable usage statistics.
|
||||
|
||||
```bash
|
||||
$ opencode2 stats
|
||||
$ opencode stats
|
||||
```
|
||||
|
||||
Show the last 7 days.
|
||||
|
||||
```bash
|
||||
$ opencode2 stats --days 7
|
||||
$ opencode stats --days 7
|
||||
```
|
||||
|
||||
Show model usage.
|
||||
|
||||
```bash
|
||||
$ opencode2 stats --models
|
||||
$ opencode stats --models
|
||||
```
|
||||
|
||||
Show cost and token details.
|
||||
|
||||
```bash
|
||||
$ opencode2 stats --cost
|
||||
$ opencode stats --cost
|
||||
```
|
||||
|
||||
Print JSON instead of a report.
|
||||
|
||||
```bash
|
||||
$ opencode2 stats --json
|
||||
$ opencode stats --json
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 stats --help
|
||||
$ opencode stats --help
|
||||
```
|
||||
|
||||
## serve
|
||||
|
||||
`opencode2 serve` starts the API and web server. See [Web](/cli/web).
|
||||
`opencode serve` starts the API and web server. See [Web](/cli/web).
|
||||
|
||||
```bash
|
||||
$ opencode2 serve
|
||||
$ opencode serve
|
||||
```
|
||||
|
||||
Bind to all interfaces on a fixed port.
|
||||
|
||||
```bash
|
||||
$ opencode2 serve --hostname 0.0.0.0 --port 4096
|
||||
$ opencode serve --hostname 0.0.0.0 --port 4096
|
||||
```
|
||||
|
||||
Allow a browser client from another origin.
|
||||
|
||||
```bash
|
||||
$ opencode2 serve --cors https://app.example.com
|
||||
$ opencode serve --cors https://app.example.com
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 serve --help
|
||||
$ opencode serve --help
|
||||
```
|
||||
|
||||
## pair
|
||||
|
||||
`opencode2 pair` shows server pairing information, including URLs, credentials, and a QR code.
|
||||
`opencode pair` shows server pairing information, including URLs, credentials, and a QR code.
|
||||
|
||||
```bash
|
||||
$ opencode2 pair
|
||||
$ opencode pair
|
||||
```
|
||||
|
||||
Advertise an external URL in the QR code.
|
||||
|
||||
```bash
|
||||
$ opencode2 pair --url https://dev.example.com
|
||||
$ opencode pair --url https://dev.example.com
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 pair --help
|
||||
$ opencode pair --help
|
||||
```
|
||||
|
||||
## service
|
||||
|
||||
`opencode2 service` manages the background server. See [Web](/cli/web).
|
||||
`opencode service` manages the background server. See [Web](/cli/web).
|
||||
|
||||
```bash
|
||||
$ opencode2 service start
|
||||
$ opencode service start
|
||||
```
|
||||
|
||||
Restart it.
|
||||
|
||||
```bash
|
||||
$ opencode2 service restart
|
||||
$ opencode service restart
|
||||
```
|
||||
|
||||
Show its status.
|
||||
|
||||
```bash
|
||||
$ opencode2 service status
|
||||
$ opencode service status
|
||||
```
|
||||
|
||||
Stop it.
|
||||
|
||||
```bash
|
||||
$ opencode2 service stop
|
||||
$ opencode service stop
|
||||
```
|
||||
|
||||
Read a setting.
|
||||
|
||||
```bash
|
||||
$ opencode2 service get hostname
|
||||
$ opencode service get hostname
|
||||
```
|
||||
|
||||
Set a setting.
|
||||
|
||||
```bash
|
||||
$ opencode2 service set hostname 0.0.0.0
|
||||
$ opencode service set hostname 0.0.0.0
|
||||
```
|
||||
|
||||
Allow an extra CORS origin.
|
||||
|
||||
```bash
|
||||
$ opencode2 service set cors https://app.example.com
|
||||
$ opencode service set cors https://app.example.com
|
||||
```
|
||||
|
||||
Pass an environment variable to the server process.
|
||||
|
||||
```bash
|
||||
$ opencode2 service set env OPENCODE_LOG_LEVEL DEBUG
|
||||
$ opencode service set env OPENCODE_LOG_LEVEL DEBUG
|
||||
```
|
||||
|
||||
Reset a setting to its default.
|
||||
|
||||
```bash
|
||||
$ opencode2 service unset hostname
|
||||
$ opencode service unset hostname
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 service --help
|
||||
$ opencode service --help
|
||||
```
|
||||
|
||||
## api
|
||||
|
||||
`opencode2 api` makes a request to the running server.
|
||||
`opencode api` makes a request to the running server.
|
||||
|
||||
```bash
|
||||
$ opencode2 api GET /api/session
|
||||
$ opencode api GET /api/session
|
||||
```
|
||||
|
||||
Call an operation ID with a query parameter.
|
||||
|
||||
```bash
|
||||
$ opencode2 api v2.session.list --param limit=10
|
||||
$ opencode api v2.session.list --param limit=10
|
||||
```
|
||||
|
||||
Send a JSON body.
|
||||
|
||||
```bash
|
||||
$ opencode2 api v2.session.create --data '{"title": "New session"}'
|
||||
$ opencode api v2.session.create --data '{"title": "New session"}'
|
||||
```
|
||||
|
||||
Add a request header.
|
||||
|
||||
```bash
|
||||
$ opencode2 api GET /api/session -H "accept: application/json"
|
||||
$ opencode api GET /api/session -H "accept: application/json"
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 api --help
|
||||
$ opencode api --help
|
||||
```
|
||||
|
||||
## acp
|
||||
|
||||
`opencode2 acp` starts an Agent Client Protocol server over stdin and stdout for editor integrations. It runs until the client closes the connection.
|
||||
`opencode acp` starts an Agent Client Protocol server over stdin and stdout for editor integrations. It runs until the client closes the connection.
|
||||
|
||||
```bash
|
||||
$ opencode2 acp
|
||||
$ opencode acp
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 acp --help
|
||||
$ opencode acp --help
|
||||
```
|
||||
|
||||
## debug
|
||||
|
||||
`opencode2 debug` provides debugging and troubleshooting tools.
|
||||
`opencode debug` provides debugging and troubleshooting tools.
|
||||
|
||||
```bash
|
||||
$ opencode2 debug agents
|
||||
$ opencode debug agents
|
||||
```
|
||||
|
||||
List configuration sources.
|
||||
|
||||
```bash
|
||||
$ opencode2 debug config
|
||||
$ opencode debug config
|
||||
```
|
||||
|
||||
Show global paths.
|
||||
|
||||
```bash
|
||||
$ opencode2 debug paths
|
||||
$ opencode debug paths
|
||||
```
|
||||
|
||||
Print a single path.
|
||||
|
||||
```bash
|
||||
$ opencode2 debug paths db
|
||||
$ opencode debug paths db
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 debug --help
|
||||
$ opencode debug --help
|
||||
```
|
||||
|
||||
## upgrade
|
||||
|
||||
`opencode2 upgrade` upgrades OpenCode to the latest or a specific version. Alias: `update`.
|
||||
`opencode upgrade` upgrades OpenCode to the latest or a specific version. Alias: `update`.
|
||||
|
||||
```bash
|
||||
$ opencode2 upgrade
|
||||
$ opencode upgrade
|
||||
```
|
||||
|
||||
Upgrade to a specific version with a specific package manager.
|
||||
|
||||
```bash
|
||||
$ opencode2 upgrade 1.18.15 --method bun
|
||||
$ opencode upgrade 1.18.15 --method bun
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 upgrade --help
|
||||
$ opencode upgrade --help
|
||||
```
|
||||
|
||||
## uninstall
|
||||
|
||||
`opencode2 uninstall` removes OpenCode and all related files.
|
||||
`opencode uninstall` removes OpenCode and all related files.
|
||||
|
||||
```bash
|
||||
$ opencode2 uninstall
|
||||
$ opencode uninstall
|
||||
```
|
||||
|
||||
Preview what would be removed.
|
||||
|
||||
```bash
|
||||
$ opencode2 uninstall --dry-run
|
||||
$ opencode uninstall --dry-run
|
||||
```
|
||||
|
||||
Keep configuration and session data.
|
||||
|
||||
```bash
|
||||
$ opencode2 uninstall --keep-config --keep-data
|
||||
$ opencode uninstall --keep-config --keep-data
|
||||
```
|
||||
|
||||
View all subcommands and flags.
|
||||
|
||||
```bash
|
||||
$ opencode2 uninstall --help
|
||||
$ opencode uninstall --help
|
||||
```
|
||||
|
||||
@@ -134,6 +134,22 @@ Configure notifications and sounds:
|
||||
| `sound_pack` | string | Selects the active sound pack. |
|
||||
| `sounds` | object | Overrides files for `default`, `question`, `permission`, `error`, `done`, or `subagent_done` events. |
|
||||
|
||||
## Session
|
||||
|
||||
Choose whether the TUI prompts before granting permission requests:
|
||||
|
||||
```json title="cli.json"
|
||||
{
|
||||
"session": {
|
||||
"permissions": "prompt"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Values | Description |
|
||||
| ------------- | ------------------------ | ----------------------------------------------------------------------- |
|
||||
| `permissions` | `prompt` or `autoaccept` | Prompts for permission requests or accepts every request automatically. |
|
||||
|
||||
## Diffs
|
||||
|
||||
Configure diff presentation:
|
||||
|
||||
@@ -5,13 +5,13 @@ title: "Intro"
|
||||
Run the CLI in a project to open the full-screen terminal interface:
|
||||
|
||||
```bash
|
||||
opencode2
|
||||
opencode
|
||||
```
|
||||
|
||||
Pass a directory to work in a different project:
|
||||
|
||||
```bash
|
||||
opencode2 ~/code/my-project
|
||||
opencode ~/code/my-project
|
||||
```
|
||||
|
||||
Suggested terminals:
|
||||
@@ -26,22 +26,22 @@ palette.
|
||||
|
||||
## Automation
|
||||
|
||||
Use `opencode2 run` to submit a prompt without opening the interactive interface. It is designed for scripts, CI jobs, and
|
||||
Use `opencode run` to submit a prompt without opening the interactive interface. It is designed for scripts, CI jobs, and
|
||||
other workflows that need model output directly in the terminal.
|
||||
|
||||
```bash
|
||||
opencode2 run "Explain this repository"
|
||||
opencode run "Explain this repository"
|
||||
```
|
||||
|
||||
## Mini
|
||||
|
||||
Use `opencode2 mini` to start OpenCode's minimal interactive interface instead of the full-screen TUI.
|
||||
Use `opencode mini` to start OpenCode's minimal interactive interface instead of the full-screen TUI.
|
||||
|
||||
```bash
|
||||
opencode2 mini
|
||||
opencode mini
|
||||
```
|
||||
|
||||
Run `opencode2 mini --help` to see its session, model, agent, prompt, and replay options.
|
||||
Run `opencode mini --help` to see its session, model, agent, prompt, and replay options.
|
||||
|
||||
## Background service
|
||||
|
||||
@@ -51,8 +51,8 @@ connects to that server, which owns sessions, configuration, integrations, permi
|
||||
Use `--standalone` to run with a private server, or `--server` to connect to a specific server URL:
|
||||
|
||||
```bash
|
||||
opencode2 --standalone
|
||||
opencode2 --server http://localhost:4096
|
||||
opencode --standalone
|
||||
opencode --server http://localhost:4096
|
||||
```
|
||||
|
||||
See [Troubleshooting](/troubleshooting) for shared service diagnostics and the [API reference](/api) for server endpoints.
|
||||
@@ -62,8 +62,8 @@ See [Troubleshooting](/troubleshooting) for shared service diagnostics and the [
|
||||
Print a specific local path for use with other tools:
|
||||
|
||||
```bash
|
||||
opencode2 debug paths db
|
||||
sqlite3 "$(opencode2 debug paths db)"
|
||||
opencode debug paths db
|
||||
sqlite3 "$(opencode debug paths db)"
|
||||
```
|
||||
|
||||
The optional selector accepts `db`, `home`, `data`, `config`, `cache`, `state`, `tmp`, `bin`, `log`, or `repos` and prints
|
||||
@@ -73,7 +73,7 @@ resolve under the data directory, and `:memory:` is printed as-is. This command
|
||||
Omit the selector to show all paths with labels:
|
||||
|
||||
```bash
|
||||
opencode2 debug paths
|
||||
opencode debug paths
|
||||
```
|
||||
|
||||
## Uninstall
|
||||
@@ -81,16 +81,16 @@ opencode2 debug paths
|
||||
Preview the files and installation that will be removed:
|
||||
|
||||
```bash
|
||||
opencode2 uninstall --dry-run
|
||||
opencode uninstall --dry-run
|
||||
```
|
||||
|
||||
Run `opencode2 uninstall` to confirm removal. OpenCode stops registered background services and persistent terminals before
|
||||
Run `opencode uninstall` to confirm removal. OpenCode stops registered background services and persistent terminals before
|
||||
removing global data, cache, configuration, and state. These directories are shared by OpenCode versions and channels.
|
||||
|
||||
To retain configuration and session data:
|
||||
|
||||
```bash
|
||||
opencode2 uninstall --keep-config --keep-data
|
||||
opencode uninstall --keep-config --keep-data
|
||||
```
|
||||
|
||||
- `--keep-config` (`-c`) retains configuration files.
|
||||
|
||||
@@ -101,7 +101,7 @@ Unknown command IDs are rejected.
|
||||
|
||||
## Mini
|
||||
|
||||
The `app.clear` command works only in [`opencode2 mini`](/cli). Press `ctrl+l` to clear the visible screen and draw the prompt again. The terminal keeps the scrollback.
|
||||
The `app.clear` command works only in [`opencode mini`](/cli). Press `ctrl+l` to clear the visible screen and draw the prompt again. The terminal keeps the scrollback.
|
||||
|
||||
```json title="cli.json"
|
||||
{
|
||||
|
||||
@@ -32,20 +32,20 @@ Use `auth login` for the same provider methods without opening the TUI. With no
|
||||
interactive provider picker.
|
||||
|
||||
```bash
|
||||
opencode2 auth login
|
||||
opencode auth login
|
||||
```
|
||||
|
||||
Pass an integration ID or name to skip the first picker. Use `--method key` to select API-key entry explicitly.
|
||||
|
||||
```bash
|
||||
opencode2 auth login anthropic --method key
|
||||
opencode auth login anthropic --method key
|
||||
```
|
||||
|
||||
Method IDs are provider-specific. Run the command without `--method` to see the available methods when a provider has
|
||||
more than one.
|
||||
|
||||
```bash
|
||||
opencode2 auth login openai
|
||||
opencode auth login openai
|
||||
```
|
||||
|
||||
API-key entry and provider forms require an interactive terminal. OAuth methods that ask you to paste an authorization
|
||||
@@ -71,15 +71,15 @@ Set a provider's supported environment variable on the server process that runs
|
||||
server, pass it when starting standalone mode.
|
||||
|
||||
```bash
|
||||
ANTHROPIC_API_KEY=sk-ant-... opencode2 --standalone
|
||||
ANTHROPIC_API_KEY=sk-ant-... opencode --standalone
|
||||
```
|
||||
|
||||
For the shared background server, add the variable to its managed environment. This stops a running service; the next
|
||||
OpenCode command starts it with the new value.
|
||||
|
||||
```bash
|
||||
opencode2 service set env ANTHROPIC_API_KEY sk-ant-...
|
||||
opencode2 auth list
|
||||
opencode service set env ANTHROPIC_API_KEY sk-ant-...
|
||||
opencode auth list
|
||||
```
|
||||
|
||||
Environment connections appear in `auth list` with type `environment`. They are not accounts: `auth logout` cannot
|
||||
@@ -87,8 +87,8 @@ remove them, so unset the variable to disconnect. A saved account takes preceden
|
||||
the same integration.
|
||||
|
||||
```bash
|
||||
opencode2 auth list
|
||||
opencode2 service unset env ANTHROPIC_API_KEY
|
||||
opencode auth list
|
||||
opencode service unset env ANTHROPIC_API_KEY
|
||||
```
|
||||
|
||||
Some cloud providers also use their native ambient credential chain instead of an API-key variable:
|
||||
@@ -102,7 +102,7 @@ Some cloud providers also use their native ambient credential chain instead of a
|
||||
|
||||
```bash
|
||||
gcloud auth application-default login
|
||||
GOOGLE_CLOUD_PROJECT=my-project opencode2
|
||||
GOOGLE_CLOUD_PROJECT=my-project opencode
|
||||
```
|
||||
|
||||
See [Providers](/providers) for provider-specific and server-side setup.
|
||||
@@ -113,14 +113,14 @@ Each successful API-key, OAuth, or command login creates a saved account. The ne
|
||||
active account by its label or credential ID.
|
||||
|
||||
```bash
|
||||
opencode2 auth list
|
||||
opencode2 auth switch anthropic work
|
||||
opencode auth list
|
||||
opencode auth switch anthropic work
|
||||
```
|
||||
|
||||
Remove a saved account with `auth logout`. Both commands open pickers when their arguments are omitted.
|
||||
|
||||
```bash
|
||||
opencode2 auth logout anthropic work
|
||||
opencode auth logout anthropic work
|
||||
```
|
||||
|
||||
In the TUI, `/connect` provides the same add, activate, rename, and delete operations for saved accounts.
|
||||
@@ -130,7 +130,7 @@ In the TUI, `/connect` provides the same add, activate, rename, and delete opera
|
||||
Saved API keys and OAuth tokens live in the server's SQLite database. For the local server, print its database path with:
|
||||
|
||||
```bash
|
||||
opencode2 debug paths db
|
||||
opencode debug paths db
|
||||
```
|
||||
|
||||
The usual release path is `~/.local/share/opencode/opencode.db`; `XDG_DATA_HOME`, the release channel, and `OPENCODE_DB`
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
title: "TUI"
|
||||
description: "Start a session and use the everyday workflows in the terminal interface."
|
||||
---
|
||||
|
||||
Run OpenCode from your project, type a request, and press **Enter**.
|
||||
|
||||
```bash
|
||||
cd ~/code/my-project
|
||||
opencode
|
||||
```
|
||||
|
||||
```text
|
||||
Explain how authentication works in this project
|
||||
```
|
||||
|
||||
Press **Shift+Enter**, **Ctrl+Enter**, or **Ctrl+J** for a new line. While OpenCode is working, **Enter** steers the active session and **Alt+Enter** queues the prompt for later.
|
||||
|
||||
## Context
|
||||
|
||||
Type `@` to search for a file, then select it to attach that file to the prompt. Keep typing after `@` to narrow the results.
|
||||
|
||||
```text
|
||||
Review @src/auth.ts for error handling problems
|
||||
```
|
||||
|
||||
You can include a line or range after the path.
|
||||
|
||||
```text
|
||||
Explain @src/auth.ts#20-45
|
||||
```
|
||||
|
||||
## Shell
|
||||
|
||||
Type `!` at the start of an empty prompt to enter shell mode. Enter a command and press **Enter**; press **Esc** to leave shell mode without running one.
|
||||
|
||||
```text
|
||||
!git status
|
||||
```
|
||||
|
||||
Shell commands run in the session's working directory and their output stays in the session.
|
||||
|
||||
## Commands
|
||||
|
||||
Type `/` to list slash commands. Continue typing to filter the list, then press **Enter** to run the selected command.
|
||||
|
||||
```text
|
||||
/models
|
||||
```
|
||||
|
||||
Common commands include `/new`, `/sessions`, `/models`, `/agents`, `/undo`, `/redo`, and `/editor`. Press **Ctrl+P** to open the command palette for every action available in the current view.
|
||||
|
||||
## Models
|
||||
|
||||
Press **Ctrl+X**, then **M** to choose a model, or run `/models`. Press **F2** to cycle through recently used models.
|
||||
|
||||
Press **Ctrl+X**, then **A** to choose an agent, or run `/agents`. Press **Shift+Tab** to cycle agents.
|
||||
|
||||
## Sessions
|
||||
|
||||
Press **Ctrl+X**, then **N** to start a new session. Press **Ctrl+X**, then **L** or run `/sessions` to return to an existing session; **Ctrl+O** opens recent sessions and projects together.
|
||||
|
||||
Tabs are enabled by default. Use **Ctrl+Tab** and **Ctrl+Shift+Tab** to move between them, **Ctrl+X** then **W** to close one, and **Ctrl+Shift+T** to reopen the last closed tab.
|
||||
|
||||
## History
|
||||
|
||||
Press **Ctrl+X**, then **U**, or run `/undo`, to revert the latest user message and the work that followed it. The reverted prompt returns to the composer so you can edit it.
|
||||
|
||||
Press **Ctrl+X**, then **R**, or run `/redo`, to restore the reverted work. Sending a new prompt instead accepts the revert and continues from that point.
|
||||
|
||||
## Editor
|
||||
|
||||
Set `VISUAL` or `EDITOR`, then press **Ctrl+X**, then **E**, or run `/editor`, to edit the current prompt in that editor. Save and exit to return the text to the composer, then press **Enter** to send it.
|
||||
|
||||
```bash
|
||||
export EDITOR="nvim"
|
||||
opencode
|
||||
```
|
||||
|
||||
The leader key is **Ctrl+X** by default. See [Keybinds](/cli/keybinds) to change these shortcuts.
|
||||
@@ -9,7 +9,7 @@ TUI. It's available by default and password protected.
|
||||
## Access
|
||||
|
||||
```bash
|
||||
$ opencode2 pair
|
||||
$ opencode pair
|
||||
|
||||
URLs http://127.0.0.1:49374
|
||||
Username opencode
|
||||
@@ -17,42 +17,42 @@ $ opencode2 pair
|
||||
```
|
||||
|
||||
By default the server runs on port 49374 and listens only on localhost. You can
|
||||
change this config with the `opencode2 service` command.
|
||||
change this config with the `opencode service` command.
|
||||
|
||||
## Configure
|
||||
|
||||
Set any option with `opencode2 service set`:
|
||||
Set any option with `opencode service set`:
|
||||
|
||||
```bash
|
||||
# Listen on every network interface
|
||||
$ opencode2 service set hostname 0.0.0.0
|
||||
$ opencode service set hostname 0.0.0.0
|
||||
|
||||
# Use a fixed port instead of the channel default
|
||||
$ opencode2 service set port 49374
|
||||
$ opencode service set port 49374
|
||||
|
||||
# Replace the generated password
|
||||
$ opencode2 service set password "a-long-secret"
|
||||
$ opencode service set password "a-long-secret"
|
||||
|
||||
# Allow a web client served from another origin
|
||||
$ opencode2 service set cors https://app.example.com,https://other.example.com
|
||||
$ opencode service set cors https://app.example.com,https://other.example.com
|
||||
|
||||
# Pass an environment variable to the server process
|
||||
$ opencode2 service set env OPENCODE_LOG_LEVEL DEBUG
|
||||
$ opencode service set env OPENCODE_LOG_LEVEL DEBUG
|
||||
```
|
||||
|
||||
Changing a setting stops the background server. To apply the new config
|
||||
|
||||
```bash
|
||||
$ opencode2 service start
|
||||
$ opencode service start
|
||||
```
|
||||
|
||||
## Standalone
|
||||
|
||||
`opencode2 serve` runs the same server in the foreground instead of through the
|
||||
`opencode serve` runs the same server in the foreground instead of through the
|
||||
shared background service.
|
||||
|
||||
```bash
|
||||
$ opencode2 serve --hostname 0.0.0.0 --port 4096
|
||||
$ opencode serve --hostname 0.0.0.0 --port 4096
|
||||
server listening on http://0.0.0.0:4096
|
||||
server password <password>
|
||||
```
|
||||
@@ -60,7 +60,7 @@ server password <password>
|
||||
Use it when you want to:
|
||||
|
||||
- Run OpenCode on a shared, always-on, or remote host, then connect clients with
|
||||
`opencode2 --server <url>`.
|
||||
`opencode --server <url>`.
|
||||
- Control the hostname, port, and CORS origins for a single process.
|
||||
- Run under a supervisor like systemd, Docker, or another environment that expects
|
||||
a foreground process.
|
||||
@@ -70,5 +70,5 @@ Use it when you want to:
|
||||
Connect a client to it with `--server`:
|
||||
|
||||
```bash
|
||||
$ opencode2 --server http://127.0.0.1:4096
|
||||
$ opencode --server http://127.0.0.1:4096
|
||||
```
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
title: "Intro"
|
||||
---
|
||||
|
||||
These docs describe OpenCode 2 and its released APIs, configuration, and plugin system.
|
||||
These docs describe OpenCode and its APIs, configuration, and plugin system.
|
||||
|
||||
OpenCode 2 installs and runs as `opencode2`. It does not replace OpenCode 1's `opencode` binary, so you can keep both
|
||||
versions installed and run them side by side.
|
||||
OpenCode installs and runs as `opencode`.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -20,13 +19,13 @@ $ curl -fsSL https://opencode.ai/v2/install | bash`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
The npm package uses a trusted postinstall script to select the native `opencode2` binary for your platform. The Bun and pnpm
|
||||
The npm package uses a trusted postinstall script to select the native `opencode` binary for your platform. The Bun and pnpm
|
||||
commands above explicitly allow that script to run.
|
||||
|
||||
On Arch Linux, install [`opencode-beta`](https://aur.archlinux.org/packages/opencode-beta) from the AUR with `paru`.
|
||||
It provides the `opencode2` command; manage updates through your AUR helper.
|
||||
It provides the `opencode` command; manage updates through your AUR helper.
|
||||
|
||||
Homebrew, Windows package managers, Docker, and standalone binaries are not supported in V2.
|
||||
Homebrew, Windows package managers, Docker, and standalone binaries are not supported.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ OpenCode connects to [Model Context Protocol](https://modelcontextprotocol.io/)
|
||||
Add a remote server from the project that should use it, then check its connection:
|
||||
|
||||
```sh
|
||||
opencode2 mcp add context7 --url https://mcp.context7.com/mcp
|
||||
opencode2 mcp list
|
||||
opencode mcp add context7 --url https://mcp.context7.com/mcp
|
||||
opencode mcp list
|
||||
```
|
||||
|
||||
The command writes the server to the project [configuration](/config). Add `--global` to make it available in every project:
|
||||
|
||||
```sh
|
||||
opencode2 mcp add context7 --global --url https://mcp.context7.com/mcp
|
||||
opencode mcp add context7 --global --url https://mcp.context7.com/mcp
|
||||
```
|
||||
|
||||
Remote servers use OAuth by default. If the list shows `needs authentication`, open OpenCode, run `/mcps`, select the server, and sign in. A connected server is ready for an agent to use:
|
||||
@@ -79,7 +79,7 @@ A higher-precedence project config replaces the entire server object with the sa
|
||||
A local server is a command that OpenCode starts over the MCP stdio transport. Add one with a command after `--`:
|
||||
|
||||
```sh
|
||||
opencode2 mcp add everything -- npx -y @modelcontextprotocol/server-everything
|
||||
opencode mcp add everything -- npx -y @modelcontextprotocol/server-everything
|
||||
```
|
||||
|
||||
Use configuration for process options such as a working directory or environment variables:
|
||||
@@ -128,7 +128,7 @@ Use `{env:NAME}` for environment substitution. Shell expressions such as `$NAME`
|
||||
A remote server uses the MCP Streamable HTTP transport and requires an absolute URL:
|
||||
|
||||
```sh
|
||||
opencode2 mcp add context7 --url https://mcp.context7.com/mcp
|
||||
opencode mcp add context7 --url https://mcp.context7.com/mcp
|
||||
```
|
||||
|
||||
Use configuration when the server needs headers or other options. Store secrets in environment variables rather than in the file:
|
||||
@@ -195,7 +195,7 @@ For dynamic registration, configure only the server URL:
|
||||
If the server needs authentication, run `/mcps`, select it, and complete authorization in the browser. The CLI can start the same flow:
|
||||
|
||||
```sh
|
||||
opencode2 mcp auth sentry
|
||||
opencode mcp auth sentry
|
||||
```
|
||||
|
||||
When a provider gives you client credentials, use V2's snake_case OAuth fields:
|
||||
@@ -232,7 +232,7 @@ When a provider gives you client credentials, use V2's snake_case OAuth fields:
|
||||
Remove stored OAuth credentials when you need to sign in again or switch accounts:
|
||||
|
||||
```sh
|
||||
opencode2 mcp logout sentry
|
||||
opencode mcp logout sentry
|
||||
```
|
||||
|
||||
## Timeouts
|
||||
@@ -350,15 +350,15 @@ The ID is request metadata, not a tool argument, so it is absent from the model-
|
||||
List servers and their current connection state from any project:
|
||||
|
||||
```sh
|
||||
opencode2 mcp list
|
||||
opencode mcp list
|
||||
```
|
||||
|
||||
Use `/mcps` in OpenCode to view, connect, disconnect, or authenticate servers. Use the CLI to add servers and manage OAuth credentials:
|
||||
|
||||
```sh
|
||||
opencode2 mcp add sentry --url https://mcp.sentry.dev/mcp
|
||||
opencode2 mcp auth sentry
|
||||
opencode2 mcp logout sentry
|
||||
opencode mcp add sentry --url https://mcp.sentry.dev/mcp
|
||||
opencode mcp auth sentry
|
||||
opencode mcp logout sentry
|
||||
```
|
||||
|
||||
To remove a server, delete its entry from the project or global configuration where it was added:
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
title: "Migrate from V1"
|
||||
---
|
||||
|
||||
OpenCode 1 and OpenCode 2 can be installed side by side. V1 runs as `opencode`, while V2 installs and runs separately as
|
||||
`opencode2`.
|
||||
OpenCode 1 and OpenCode 2 both use the `opencode` command and are no longer installed side by side by default. Remove a
|
||||
package-managed V1 installation before installing V2; the V2 curl installer replaces the V1 binary.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
@@ -399,7 +399,10 @@ See [Models](/models) for the complete native model shape.
|
||||
### Supported fields without direct native equivalents
|
||||
|
||||
Most fields that keep the same shape, including `shell`, `model`, `default_agent`, `watcher`, `formatter`,
|
||||
`lsp`, `instructions`, `enterprise`, and `tool_output`, require no migration.
|
||||
`instructions`, `enterprise`, and `tool_output`, require no migration.
|
||||
|
||||
V2 accepts and preserves `lsp` configuration, but it does not run language servers, expose LSP tools, or produce LSP
|
||||
diagnostics. Replace workflows that depend on those capabilities with the project's lint, typecheck, or compiler commands.
|
||||
|
||||
The V1 provider filters do not have one-to-one native V2 config fields, but their behavior remains supported:
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Availability is project-specific:
|
||||
Use `--model` to choose a model for one command-line run without changing the configured default:
|
||||
|
||||
```bash
|
||||
opencode2 run --model anthropic/claude-sonnet-4-5 "Refactor parseToken"
|
||||
opencode run --model anthropic/claude-sonnet-4-5 "Refactor parseToken"
|
||||
```
|
||||
|
||||
Agents and commands can also choose their own model. See [Agents](/agents) and [Commands](/commands).
|
||||
@@ -63,7 +63,7 @@ Variants are named options for one model, often used for reasoning effort or tok
|
||||
one for a run, session, agent, or command:
|
||||
|
||||
```bash
|
||||
opencode2 run --model openai/gpt-5.2#high "Review this migration plan"
|
||||
opencode run --model openai/gpt-5.2#high "Review this migration plan"
|
||||
```
|
||||
|
||||
Variant names come from the selected model's current catalog metadata. Names such as `low`, `high`, and `max` are not
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: Network
|
||||
description: Configure proxies and custom certificate authorities.
|
||||
---
|
||||
|
||||
Set the standard proxy variables and exclude loopback addresses. OpenCode uses local HTTP connections between the CLI and
|
||||
its background service, so the loopback exclusion is required when a proxy is configured in the CLI environment.
|
||||
|
||||
```bash
|
||||
export HTTP_PROXY=http://proxy.example.com:8080
|
||||
export HTTPS_PROXY=http://proxy.example.com:8080
|
||||
export NO_PROXY=localhost,127.0.0.1,::1
|
||||
|
||||
opencode
|
||||
```
|
||||
|
||||
`HTTP_PROXY` handles HTTP destinations and `HTTPS_PROXY` handles HTTPS destinations. The proxy URL itself can use `http://`
|
||||
for both variables. `NO_PROXY` is a comma-separated list of hosts and addresses that connect directly.
|
||||
|
||||
## Service
|
||||
|
||||
Shell exports affect a background service only when that service starts from the shell. Persist the variables in the managed
|
||||
service configuration so later service starts use the same network settings.
|
||||
|
||||
```bash
|
||||
opencode service set env HTTP_PROXY http://proxy.example.com:8080
|
||||
opencode service set env HTTPS_PROXY http://proxy.example.com:8080
|
||||
opencode service set env NO_PROXY localhost,127.0.0.1,::1
|
||||
opencode service start
|
||||
```
|
||||
|
||||
Changing a managed environment variable stops the running service. `service start` starts it again with the new environment.
|
||||
Keep `NO_PROXY` in the CLI shell too when that shell sets a proxy, because managed service variables apply to the server
|
||||
process, not the CLI process.
|
||||
|
||||
Remove a persisted variable with `service unset env`:
|
||||
|
||||
```bash
|
||||
opencode service unset env HTTPS_PROXY
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
For a proxy that accepts URL credentials, include the username and password in each proxy URL that needs authentication.
|
||||
Percent-encode characters such as `@`, `:`, and `/` inside either credential.
|
||||
|
||||
```bash
|
||||
export HTTPS_PROXY='http://user:p%40ssword@proxy.example.com:8080'
|
||||
```
|
||||
|
||||
For the background service, persist the complete URL. The value is stored in the private service configuration and is
|
||||
shown by `opencode service get env`, so do not share that output.
|
||||
|
||||
```bash
|
||||
opencode service set env HTTPS_PROXY 'http://user:p%40ssword@proxy.example.com:8080'
|
||||
```
|
||||
|
||||
## Certificates
|
||||
|
||||
Set `NODE_EXTRA_CA_CERTS` to a PEM file when the proxy or destination uses a certificate signed by a private certificate
|
||||
authority. The extra authorities are added to the runtime trust store when the process starts.
|
||||
|
||||
```bash
|
||||
export NODE_EXTRA_CA_CERTS=/etc/company/ca.pem
|
||||
opencode --standalone
|
||||
```
|
||||
|
||||
Persist the file path for the background service, then restart it:
|
||||
|
||||
```bash
|
||||
opencode service set env NODE_EXTRA_CA_CERTS /etc/company/ca.pem
|
||||
opencode service start
|
||||
```
|
||||
|
||||
## Foreground
|
||||
|
||||
`--standalone` and `serve` use the environment of their own process. `opencode service set env` does not configure these
|
||||
processes.
|
||||
|
||||
```bash
|
||||
HTTP_PROXY=http://proxy.example.com:8080 \
|
||||
HTTPS_PROXY=http://proxy.example.com:8080 \
|
||||
NO_PROXY=localhost,127.0.0.1,::1 \
|
||||
opencode --standalone
|
||||
```
|
||||
|
||||
Apply the same pattern to a foreground server:
|
||||
|
||||
```bash
|
||||
HTTPS_PROXY=http://proxy.example.com:8080 \
|
||||
NO_PROXY=localhost,127.0.0.1,::1 \
|
||||
opencode serve
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
Check that the CLI can reach the background service after applying the settings:
|
||||
|
||||
```bash
|
||||
opencode api get /api/health
|
||||
```
|
||||
|
||||
A successful health response verifies the local client-to-service connection. Run a normal provider request to verify the
|
||||
service's outbound proxy and certificate path.
|
||||
@@ -81,13 +81,13 @@ use `.*` to match an ID prefix. A later ID re-enables a plugin.
|
||||
Install, list, check, update, or remove global package plugins with the CLI.
|
||||
|
||||
```sh
|
||||
opencode2 plugin add opencode-acme-plugin@1.2.0
|
||||
opencode2 plugin list
|
||||
opencode2 plugin list --builtin
|
||||
opencode2 plugin check
|
||||
opencode2 plugin update
|
||||
opencode2 plugin update opencode-acme-plugin
|
||||
opencode2 plugin remove opencode-acme-plugin@1.2.0
|
||||
opencode plugin add opencode-acme-plugin@1.2.0
|
||||
opencode plugin list
|
||||
opencode plugin list --builtin
|
||||
opencode plugin check
|
||||
opencode plugin update
|
||||
opencode plugin update opencode-acme-plugin
|
||||
opencode plugin remove opencode-acme-plugin@1.2.0
|
||||
```
|
||||
|
||||
`plugin check` checks server and TUI-only package plugins for updates. `plugin update` updates every outdated package;
|
||||
@@ -98,10 +98,10 @@ Git repositories can use hosted shortcuts, HTTPS, or SSH, including private repo
|
||||
Git credentials.
|
||||
|
||||
```sh
|
||||
opencode2 plugin add @acme/opencode-plugin@latest
|
||||
opencode2 plugin add github:acme/opencode-plugin
|
||||
opencode2 plugin add git+ssh://git@github.com/acme/opencode-plugin.git#main
|
||||
opencode2 plugin add 'github:acme/plugins#main::path:packages/opencode-plugin'
|
||||
opencode plugin add @acme/opencode-plugin@latest
|
||||
opencode plugin add github:acme/opencode-plugin
|
||||
opencode plugin add git+ssh://git@github.com/acme/opencode-plugin.git#main
|
||||
opencode plugin add 'github:acme/plugins#main::path:packages/opencode-plugin'
|
||||
```
|
||||
|
||||
Branches, tags, complete commit hashes, and npm's `::path:` repository-subdirectory selectors are supported. Configure
|
||||
@@ -116,7 +116,7 @@ still require restarting OpenCode.
|
||||
|
||||
```sh
|
||||
touch .opencode/plugins/concise/index.ts
|
||||
opencode2 service restart
|
||||
opencode service restart
|
||||
```
|
||||
|
||||
## Terminal
|
||||
|
||||
@@ -238,18 +238,21 @@ See [Models](/models) for selection, defaults, capabilities, limits, costs, and
|
||||
|
||||
## Azure
|
||||
|
||||
Azure supports either an API key or the Microsoft Entra ID session from the Azure CLI. To use Entra ID, install the
|
||||
[Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) and sign in before connecting.
|
||||
Azure's standard catalog endpoint needs a resource name in addition to its credential. Set `settings.resourceName`
|
||||
once, then connect an API key or use the Microsoft Entra ID session from the Azure CLI as described in
|
||||
[Provider accounts](/cli/providers).
|
||||
|
||||
```bash
|
||||
az login
|
||||
```
|
||||
|
||||
For a resource in another tenant or subscription, select both explicitly.
|
||||
|
||||
```bash
|
||||
az login --tenant TENANT_ID
|
||||
az account set --subscription NAME_OR_ID
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"azure": {
|
||||
"settings": {
|
||||
"resourceName": "my-models",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Find the **Resource name** in the [Azure portal](https://portal.azure.com/) or
|
||||
@@ -262,14 +265,23 @@ az cognitiveservices account list \
|
||||
--output table
|
||||
```
|
||||
|
||||
In OpenCode, select **Azure**, then **Microsoft Entra ID (Azure CLI)**. Enter the resource name when prompted;
|
||||
`AZURE_RESOURCE_NAME` skips that prompt when already set.
|
||||
To use Entra ID, install the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli), sign in, then
|
||||
choose **Microsoft Entra ID (Azure CLI)** when connecting Azure.
|
||||
|
||||
```text
|
||||
/connect
|
||||
/models
|
||||
```bash
|
||||
az login
|
||||
```
|
||||
|
||||
For a resource in another tenant or subscription, select both explicitly.
|
||||
|
||||
```bash
|
||||
az login --tenant TENANT_ID
|
||||
az account set --subscription NAME_OR_ID
|
||||
```
|
||||
|
||||
Instead of configuration, `AZURE_RESOURCE_NAME` supplies the resource name to the OpenCode server. The legacy
|
||||
`AZURE_COGNITIVE_SERVICES_RESOURCE_NAME` variable also works.
|
||||
|
||||
OpenCode does not query Azure management APIs or discover deployments. If a deployment does not match its catalog
|
||||
model name, map an OpenCode model ID to the deployment with `modelID`.
|
||||
|
||||
@@ -299,6 +311,245 @@ If a request uses a token from the wrong tenant, sign in again with the required
|
||||
az login --tenant TENANT_ID
|
||||
```
|
||||
|
||||
## Bedrock
|
||||
|
||||
Amazon Bedrock uses the AWS default credential chain. A named AWS profile is the simplest durable setup; OpenCode also
|
||||
recognizes access-key environments, web identity, and container credentials.
|
||||
|
||||
```bash
|
||||
aws configure sso --profile work
|
||||
aws sso login --profile work
|
||||
```
|
||||
|
||||
Select the profile and region in provider settings. A configured `profile`, `AWS_PROFILE`, `AWS_ACCESS_KEY_ID`, web
|
||||
identity token file, or container credential URI activates the provider; a region alone does not.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"amazon-bedrock": {
|
||||
"settings": {
|
||||
"profile": "work",
|
||||
"region": "us-west-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Without an explicit region, OpenCode uses `AWS_REGION`, then `AWS_DEFAULT_REGION`, then `us-east-1`. For a private or
|
||||
VPC endpoint, set `baseURL` while keeping the same profile and region.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"amazon-bedrock": {
|
||||
"settings": {
|
||||
"profile": "work",
|
||||
"region": "us-west-2",
|
||||
"baseURL": "https://bedrock-runtime.vpce.example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Bedrock API keys use `AWS_BEARER_TOKEN_BEDROCK`. Other AWS variables feed SigV4 and are not stored as OpenCode API-key
|
||||
accounts.
|
||||
|
||||
## Vertex
|
||||
|
||||
Google Vertex uses Application Default Credentials (ADC) and needs a project before its models become available.
|
||||
Create local ADC, then set the project and location in provider settings.
|
||||
|
||||
```bash
|
||||
gcloud auth application-default login
|
||||
```
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"google-vertex": {
|
||||
"settings": {
|
||||
"project": "my-project",
|
||||
"location": "us-central1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
OpenCode also resolves the project from `GOOGLE_VERTEX_PROJECT`, `GOOGLE_CLOUD_PROJECT`, `GCP_PROJECT`, or
|
||||
`GCLOUD_PROJECT`, in that order. It resolves the location from `GOOGLE_VERTEX_LOCATION`, `GOOGLE_CLOUD_LOCATION`, or
|
||||
`VERTEX_LOCATION`, and defaults to `us-central1`.
|
||||
|
||||
```bash
|
||||
GOOGLE_CLOUD_PROJECT=my-project GOOGLE_VERTEX_LOCATION=europe-west4 opencode --standalone
|
||||
```
|
||||
|
||||
Service accounts work through the same ADC path. Point `GOOGLE_APPLICATION_CREDENTIALS` at the service-account JSON
|
||||
file and still provide a project through settings or one of the project variables above.
|
||||
|
||||
```bash
|
||||
GOOGLE_APPLICATION_CREDENTIALS=/secure/vertex.json \
|
||||
GOOGLE_CLOUD_PROJECT=my-project \
|
||||
opencode --standalone
|
||||
```
|
||||
|
||||
Use the single `google-vertex` provider ID for Gemini, Anthropic, and OpenAI-compatible Vertex catalog models. The old
|
||||
`google-vertex-anthropic` provider ID is unavailable in V2.
|
||||
|
||||
## Copilot
|
||||
|
||||
GitHub Copilot supports device OAuth rather than manual API-key entry. Connect **GitHub Copilot**, choose GitHub.com or
|
||||
GitHub Enterprise, finish the device flow, then open `/models`.
|
||||
|
||||
```text
|
||||
/connect
|
||||
# Select GitHub Copilot, then Login with GitHub Copilot.
|
||||
/models
|
||||
```
|
||||
|
||||
For GitHub Enterprise, enter the deployment URL or domain when prompted. OpenCode uses a Copilot API endpoint returned
|
||||
by GitHub when available; otherwise it derives the endpoint from the enterprise domain.
|
||||
|
||||
```text
|
||||
company.ghe.com
|
||||
```
|
||||
|
||||
The connected account needs Copilot Chat access. If GitHub reports no entitlement, sign up for Copilot Free or ask the
|
||||
organization to assign a Copilot seat, then connect again. OpenCode fetches the account's current model list after login
|
||||
and whenever the active Copilot account changes.
|
||||
|
||||
## Ollama
|
||||
|
||||
Start Ollama and pull a model. OpenCode probes `http://127.0.0.1:11434`, discovers completion models, and adds them to
|
||||
`/models` without an account connection.
|
||||
|
||||
```bash
|
||||
ollama serve
|
||||
ollama pull qwen3:8b
|
||||
```
|
||||
|
||||
Point OpenCode at a remote or proxied Ollama server with `settings.baseURL`. Include `/v1`; OpenCode derives the native
|
||||
`/api/tags` and `/api/show` discovery paths from it. `apiKey` is optional and is sent as a bearer token to discovery and
|
||||
model requests.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"ollama": {
|
||||
"settings": {
|
||||
"baseURL": "https://ollama.example.com/v1",
|
||||
"apiKey": "{env:OLLAMA_API_KEY}",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Discovery refreshes periodically and keeps the last successful inventory during a temporary outage. Embedding-only
|
||||
models do not appear because OpenCode only adds models whose Ollama metadata includes the `completion` capability.
|
||||
|
||||
## Runtimes
|
||||
|
||||
LM Studio and vLLM also have built-in local discovery. Their default endpoints are
|
||||
`http://127.0.0.1:1234/v1` and `http://127.0.0.1:8000/v1`.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"lmstudio": {
|
||||
"settings": { "baseURL": "http://gpu-host:1234/v1" },
|
||||
},
|
||||
"vllm": {
|
||||
"settings": { "baseURL": "http://gpu-host:8000/v1" },
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
LM Studio discovers language models from `/api/v1/models`. vLLM checks `/health` before reading `/v1/models`; its
|
||||
discovery cannot infer tool support, so discovered vLLM models start with tools disabled. For another OpenAI-compatible
|
||||
runtime, use the [custom provider](#custom) recipe and list its models explicitly.
|
||||
|
||||
## Gateways
|
||||
|
||||
OpenRouter uses its native runtime and catalog. Provide `OPENROUTER_API_KEY` to the OpenCode server or connect an
|
||||
OpenRouter account, then refer to models with the full OpenRouter model ID after the provider prefix.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "openrouter/anthropic/claude-sonnet-4",
|
||||
}
|
||||
```
|
||||
|
||||
Keep the native OpenRouter package when overriding its endpoint or routing through an OpenRouter-compatible gateway.
|
||||
This preserves OpenRouter request and reasoning behavior.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"providers": {
|
||||
"openrouter": {
|
||||
"settings": {
|
||||
"baseURL": "https://openrouter-gateway.example.com/api/v1",
|
||||
},
|
||||
"headers": {
|
||||
"X-Gateway-Tenant": "engineering",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
For a gateway that exposes an OpenAI-compatible API but has its own model inventory, define a custom provider instead.
|
||||
The configuration key becomes the provider prefix and each `models` key becomes a selectable model ID.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "company/coder",
|
||||
"providers": {
|
||||
"company": {
|
||||
"env": ["COMPANY_GATEWAY_KEY"],
|
||||
"package": "@opencode/ai/providers/openai-compatible",
|
||||
"settings": {
|
||||
"baseURL": "https://gateway.example.com/v1",
|
||||
},
|
||||
"models": {
|
||||
"coder": { "modelID": "upstream/coder-v2" },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Errors
|
||||
|
||||
Provider and model errors usually identify the failed stage. Check the server process environment and the exact model
|
||||
ID before changing packages.
|
||||
|
||||
| Error or symptom | Check |
|
||||
| --- | --- |
|
||||
| `No model is available for session ...` | No enabled model is currently selectable. Finish the provider-specific setup, then choose a model in `/models`. |
|
||||
| `Model unavailable: provider/model` | The provider is inactive, the model ID is absent or disabled, or dynamic discovery no longer returns it. For custom aliases, check the `models` map key rather than `modelID`. |
|
||||
| `Cannot initialize provider/model: NAME is required to resolve the provider endpoint` | A `${NAME}` placeholder remains in `baseURL`. Set that variable on the OpenCode server or replace the template with a complete endpoint. |
|
||||
| `Azure resource name is missing` | Set `providers.azure.settings.resourceName`, `AZURE_RESOURCE_NAME`, or a complete `settings.baseURL`. |
|
||||
| Vertex does not appear | Set a resolvable project in provider settings or a supported project variable. ADC alone does not activate the provider. |
|
||||
| Bedrock does not appear | Provide a profile or another supported AWS credential-chain input. `AWS_REGION` by itself only selects a region. |
|
||||
| Ollama has no models | Confirm the server exposes `/api/tags` and `/api/show` at the path derived from `baseURL`, and that `/api/show` reports the `completion` capability. |
|
||||
| Copilot has no models | Confirm the active OAuth account has Copilot Chat access. A failed model sync is logged as `failed to sync GitHub Copilot models`. |
|
||||
|
||||
V2 rejects the retired provider IDs with a direct replacement. Use `azure/<model>` instead of
|
||||
`azure-cognitive-services/<model>`, and `google-vertex/<model>` instead of `google-vertex-anthropic/<model>`.
|
||||
|
||||
## WebSockets
|
||||
|
||||
OpenAI, xAI, and supported Azure Responses models can keep one WebSocket connection open per session. Consecutive steps
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
---
|
||||
title: "Tools"
|
||||
---
|
||||
|
||||
Ask for the outcome you want. OpenCode chooses the available tools, requests
|
||||
approval when required, and returns the result.
|
||||
|
||||
```text
|
||||
Find where request timeouts are configured, change the default to 30 seconds,
|
||||
and run the relevant existing tests.
|
||||
```
|
||||
|
||||
This task typically uses `grep` or `glob`, `read`, an editing tool, and `shell`.
|
||||
You can also name a tool when you want a specific approach.
|
||||
|
||||
```text
|
||||
Use grep to find every reference to DEFAULT_TIMEOUT, then read the matching files.
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
### Read
|
||||
|
||||
`read` returns a file or a non-recursive directory listing. Give it a `path`;
|
||||
use `offset` and `limit` to page through large results.
|
||||
|
||||
```text
|
||||
Read src/server.ts starting at line 120 and return at most 80 lines.
|
||||
```
|
||||
|
||||
Text reads contain numbered lines and are limited to 2,000 lines and 50 KiB per
|
||||
page. Individual lines are shortened after 2,000 characters. The tool also
|
||||
passes PNG, JPEG, GIF, WebP, and PDF files to the model, up to 20 MiB of source
|
||||
data. Other binary files fail. See [Attachments](/attachments) for supported
|
||||
media and image processing.
|
||||
|
||||
Permission: `read` with the normalized path as its resource.
|
||||
|
||||
### Glob
|
||||
|
||||
`glob` finds file paths from a pattern such as `**/*.ts`. It searches the
|
||||
current directory unless `path` selects another relative directory; `hidden`
|
||||
includes hidden entries and `limit` caps the results.
|
||||
|
||||
```text
|
||||
Use glob with **/*.test.ts under packages/core and return at most 50 files.
|
||||
```
|
||||
|
||||
The default limit is 100 files and the search timeout is 30 seconds.
|
||||
Permission: `glob` with the requested pattern as its resource.
|
||||
|
||||
### Grep
|
||||
|
||||
`grep` searches file contents and returns paths, line numbers, and previews.
|
||||
Its `pattern` uses regular-expression syntax unless `literal` is true. Narrow a
|
||||
search with `path`, `include`, `caseSensitive`, or `limit`.
|
||||
|
||||
```text
|
||||
Use grep for the literal text "request timed out" in src, including only *.ts files.
|
||||
```
|
||||
|
||||
The default limit is 100 matching lines and the search timeout is 30 seconds.
|
||||
Permission: `grep` with the requested pattern, not the search path, as its
|
||||
resource.
|
||||
|
||||
### Edit
|
||||
|
||||
`edit` replaces text in an existing file. Supply `path`, `oldString`, and a
|
||||
different `newString`; the old text must match exactly once unless `replaceAll`
|
||||
is true.
|
||||
|
||||
```text
|
||||
In src/config.ts, replace the unique text "timeout: 60" with "timeout: 30".
|
||||
```
|
||||
|
||||
Use `edit` for a focused change. OpenCode may format the file after writing it.
|
||||
Permission: `edit` with the target path as its resource.
|
||||
|
||||
### Write
|
||||
|
||||
`write` creates or completely replaces a text file from `path` and `content`.
|
||||
It creates missing parent directories and may run the configured formatter.
|
||||
|
||||
```text
|
||||
Create docs/example.md with a heading and one setup command.
|
||||
```
|
||||
|
||||
Use `edit` instead when only part of an existing file should change.
|
||||
Permission: `edit` with the target path as its resource.
|
||||
|
||||
### Patch
|
||||
|
||||
`patch` applies one patch that can add, update, move, or delete several files.
|
||||
Its `patchText` uses `*** Add File`, `*** Update File`, and `*** Delete File`
|
||||
sections.
|
||||
|
||||
```text
|
||||
Use patch to rename src/old.ts to src/new.ts and update its exported name.
|
||||
```
|
||||
|
||||
OpenCode exposes `patch` for supported GPT models; other models receive `edit`
|
||||
and `write` instead. Permission: `edit` with every affected path as a resource.
|
||||
|
||||
Paths outside the active Location or its project worktree also require
|
||||
`external_directory` approval. See [Permissions](/permissions) for path
|
||||
normalization, rule order, and saved approvals. To make outside material
|
||||
available by name, configure [References](/references).
|
||||
|
||||
## Commands
|
||||
|
||||
### Shell
|
||||
|
||||
`shell` executes a command in the host user's shell. Set `workdir` instead of
|
||||
putting `cd` in the command, and set `timeout` in milliseconds when the default
|
||||
two-minute foreground timeout is not suitable.
|
||||
|
||||
```text
|
||||
Run bun test from packages/core with a five-minute timeout.
|
||||
```
|
||||
|
||||
Set `background` to true for a dev server or another long-running process.
|
||||
Background calls return immediately and notify the session when they finish;
|
||||
they have no timeout unless one is supplied. Large output is shortened and the
|
||||
complete output is retained in a managed file.
|
||||
|
||||
Permission: `shell` with each scanner-produced command as a resource. The
|
||||
scanner also checks an external working directory and directories it can infer
|
||||
from the command. Shell has the host user's filesystem, process, and network
|
||||
authority, so use narrow rules in [Permissions](/permissions).
|
||||
|
||||
## Web
|
||||
|
||||
### Webfetch
|
||||
|
||||
`webfetch` retrieves one HTTP or HTTPS URL as `markdown`, `text`, or `html`.
|
||||
Markdown is the default; `timeout` accepts up to 120 seconds.
|
||||
|
||||
```text
|
||||
Fetch https://example.com/docs as markdown.
|
||||
```
|
||||
|
||||
It accepts textual responses such as HTML, plain text, JSON, and XML, but not
|
||||
images or other binary downloads. Large output can be shortened while the full
|
||||
text is retained in managed storage. Permission: `webfetch` with the requested
|
||||
URL as its resource.
|
||||
|
||||
### Websearch
|
||||
|
||||
`websearch` searches the selected integration for current information. Its
|
||||
input is a search `query`.
|
||||
|
||||
```text
|
||||
Search the web for the latest Bun release notes.
|
||||
```
|
||||
|
||||
Permission: `websearch` with the query as its resource. See [Websearch](/websearch)
|
||||
for providers, selection, rate limits, and disabling the tool.
|
||||
|
||||
## Interaction
|
||||
|
||||
### Question
|
||||
|
||||
`question` pauses execution and presents one or more questions to the user.
|
||||
Each question has a short header, prompt, and choices; `multiple` allows more
|
||||
than one choice. A free-form answer is always available.
|
||||
|
||||
```text
|
||||
Before changing the API, ask me to choose between a breaking change and a compatibility layer.
|
||||
```
|
||||
|
||||
Permission: `question` with `*` as its resource. A client must support the
|
||||
interactive form, and dismissing it cancels the question.
|
||||
|
||||
### Skill
|
||||
|
||||
`skill` loads the instructions and bundled resources for one available skill
|
||||
ID into the conversation.
|
||||
|
||||
```text
|
||||
Load the effect skill before changing this Effect code.
|
||||
```
|
||||
|
||||
The ID must be in the advertised skill list or explicitly named by the user.
|
||||
Permission: `skill` with the skill ID as its resource. See [Skills](/skills) for
|
||||
creation, discovery, and loading rules.
|
||||
|
||||
## Automation
|
||||
|
||||
### Subagent
|
||||
|
||||
`subagent` starts a child session with a configured subagent. Supply the agent
|
||||
ID, a short `description`, and a complete `prompt`.
|
||||
|
||||
```text
|
||||
Ask the explore subagent to map the authentication flow and return the key files.
|
||||
```
|
||||
|
||||
Foreground calls wait for the result. `background: true` returns immediately
|
||||
and notifies the parent when the child finishes. Pass the returned `sessionID`
|
||||
to continue that same child conversation. Only subagent-mode agents can be
|
||||
used, and the default nesting depth is one.
|
||||
|
||||
Permission: `subagent` with the selected agent ID as its resource.
|
||||
|
||||
### Execute
|
||||
|
||||
`execute` runs JavaScript in Code Mode so the agent can call and combine tools
|
||||
from the catalog. It is useful for parallel independent calls and for processing
|
||||
results without adding every intermediate value to the model context.
|
||||
|
||||
```text
|
||||
Read package.json and README.md in parallel, then return their relevant setup details.
|
||||
```
|
||||
|
||||
The runtime has no direct filesystem access, imports, timers, or `fetch`; it can
|
||||
only call tools in its catalog. Permission `execute` with resource `*` controls
|
||||
whether Code Mode is available. Every nested tool still enforces its own
|
||||
permission.
|
||||
|
||||
### Sessions
|
||||
|
||||
The `opencode` Code Mode namespace contains session utilities:
|
||||
|
||||
- `session_rename` changes the title of the current session, or another session
|
||||
selected by `sessionID`.
|
||||
- `session_move` moves the current session, or another selected session, to a
|
||||
relative or absolute `directory`. The move takes effect at a safe boundary,
|
||||
so destination-dependent work belongs in a later call.
|
||||
|
||||
```text
|
||||
Rename this session to "Timeout cleanup", then move it to the new worktree.
|
||||
```
|
||||
|
||||
These utilities do not request a built-in permission action.
|
||||
|
||||
## Browser
|
||||
|
||||
The `browser` Code Mode namespace controls the browser attached by the OpenCode
|
||||
desktop app. Open a tab, keep its returned `tabID`, then pass that explicit ID to
|
||||
every page operation.
|
||||
|
||||
```text
|
||||
Open https://example.com, take a snapshot of that tab, and report the main heading.
|
||||
```
|
||||
|
||||
The namespace includes tab and navigation commands, page snapshots and search,
|
||||
clicking and form input, screenshots, file transfer, console and network
|
||||
inspection, performance traces, heap inspection, and Lighthouse audits.
|
||||
Screenshots require a focused visible tab. Upload paths are server-local;
|
||||
captures return server-local paths, and each file transfer is limited to 5 MiB.
|
||||
|
||||
Page content, logs, headers, and response bodies are untrusted data, not agent
|
||||
instructions. A `browser` deny rule with resource `*` removes the browser catalog;
|
||||
browser operations do not issue individual permission prompts.
|
||||
|
||||
## Extensions
|
||||
|
||||
[MCP servers](/mcp-servers) add tools whose names and inputs come from each
|
||||
connected server. Their permission action is `<server>_<tool>` with resource
|
||||
`*`. They are not a fixed part of the built-in catalog.
|
||||
|
||||
[Skills](/skills) add task instructions rather than new executable tools.
|
||||
[Attachments](/attachments) put user-selected content into a prompt, while
|
||||
[References](/references) provide named outside directories. These features
|
||||
complement tools without bypassing their permission checks.
|
||||
@@ -15,26 +15,26 @@ state. Start by determining whether an issue is in a client, the shared server,
|
||||
Show the current server status:
|
||||
|
||||
```bash
|
||||
opencode2 service status
|
||||
opencode service status
|
||||
```
|
||||
|
||||
Verify that its API is healthy:
|
||||
|
||||
```bash
|
||||
opencode2 api get /api/health
|
||||
opencode api get /api/health
|
||||
```
|
||||
|
||||
If the service is stuck or unhealthy, restart it:
|
||||
|
||||
```bash
|
||||
opencode2 service restart
|
||||
opencode service restart
|
||||
```
|
||||
|
||||
You can also stop and start it explicitly:
|
||||
|
||||
```bash
|
||||
opencode2 service stop
|
||||
opencode2 service start
|
||||
opencode service stop
|
||||
opencode service start
|
||||
```
|
||||
|
||||
<Callout type="note">
|
||||
@@ -47,30 +47,30 @@ opencode2 service start
|
||||
If a browser client on another origin cannot connect because of CORS, add the client's origin to the service configuration:
|
||||
|
||||
```bash
|
||||
opencode2 service set cors http://192.168.1.10:3001
|
||||
opencode2 service get cors
|
||||
opencode service set cors http://192.168.1.10:3001
|
||||
opencode service get cors
|
||||
```
|
||||
|
||||
Use an exact HTTP or HTTPS origin, including the port when needed, without a path or trailing slash. To allow multiple
|
||||
origins, pass a comma-separated list as one argument; whitespace around each origin is trimmed:
|
||||
|
||||
```bash
|
||||
opencode2 service set cors "http://192.168.1.10:3001, https://app.example.com"
|
||||
opencode service set cors "http://192.168.1.10:3001, https://app.example.com"
|
||||
```
|
||||
|
||||
`service get cors` prints a JSON array. Remove the configured list with:
|
||||
|
||||
```bash
|
||||
opencode2 service unset cors
|
||||
opencode service unset cors
|
||||
```
|
||||
|
||||
Setting or unsetting service configuration stops the background service. Its next start picks up the new configuration;
|
||||
use `opencode2 service start` to start it explicitly.
|
||||
use `opencode service start` to start it explicitly.
|
||||
|
||||
For a foreground server, repeat `--cors` for each additional allowed origin:
|
||||
|
||||
```bash
|
||||
opencode2 serve --cors http://192.168.1.10:3001 --cors https://app.example.com
|
||||
opencode serve --cors http://192.168.1.10:3001 --cors https://app.example.com
|
||||
```
|
||||
|
||||
With `serve --service`, supplied `--cors` flags override the persisted list for that process. Without those flags, service
|
||||
@@ -86,7 +86,7 @@ See the [API reference](/api) for all endpoints and operation IDs.
|
||||
Pass a JSON request body with `--data` or `-d`, and add headers with `--header` or `-H`.
|
||||
|
||||
<Callout type="warning">
|
||||
Running `opencode2 api` may start the background service when no compatible healthy service is available.
|
||||
Running `opencode api` may start the background service when no compatible healthy service is available.
|
||||
</Callout>
|
||||
|
||||
## Read logs
|
||||
@@ -117,7 +117,7 @@ On macOS and Linux, you can signal a running OpenCode process to capture diagnos
|
||||
from the health endpoint:
|
||||
|
||||
```bash
|
||||
opencode2 api get /api/health
|
||||
opencode api get /api/health
|
||||
```
|
||||
|
||||
Use the `pid` from the response with one of these signals:
|
||||
@@ -177,8 +177,8 @@ The database normally lives at:
|
||||
|
||||
Include the following when reporting a reproducible problem:
|
||||
|
||||
- Output from `opencode2 --version`
|
||||
- Output from `opencode2 service status`
|
||||
- Output from `opencode --version`
|
||||
- Output from `opencode service status`
|
||||
- The smallest sequence of steps that reproduces the issue
|
||||
- Whether the issue affects the shared service, a specific client, or one project
|
||||
- Relevant log lines, including their `run` and `role` fields
|
||||
|
||||
@@ -24,7 +24,7 @@ OpenCode includes four search providers:
|
||||
Connect an account from the TUI with `/connect`, or set the provider's environment variable before starting OpenCode.
|
||||
|
||||
```bash
|
||||
$ TAVILY_API_KEY=your-key opencode2
|
||||
$ TAVILY_API_KEY=your-key opencode
|
||||
```
|
||||
|
||||
## Selection
|
||||
|
||||
@@ -38,11 +38,13 @@ export const docsSections: DocsSection[] = [
|
||||
{ title: "Plugins", slug: "plugins" },
|
||||
{ title: "Providers", slug: "providers" },
|
||||
{ title: "Websearch", slug: "websearch" },
|
||||
{ title: "Network", slug: "network" },
|
||||
{ title: "Snapshots", slug: "snapshots" },
|
||||
{ title: "Compaction", slug: "compaction" },
|
||||
{ title: "Formatters", slug: "formatters" },
|
||||
{ title: "References", slug: "references" },
|
||||
{ title: "Attachments", slug: "attachments" },
|
||||
{ title: "Tools", slug: "tools" },
|
||||
{ title: "MCP servers", slug: "mcp-servers" },
|
||||
{ title: "Permissions", slug: "permissions" },
|
||||
{ title: "Instructions", slug: "instructions" },
|
||||
@@ -66,10 +68,12 @@ export const docsSections: DocsSection[] = [
|
||||
{
|
||||
items: [
|
||||
{ title: "Intro", slug: "cli" },
|
||||
{ title: "TUI", slug: "cli/tui" },
|
||||
{ title: "Config", slug: "cli/config" },
|
||||
{ title: "Web", slug: "cli/web" },
|
||||
{ title: "Providers", slug: "cli/providers" },
|
||||
{ title: "Commands", slug: "cli/commands" },
|
||||
{ title: "ACP", slug: "cli/acp" },
|
||||
{ title: "Theme", slug: "cli/theme" },
|
||||
{ title: "Plugins", slug: "cli/plugins" },
|
||||
{ title: "Keybinds", slug: "cli/keybinds" },
|
||||
|
||||
Reference in New Issue
Block a user