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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/opencode/src/cli/cmd/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/v2"
import { Server } from "../../server/server"
import { Provider } from "../../provider/provider"
import { Agent } from "../../agent/agent"
import { PermissionNext } from "../../permission/next"

const TOOL: Record<string, [string, string]> = {
todowrite: ["Todo", UI.Style.TEXT_WARNING_BOLD],
Expand Down Expand Up @@ -91,8 +92,16 @@ export const RunCommand = cmd({
type: "string",
describe: "model variant (provider-specific reasoning effort, e.g., high, max, minimal)",
})
.option("dangerously-skip-permissions", {
type: "boolean",
describe: "Skip all permission prompts (use with extreme caution)",
})
},
handler: async (args) => {
if (args.dangerouslySkipPermissions || Flag.OPENCODE_DANGEROUSLY_SKIP_PERMISSIONS) {
PermissionNext.setSkipPermissions(true)
}

let message = [...args.message, ...(args["--"] || [])]
.map((arg) => (arg.includes(" ") ? `"${arg.replace(/"/g, '\\"')}"` : arg))
.join(" ")
Expand Down
1 change: 1 addition & 0 deletions packages/opencode/src/cli/cmd/tui/context/args.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface Args {
prompt?: string
continue?: boolean
sessionID?: string
dangerouslySkipPermissions?: boolean
}

export const { use: useArgs, provider: ArgsProvider } = createSimpleContext({
Expand Down
3 changes: 3 additions & 0 deletions packages/opencode/src/cli/cmd/tui/routes/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ export function Home() {
<Tips />
</Show>
</box>
<Show when={args.dangerouslySkipPermissions}>
<text fg={theme.warning}>△ YOLO mode</text>
</Show>
<Toast />
</box>
<box paddingTop={1} paddingBottom={1} paddingLeft={2} paddingRight={2} flexDirection="row" flexShrink={0} gap={2}>
Expand Down
5 changes: 5 additions & 0 deletions packages/opencode/src/cli/cmd/tui/routes/session/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { useDirectory } from "../../context/directory"
import { useConnected } from "../../component/dialog-model"
import { createStore } from "solid-js/store"
import { useRoute } from "../../context/route"
import { useArgs } from "../../context/args"

export function Footer() {
const { theme } = useTheme()
const sync = useSync()
const route = useRoute()
const args = useArgs()
const mcp = createMemo(() => Object.values(sync.data.mcp).filter((x) => x.status === "connected").length)
const mcpError = createMemo(() => Object.values(sync.data.mcp).some((x) => x.status === "failed"))
const lsp = createMemo(() => Object.keys(sync.data.lsp))
Expand Down Expand Up @@ -53,6 +55,9 @@ export function Footer() {
<box flexDirection="row" justifyContent="space-between" gap={1} flexShrink={0}>
<text fg={theme.textMuted}>{directory()}</text>
<box gap={2} flexDirection="row" flexShrink={0}>
<Show when={args.dangerouslySkipPermissions}>
<text fg={theme.warning}>△ YOLO mode</text>
</Show>
<Switch>
<Match when={store.welcome}>
<text fg={theme.text}>
Expand Down
5 changes: 5 additions & 0 deletions packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import { useKeybind } from "../../context/keybind"
import { useDirectory } from "../../context/directory"
import { useKV } from "../../context/kv"
import { TodoItem } from "../../component/todo-item"
import { useArgs } from "../../context/args"

export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
const sync = useSync()
const { theme } = useTheme()
const args = useArgs()
const session = createMemo(() => sync.session.get(props.sessionID)!)
const diff = createMemo(() => sync.data.session_diff[props.sessionID] ?? [])
const todo = createMemo(() => sync.data.todo[props.sessionID] ?? [])
Expand Down Expand Up @@ -312,6 +314,9 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
</span>{" "}
<span>{Installation.VERSION}</span>
</text>
<Show when={args.dangerouslySkipPermissions}>
<text fg={theme.warning}>△ YOLO mode</text>
</Show>
</box>
</box>
</Show>
Expand Down
10 changes: 10 additions & 0 deletions packages/opencode/src/cli/cmd/tui/thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Log } from "@/util/log"
import { withNetworkOptions, resolveNetworkOptions } from "@/cli/network"
import type { Event } from "@opencode-ai/sdk/v2"
import type { EventSource } from "./context/sdk"
import { Flag } from "@/flag/flag"

declare global {
const OPENCODE_WORKER_PATH: string
Expand Down Expand Up @@ -71,8 +72,16 @@ export const TuiThreadCommand = cmd({
.option("agent", {
type: "string",
describe: "agent to use",
})
.option("dangerously-skip-permissions", {
type: "boolean",
describe: "Skip all permission prompts (use with extreme caution)",
}),
handler: async (args) => {
if (args.dangerouslySkipPermissions || Flag.OPENCODE_DANGEROUSLY_SKIP_PERMISSIONS) {
process.env.OPENCODE_DANGEROUSLY_SKIP_PERMISSIONS = "true"
}

// Resolve relative paths against PWD to preserve behavior when using --cwd flag
const baseCwd = process.env.PWD ?? process.cwd()
const cwd = args.project ? path.resolve(baseCwd, args.project) : process.cwd()
Expand Down Expand Up @@ -150,6 +159,7 @@ export const TuiThreadCommand = cmd({
agent: args.agent,
model: args.model,
prompt,
dangerouslySkipPermissions: args.dangerouslySkipPermissions || Flag.OPENCODE_DANGEROUSLY_SKIP_PERMISSIONS,
},
onExit: async () => {
await client.call("shutdown", undefined)
Expand Down
1 change: 1 addition & 0 deletions packages/opencode/src/flag/flag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export namespace Flag {
export const OPENCODE_DISABLE_PRUNE = truthy("OPENCODE_DISABLE_PRUNE")
export const OPENCODE_DISABLE_TERMINAL_TITLE = truthy("OPENCODE_DISABLE_TERMINAL_TITLE")
export const OPENCODE_PERMISSION = process.env["OPENCODE_PERMISSION"]
export const OPENCODE_DANGEROUSLY_SKIP_PERMISSIONS = truthy("OPENCODE_DANGEROUSLY_SKIP_PERMISSIONS")
export const OPENCODE_DISABLE_DEFAULT_PLUGINS = truthy("OPENCODE_DISABLE_DEFAULT_PLUGINS")
export const OPENCODE_DISABLE_LSP_DOWNLOAD = truthy("OPENCODE_DISABLE_LSP_DOWNLOAD")
export const OPENCODE_ENABLE_EXPERIMENTAL_MODELS = truthy("OPENCODE_ENABLE_EXPERIMENTAL_MODELS")
Expand Down
8 changes: 8 additions & 0 deletions packages/opencode/src/permission/next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@ import { fn } from "@/util/fn"
import { Log } from "@/util/log"
import { Wildcard } from "@/util/wildcard"
import z from "zod"
import { Flag } from "@/flag/flag"

export namespace PermissionNext {
const log = Log.create({ service: "permission" })

let skipPermissions = Flag.OPENCODE_DANGEROUSLY_SKIP_PERMISSIONS

export function setSkipPermissions(value: boolean) {
skipPermissions = value
}

export const Action = z.enum(["allow", "deny", "ask"]).meta({
ref: "PermissionAction",
})
Expand Down Expand Up @@ -126,6 +133,7 @@ export namespace PermissionNext {
if (rule.action === "deny")
throw new DeniedError(ruleset.filter((r) => Wildcard.match(request.permission, r.permission)))
if (rule.action === "ask") {
if (skipPermissions) continue
const id = input.id ?? Identifier.ascending("permission")
return new Promise<void>((resolve, reject) => {
const info: Request = {
Expand Down