fix(cli): align auto permission flags (#39384)

This commit is contained in:
Aiden Cline 2026-07-28 13:31:57 -05:00 committed by GitHub
commit 771174b5c3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 38 additions and 28 deletions

View file

@ -14,10 +14,23 @@ const ServerParams = {
),
}
const PermissionParams = {
auto: Flag.boolean("auto").pipe(
Flag.withDescription("Auto-approve permissions that are not explicitly denied"),
Flag.withDefault(false),
),
yolo: Flag.boolean("yolo").pipe(Flag.withDefault(false), Flag.withHidden),
dangerouslySkipPermissions: Flag.boolean("dangerously-skip-permissions").pipe(
Flag.withDefault(false),
Flag.withHidden,
),
}
export const Commands = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME : "opencode", {
description: "OpenCode 2.0 preview command line interface",
params: {
...ServerParams,
...PermissionParams,
directory: Argument.string("directory").pipe(
Argument.withDescription("Directory to start OpenCode in"),
Argument.optional,
@ -196,11 +209,7 @@ export const Commands = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCO
),
title: Flag.string("title").pipe(Flag.withDescription("Session title"), Flag.optional),
thinking: Flag.boolean("thinking").pipe(Flag.withDescription("Show thinking blocks"), Flag.withDefault(false)),
auto: Flag.boolean("auto").pipe(
Flag.withDescription("Auto-approve permissions that are not explicitly denied"),
Flag.withDefault(false),
),
yolo: Flag.boolean("yolo").pipe(Flag.withDefault(false), Flag.withHidden),
...PermissionParams,
},
}),
Spec.make("service", {

View file

@ -59,6 +59,7 @@ export default Runtime.handler(Commands, (input) =>
continue: input.continue,
sessionID: Option.getOrUndefined(input.session),
prompt: Option.getOrUndefined(input.prompt),
auto: input.auto || input.yolo || input.dangerouslySkipPermissions,
},
config: {
path: config.path,

View file

@ -24,7 +24,7 @@ export default Runtime.handler(Commands.commands.run, (input) =>
file: [...input.file],
title: Option.getOrUndefined(input.title),
thinking: input.thinking,
auto: input.auto || input.yolo,
auto: input.auto || input.yolo || input.dangerouslySkipPermissions,
}),
)
}),

View file

@ -5,11 +5,13 @@ import { useDirectory } from "../../context/directory"
import { useConnected } from "../../component/use-connected"
import { createStore } from "solid-js/store"
import { useRoute } from "../../context/route"
import { usePermission } from "../../context/permission"
export function Footer() {
const { themeV2 } = useTheme()
const data = useData()
const route = useRoute()
const permission = usePermission()
const mcp = createMemo(
() => (data.location.mcp.server.list() ?? []).filter((x) => x.status.status === "connected").length,
)
@ -61,7 +63,7 @@ export function Footer() {
</text>
</Match>
<Match when={connected()}>
<Show when={permissions().length > 0}>
<Show when={permission.mode !== "auto" && permissions().length > 0}>
<text fg={themeV2.text.feedback.warning.default}>
<span style={{ fg: themeV2.text.feedback.warning.default }}></span> {permissions().length} Permission
{permissions().length > 1 ? "s" : ""}

View file

@ -157,6 +157,7 @@ export function Session() {
(sessionID) => data.session.permission.list(sessionID) ?? [],
)
})
const promptedPermissions = createMemo(() => (local.permission.mode === "auto" ? [] : permissions()))
const forms = createMemo(() => {
const global = data.session.form.list("global", location()) ?? []
if (session()?.parentID) return global
@ -168,7 +169,7 @@ export function Session() {
open: false,
tab: undefined as string | undefined,
})
const disabled = createMemo(() => permissions().length > 0 || forms().length > 0)
const disabled = createMemo(() => promptedPermissions().length > 0 || forms().length > 0)
const pending = createMemo(() => {
const completed = messages().findLast((x) => x.type === "assistant" && x.time.completed)?.id
@ -966,10 +967,10 @@ export function Session() {
/>
<Switch>
<Match when={composer.open || (!!session()?.parentID && forms().length === 0)}>{null}</Match>
<Match when={permissions().length > 0}>
<Show when={permissions()[0]?.id} keyed>
<Match when={promptedPermissions().length > 0}>
<Show when={promptedPermissions()[0]?.id} keyed>
{(_) => {
const request = permissions()[0]
const request = promptedPermissions()[0]
return request ? (
<PermissionPrompt request={request} directory={session()?.location.directory} />
) : null
@ -2324,6 +2325,17 @@ function GenericTool(props: ToolProps) {
)
}
function useToolPermission(part: () => SessionMessageAssistantTool | undefined) {
const ctx = use()
const data = useData()
const local = useLocal()
return createMemo(() => {
if (local.permission.mode === "auto") return false
const request = data.session.permission.list(ctx.sessionID)?.[0]
return request?.source?.type === "tool" && request.source.callID === part()?.id
})
}
function InlineTool(props: {
icon: string
iconColor?: RGBA
@ -2338,16 +2350,10 @@ function InlineTool(props: {
onClick?: () => void
}) {
const { themeV2 } = useTheme()
const ctx = use()
const data = useData()
const renderer = useRenderer()
const [hover, setHover] = createSignal(false)
const [errorExpanded, setErrorExpanded] = createSignal(false)
const permission = createMemo(() => {
const request = data.session.permission.list(ctx.sessionID)?.[0]
return request?.source?.type === "tool" && request.source.callID === props.part.id
})
const permission = useToolPermission(() => props.part)
const error = createMemo(() => (props.part.state.status === "error" ? props.part.state.error.message : undefined))
@ -2526,15 +2532,10 @@ function BlockTool(props: BlockToolProps) {
function BlockToolContent(props: BlockToolProps & { borderColor: RGBA }) {
const { themeV2 } = useTheme()
const ctx = use()
const data = useData()
const renderer = useRenderer()
const [hover, setHover] = createSignal(false)
const error = createMemo(() => (props.part?.state.status === "error" ? props.part.state.error.message : undefined))
const permission = createMemo(() => {
if (!props.part) return false
const request = data.session.permission.list(ctx.sessionID)?.[0]
return request?.source?.type === "tool" && request.source.callID === props.part.id
})
const permission = useToolPermission(() => props.part)
return (
<box
border={["left"]}
@ -2611,10 +2612,7 @@ function Shell(props: ToolProps) {
const client = useClient()
const data = useData()
const pathFormatter = usePathFormatter()
const permission = createMemo(() => {
const request = data.session.permission.list(ctx.sessionID)?.[0]
return request?.source?.type === "tool" && request.source.callID === props.part.id
})
const permission = useToolPermission(() => props.part)
const color = createMemo(() => (permission() ? themeV2.text.feedback.warning.default : themeV2.text.default))
const shellID = createMemo(() => stringValue(props.metadata.shellID))
const background = createMemo(() => Boolean(shellID()) && props.part.state.status !== "running")