mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
Add agent permission mode controls (#5440)
This commit is contained in:
@@ -2,16 +2,21 @@ import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { AGENT_CATALOG } from '@/lib/agent-catalog'
|
||||
import { AgentStep } from './AgentStep'
|
||||
import { TooltipProvider } from '@/components/ui/tooltip'
|
||||
|
||||
describe('AgentStep', () => {
|
||||
it('shows the collapsed fallback agents summary', () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<AgentStep
|
||||
selectedAgent={null}
|
||||
onSelect={vi.fn()}
|
||||
detectedSet={new Set([AGENT_CATALOG[0].id])}
|
||||
isDetecting={false}
|
||||
/>
|
||||
<TooltipProvider>
|
||||
<AgentStep
|
||||
selectedAgent={null}
|
||||
onSelect={vi.fn()}
|
||||
detectedSet={new Set([AGENT_CATALOG[0].id])}
|
||||
isDetecting={false}
|
||||
yoloPermissions
|
||||
onYoloPermissionsChange={vi.fn()}
|
||||
/>
|
||||
</TooltipProvider>
|
||||
)
|
||||
|
||||
expect(html).toContain(`Show ${AGENT_CATALOG.length - 1} more agents→`)
|
||||
@@ -19,12 +24,16 @@ describe('AgentStep', () => {
|
||||
|
||||
it('labels the fallback agents summary as hide when expanded', () => {
|
||||
const html = renderToStaticMarkup(
|
||||
<AgentStep
|
||||
selectedAgent={AGENT_CATALOG[1].id}
|
||||
onSelect={vi.fn()}
|
||||
detectedSet={new Set([AGENT_CATALOG[0].id])}
|
||||
isDetecting={false}
|
||||
/>
|
||||
<TooltipProvider>
|
||||
<AgentStep
|
||||
selectedAgent={AGENT_CATALOG[1].id}
|
||||
onSelect={vi.fn()}
|
||||
detectedSet={new Set([AGENT_CATALOG[0].id])}
|
||||
isDetecting={false}
|
||||
yoloPermissions
|
||||
onYoloPermissionsChange={vi.fn()}
|
||||
/>
|
||||
</TooltipProvider>
|
||||
)
|
||||
|
||||
expect(html).toContain('Hide agents')
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useState } from 'react'
|
||||
import { Check, ExternalLink } from 'lucide-react'
|
||||
import { Check, ExternalLink, Info } from 'lucide-react'
|
||||
import { getAgentCatalog, AgentIcon, type AgentCatalogEntry } from '@/lib/agent-catalog'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import type { TuiAgent } from '../../../../shared/types'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
|
||||
@@ -14,9 +16,18 @@ type AgentStepProps = {
|
||||
onSelect: (agent: TuiAgent, fromCollapsedSection: boolean) => void
|
||||
detectedSet: Set<TuiAgent>
|
||||
isDetecting: boolean
|
||||
yoloPermissions?: boolean
|
||||
onYoloPermissionsChange?: (enabled: boolean) => void
|
||||
}
|
||||
|
||||
export function AgentStep({ selectedAgent, onSelect, detectedSet, isDetecting }: AgentStepProps) {
|
||||
export function AgentStep({
|
||||
selectedAgent,
|
||||
onSelect,
|
||||
detectedSet,
|
||||
isDetecting,
|
||||
yoloPermissions = true,
|
||||
onYoloPermissionsChange
|
||||
}: AgentStepProps) {
|
||||
const agentCatalog = getAgentCatalog()
|
||||
const detected = agentCatalog.filter((agent) => detectedSet.has(agent.id))
|
||||
const rest = agentCatalog.filter((agent) => !detectedSet.has(agent.id))
|
||||
@@ -82,6 +93,44 @@ export function AgentStep({ selectedAgent, onSelect, detectedSet, isDetecting }:
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<label className="flex cursor-pointer items-center justify-between gap-4 rounded-lg border border-border bg-background/50 px-4 py-3 transition-colors hover:bg-accent/50">
|
||||
<span className="flex min-w-0 items-center gap-3">
|
||||
<Checkbox
|
||||
checked={yoloPermissions}
|
||||
onCheckedChange={(checked) => onYoloPermissionsChange?.(checked === true)}
|
||||
aria-label={translate(
|
||||
'auto.components.onboarding.AgentStep.yoloPermissionsLabel',
|
||||
'Yolo / Dangerously skip permissions'
|
||||
)}
|
||||
/>
|
||||
<span className="min-w-0 text-sm font-medium text-foreground">
|
||||
{translate(
|
||||
'auto.components.onboarding.AgentStep.yoloPermissionsLabel',
|
||||
'Yolo / Dangerously skip permissions'
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={translate(
|
||||
'auto.components.onboarding.AgentStep.yoloPermissionsInfo',
|
||||
'Agent permission info'
|
||||
)}
|
||||
className="grid size-6 shrink-0 place-items-center rounded-md text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
||||
>
|
||||
<Info className="size-3.5" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={6} style={{ zIndex: 120 }}>
|
||||
{translate(
|
||||
'auto.components.onboarding.AgentStep.yoloPermissionsTooltip',
|
||||
'Skip permission checks for agents for less interruptions'
|
||||
)}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</label>
|
||||
<section className="space-y-3">
|
||||
<SectionHeader
|
||||
label={
|
||||
|
||||
@@ -274,6 +274,8 @@ export default function OnboardingFlow({
|
||||
onSelect={flow.setSelectedAgent}
|
||||
detectedSet={flow.detectedSet}
|
||||
isDetecting={flow.isDetectingAgents}
|
||||
yoloPermissions={flow.yoloPermissions}
|
||||
onYoloPermissionsChange={flow.setYoloPermissions}
|
||||
/>
|
||||
)}
|
||||
{currentStep.id === 'theme' && (
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useAppStore } from '@/store'
|
||||
import { ONBOARDING_FINAL_STEP, ONBOARDING_FLOW_VERSION } from '../../../../shared/constants'
|
||||
import type { EventProps } from '../../../../shared/telemetry-events'
|
||||
import type { GlobalSettings, OnboardingState, TuiAgent } from '../../../../shared/types'
|
||||
import { applyAgentPermissionMode } from '../../../../shared/tui-agent-permissions'
|
||||
import type { StepId, StepNumber } from './use-onboarding-flow-types'
|
||||
|
||||
export async function persistStep(
|
||||
@@ -126,6 +127,7 @@ export function useCloseWith({
|
||||
type PersistCurrentStepDeps = {
|
||||
currentStepId: StepId
|
||||
selectedAgent: TuiAgent | null
|
||||
yoloPermissions: boolean
|
||||
theme: GlobalSettings['theme']
|
||||
settings: GlobalSettings | null
|
||||
updateSettings: (updates: Partial<GlobalSettings>) => Promise<void> | void
|
||||
@@ -141,6 +143,7 @@ export type PersistCurrentStepResult = {
|
||||
export function usePersistCurrentStep({
|
||||
currentStepId,
|
||||
selectedAgent,
|
||||
yoloPermissions,
|
||||
theme,
|
||||
settings,
|
||||
updateSettings,
|
||||
@@ -155,7 +158,14 @@ export function usePersistCurrentStep({
|
||||
try {
|
||||
if (currentStepId === 'agent') {
|
||||
const defaultTuiAgent = selectedAgentOrBlank(selectedAgent)
|
||||
await updateSettings({ defaultTuiAgent })
|
||||
await updateSettings({
|
||||
defaultTuiAgent,
|
||||
...applyAgentPermissionMode({
|
||||
mode: yoloPermissions ? 'yolo' : 'manual',
|
||||
agentDefaultArgs: settings.agentDefaultArgs,
|
||||
agentDefaultEnv: settings.agentDefaultEnv
|
||||
})
|
||||
})
|
||||
const choseAgent = defaultTuiAgent !== 'blank'
|
||||
const wasAlreadyChosen = onboardingChecklist.choseAgent
|
||||
onOnboardingChange(
|
||||
@@ -210,6 +220,7 @@ export function usePersistCurrentStep({
|
||||
settings,
|
||||
theme,
|
||||
updateSettings,
|
||||
yoloPermissions,
|
||||
setError
|
||||
])
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import { buildOnboardingFolderAgentStartup } from '@/lib/onboarding-folder-agent
|
||||
import { resolveOnboardingSettingsHydration } from './onboarding-settings-hydration'
|
||||
import { openProjectDefaultCheckout } from '../sidebar/project-added-default-checkout'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { resolveAgentPermissionModeSummary } from '../../../../shared/tui-agent-permissions'
|
||||
|
||||
export { STEPS } from './use-onboarding-flow-types'
|
||||
export type { StepId, StepNumber } from './use-onboarding-flow-types'
|
||||
@@ -240,6 +241,12 @@ export function useOnboardingFlow(
|
||||
? settings.defaultTuiAgent
|
||||
: null
|
||||
)
|
||||
const [yoloPermissions, setYoloPermissions] = useState(
|
||||
resolveAgentPermissionModeSummary({
|
||||
agentDefaultArgs: settings?.agentDefaultArgs,
|
||||
agentDefaultEnv: settings?.agentDefaultEnv
|
||||
}) !== 'manual'
|
||||
)
|
||||
// Why: hydrate theme from saved settings instead of hardcoding 'dark' so users
|
||||
// who already configured a theme see their choice preselected.
|
||||
const [theme, setTheme] = useState<GlobalSettings['theme']>(settings?.theme ?? 'dark')
|
||||
@@ -263,6 +270,7 @@ export function useOnboardingFlow(
|
||||
// fallback defaults, unless the user already interacted with that field.
|
||||
const themeInteractedRef = useRef(false)
|
||||
const agentInteractedRef = useRef(false)
|
||||
const yoloPermissionsInteractedRef = useRef(false)
|
||||
const [settingsHydrated, setSettingsHydrated] = useState(settings != null)
|
||||
const settingsHydration = resolveOnboardingSettingsHydration({
|
||||
settings,
|
||||
@@ -281,6 +289,16 @@ export function useOnboardingFlow(
|
||||
setSelectedAgent(settingsHydration.selectedAgent)
|
||||
}
|
||||
}
|
||||
if (settings && !yoloPermissionsInteractedRef.current) {
|
||||
const nextYoloPermissions =
|
||||
resolveAgentPermissionModeSummary({
|
||||
agentDefaultArgs: settings.agentDefaultArgs,
|
||||
agentDefaultEnv: settings.agentDefaultEnv
|
||||
}) !== 'manual'
|
||||
if (nextYoloPermissions !== yoloPermissions) {
|
||||
setYoloPermissions(nextYoloPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
// Why: track user interaction so async settings hydration above doesn't
|
||||
// overwrite a value the user explicitly chose.
|
||||
@@ -335,6 +353,10 @@ export function useOnboardingFlow(
|
||||
},
|
||||
[]
|
||||
)
|
||||
const setYoloPermissionsInteractive = useCallback((enabled: boolean) => {
|
||||
yoloPermissionsInteractedRef.current = true
|
||||
setYoloPermissions(enabled)
|
||||
}, [])
|
||||
|
||||
const detectedSet = useMemo(() => new Set(detectedAgentIds ?? []), [detectedAgentIds])
|
||||
const currentStep = STEPS[stepIndex]
|
||||
@@ -573,6 +595,7 @@ export function useOnboardingFlow(
|
||||
const persistCurrentStep = usePersistCurrentStep({
|
||||
currentStepId: currentStep.id,
|
||||
selectedAgent,
|
||||
yoloPermissions,
|
||||
theme,
|
||||
settings,
|
||||
updateSettings,
|
||||
@@ -1211,6 +1234,8 @@ export function useOnboardingFlow(
|
||||
currentStep,
|
||||
selectedAgent,
|
||||
setSelectedAgent: setSelectedAgentInteractive,
|
||||
yoloPermissions,
|
||||
setYoloPermissions: setYoloPermissionsInteractive,
|
||||
theme,
|
||||
setTheme: setThemeInteractive,
|
||||
cloneUrl,
|
||||
|
||||
@@ -13,6 +13,7 @@ import { getAgentAwakeDescription, getAgentAwakeTitle } from './agent-awake-copy
|
||||
import { AgentAwakeSetting } from './AgentAwakeSetting'
|
||||
import {
|
||||
AgentAvailabilityControl,
|
||||
AgentPermissionsSetting,
|
||||
AgentGeneratedTabTitlesSetting,
|
||||
AgentStatusHooksSetting,
|
||||
AgentsPane,
|
||||
@@ -21,6 +22,7 @@ import {
|
||||
createAgentAvailabilityUpdateQueue
|
||||
} from './AgentsPane'
|
||||
import { matchesSettingsSearch } from './settings-search'
|
||||
import { TooltipProvider } from '../ui/tooltip'
|
||||
|
||||
const detectedAgentsMock = vi.hoisted(() => ({
|
||||
detectedIds: ['claude'] as TuiAgent[] | null,
|
||||
@@ -64,11 +66,15 @@ function renderPane(
|
||||
props: Partial<React.ComponentProps<typeof AgentsPane>> = {}
|
||||
): string {
|
||||
return renderToStaticMarkup(
|
||||
React.createElement(AgentsPane, {
|
||||
settings,
|
||||
updateSettings: vi.fn(),
|
||||
...props
|
||||
})
|
||||
React.createElement(
|
||||
TooltipProvider,
|
||||
null,
|
||||
React.createElement(AgentsPane, {
|
||||
settings,
|
||||
updateSettings: vi.fn(),
|
||||
...props
|
||||
})
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -259,6 +265,30 @@ describe('AgentsPane', () => {
|
||||
expect(matchesSettingsSearch('hide', getAgentsPaneSearchEntries())).toBe(true)
|
||||
})
|
||||
|
||||
it('includes agent permission search metadata', () => {
|
||||
expect(matchesSettingsSearch('permission', getAgentsPaneSearchEntries())).toBe(true)
|
||||
expect(matchesSettingsSearch('yolo', getAgentsPaneSearchEntries())).toBe(true)
|
||||
expect(matchesSettingsSearch('manual', getAgentsPaneSearchEntries())).toBe(true)
|
||||
})
|
||||
|
||||
it('applies the selected agent permission mode from settings without a mixed segment', () => {
|
||||
const onChange = vi.fn()
|
||||
const element = AgentPermissionsSetting({ mode: 'mixed', onChange })
|
||||
const props = element.props.children.props.action.props as {
|
||||
value: 'yolo'
|
||||
onChange: (value: 'yolo' | 'manual' | 'mixed') => void
|
||||
options: { value: string }[]
|
||||
}
|
||||
|
||||
expect(props.value).toBe('yolo')
|
||||
expect(props.options.map((option) => option.value)).toEqual(['yolo', 'manual'])
|
||||
props.onChange('mixed')
|
||||
expect(onChange).not.toHaveBeenCalled()
|
||||
|
||||
props.onChange('manual')
|
||||
expect(onChange).toHaveBeenCalledWith('manual')
|
||||
})
|
||||
|
||||
it('keeps catalog agent ids, labels, and commands discoverable in settings search', () => {
|
||||
for (const agent of AGENT_CATALOG) {
|
||||
expect(matchesSettingsSearch(agent.id, getAgentsPaneSearchEntries())).toBe(true)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
selection, per-agent controls, and runtime location together so settings
|
||||
reconciliation stays visible in one file. */
|
||||
import { useMemo, useState } from 'react'
|
||||
import { Check, ChevronDown, ExternalLink, RefreshCw, Terminal } from 'lucide-react'
|
||||
import { Check, ChevronDown, ExternalLink, Info, RefreshCw, Terminal } from 'lucide-react'
|
||||
import type { GlobalSettings, TuiAgent } from '../../../../shared/types'
|
||||
import { getAgentCatalog, AgentIcon } from '@/lib/agent-catalog'
|
||||
import { useDetectedAgents } from '@/hooks/useDetectedAgents'
|
||||
@@ -33,8 +33,14 @@ import {
|
||||
resolveTuiAgentLaunchArgs,
|
||||
resolveTuiAgentLaunchEnv
|
||||
} from '../../../../shared/tui-agent-launch-defaults'
|
||||
import {
|
||||
applyAgentPermissionMode,
|
||||
resolveAgentPermissionModeSummary,
|
||||
type AgentPermissionMode
|
||||
} from '../../../../shared/tui-agent-permissions'
|
||||
import { getSettingOwnershipSummary } from './setting-ownership'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'
|
||||
|
||||
export { getAgentsPaneSearchEntries } from './agents-search'
|
||||
|
||||
@@ -103,6 +109,11 @@ type AgentAvailabilityControlProps = {
|
||||
onSetEnabled: (enabled: boolean) => void
|
||||
}
|
||||
|
||||
type AgentPermissionsSettingProps = {
|
||||
mode: AgentPermissionMode
|
||||
onChange: (mode: Exclude<AgentPermissionMode, 'mixed'>) => void
|
||||
}
|
||||
|
||||
export function buildAgentAvailabilitySettingsUpdate(
|
||||
settings: Pick<GlobalSettings, 'defaultTuiAgent' | 'disabledTuiAgents'>,
|
||||
id: TuiAgent,
|
||||
@@ -177,6 +188,76 @@ export function AgentAvailabilityControl({
|
||||
)
|
||||
}
|
||||
|
||||
export function AgentPermissionsSetting({
|
||||
mode,
|
||||
onChange
|
||||
}: AgentPermissionsSettingProps): React.JSX.Element {
|
||||
const visibleMode: Exclude<AgentPermissionMode, 'mixed'> = mode === 'manual' ? 'manual' : 'yolo'
|
||||
return (
|
||||
<section className="space-y-3">
|
||||
<SettingsSubsectionHeader
|
||||
title={
|
||||
<span className="flex items-center gap-2">
|
||||
{translate('auto.components.settings.AgentsPane.agentPermissions', 'Agent Permissions')}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={translate(
|
||||
'auto.components.settings.AgentsPane.agentPermissionsInfo',
|
||||
'Agent permissions info'
|
||||
)}
|
||||
className="grid size-5 place-items-center rounded-md text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50"
|
||||
>
|
||||
<Info className="size-3.5" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={6}>
|
||||
{translate(
|
||||
'auto.components.settings.AgentsPane.agentPermissionsTooltip',
|
||||
"Doesn't apply to agents where you've overridden launch arguments."
|
||||
)}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</span>
|
||||
}
|
||||
description={translate(
|
||||
'auto.components.settings.AgentsPane.agentPermissionsDescription',
|
||||
'Choose whether Orca launches agents with fewer permission prompts or with manual checks.'
|
||||
)}
|
||||
action={
|
||||
<SettingsSegmentedControl<AgentPermissionMode>
|
||||
value={visibleMode}
|
||||
onChange={(nextMode) => {
|
||||
if (nextMode !== 'mixed') {
|
||||
onChange(nextMode)
|
||||
}
|
||||
}}
|
||||
ariaLabel={translate(
|
||||
'auto.components.settings.AgentsPane.agentPermissions',
|
||||
'Agent Permissions'
|
||||
)}
|
||||
size="sm"
|
||||
options={[
|
||||
{
|
||||
value: 'yolo',
|
||||
label: translate('auto.components.settings.AgentsPane.agentPermissionsYolo', 'Yolo')
|
||||
},
|
||||
{
|
||||
value: 'manual',
|
||||
label: translate(
|
||||
'auto.components.settings.AgentsPane.agentPermissionsManual',
|
||||
'Manual'
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function AgentCommandOverrideInput({
|
||||
defaultCmd,
|
||||
cmdOverride,
|
||||
@@ -617,6 +698,10 @@ export function AgentsPane({
|
||||
const cmdOverrides = settings.agentCmdOverrides ?? {}
|
||||
const agentDefaultArgs = settings.agentDefaultArgs ?? {}
|
||||
const agentDefaultEnv = settings.agentDefaultEnv ?? {}
|
||||
const agentPermissionMode = resolveAgentPermissionModeSummary({
|
||||
agentDefaultArgs,
|
||||
agentDefaultEnv
|
||||
})
|
||||
const disabledAgents = normalizeDisabledTuiAgents(settings.disabledTuiAgents)
|
||||
|
||||
const setDefault = (id: TuiAgent | 'blank' | null): void => {
|
||||
@@ -661,6 +746,16 @@ export function AgentsPane({
|
||||
})
|
||||
}
|
||||
|
||||
const saveAgentPermissionMode = (mode: Exclude<AgentPermissionMode, 'mixed'>): void => {
|
||||
updateSettings(
|
||||
applyAgentPermissionMode({
|
||||
mode,
|
||||
agentDefaultArgs,
|
||||
agentDefaultEnv
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// Why: null means detection is in flight, not "all agents are installed".
|
||||
// Showing the full catalog here makes the default-agent picker flash invalid
|
||||
// options while switching between Windows and WSL detection contexts.
|
||||
@@ -742,6 +837,8 @@ export function AgentsPane({
|
||||
|
||||
<AgentAwakeSetting settings={settings} updateSettings={updateSettings} />
|
||||
|
||||
<AgentPermissionsSetting mode={agentPermissionMode} onChange={saveAgentPermissionMode} />
|
||||
|
||||
{detectedAgents.length > 0 && (
|
||||
<section className="space-y-3">
|
||||
<SettingsSubsectionHeader
|
||||
|
||||
@@ -30,6 +30,10 @@ function buildAgentSettingsKeywords(): string[] {
|
||||
{ key: 'auto.components.settings.agents.search.60393e1b17', fallback: 'disable' },
|
||||
{ key: 'auto.components.settings.agents.search.2e188c771c', fallback: 'hide' },
|
||||
{ key: 'auto.components.settings.agents.search.87fffe6c20', fallback: 'show' },
|
||||
{ key: 'auto.components.settings.agents.search.permission', fallback: 'permission' },
|
||||
{ key: 'auto.components.settings.agents.search.permissions', fallback: 'permissions' },
|
||||
{ key: 'auto.components.settings.agents.search.yolo', fallback: 'yolo', englishOnly: true },
|
||||
{ key: 'auto.components.settings.agents.search.manual', fallback: 'manual' },
|
||||
{
|
||||
key: 'auto.components.settings.agents.search.e2b7c0dcd7',
|
||||
fallback: 'github',
|
||||
@@ -94,5 +98,26 @@ export const getAgentsPaneSearchEntries = createLocalizedCatalog(() => [
|
||||
title: getAgentAwakeTitle(),
|
||||
description: getAgentAwakeDescription(),
|
||||
keywords: getAgentAwakeSearchKeywords()
|
||||
},
|
||||
{
|
||||
title: translate(
|
||||
'auto.components.settings.agents.search.agentPermissions',
|
||||
'Agent Permissions'
|
||||
),
|
||||
description: translate(
|
||||
'auto.components.settings.agents.search.agentPermissionsDescription',
|
||||
'Switch agent permission defaults between Yolo and Manual.'
|
||||
),
|
||||
keywords: [
|
||||
...translateSearchKeyword('auto.components.settings.agents.search.permission', 'permission'),
|
||||
...translateSearchKeyword(
|
||||
'auto.components.settings.agents.search.permissions',
|
||||
'permissions'
|
||||
),
|
||||
...translateSearchKeyword('auto.components.settings.agents.search.yolo', 'yolo'),
|
||||
...translateSearchKeyword('auto.components.settings.agents.search.manual', 'manual'),
|
||||
...translateSearchKeyword('auto.components.settings.agents.search.skip', 'skip'),
|
||||
...translateSearchKeyword('auto.components.settings.agents.search.checks', 'checks')
|
||||
]
|
||||
}
|
||||
])
|
||||
|
||||
@@ -4280,7 +4280,13 @@
|
||||
"cfb3f35775": "Arguments",
|
||||
"6f99bf5dd0": "No default arguments",
|
||||
"8fbe1f37c1": "Environment",
|
||||
"2d133152fa": "No default environment"
|
||||
"2d133152fa": "No default environment",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsInfo": "Agent permissions info",
|
||||
"agentPermissionsTooltip": "Doesn't apply to agents where you've overridden launch arguments.",
|
||||
"agentPermissionsDescription": "Choose whether Orca launches agents with fewer permission prompts or with manual checks.",
|
||||
"agentPermissionsYolo": "Yolo",
|
||||
"agentPermissionsManual": "Manual"
|
||||
},
|
||||
"AppIconSelector": {
|
||||
"d5a112dc9b": "Next icon",
|
||||
@@ -6351,7 +6357,9 @@
|
||||
"5784ae8c43": "rename",
|
||||
"8a17fd6026": "stable",
|
||||
"a79d266f71": "session",
|
||||
"afbf35be68": "stable session"
|
||||
"afbf35be68": "stable session",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsDescription": "Switch agent permission defaults between Yolo and Manual."
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
@@ -8811,7 +8819,10 @@
|
||||
"69af7e9c1c": "isn't on your PATH yet. Orca will set it as your default and you can install it any time.",
|
||||
"1eee1c7bd8": "No agents detected on your PATH. Pick one to install later, or continue with a blank terminal.",
|
||||
"hideAgents": "Hide agents",
|
||||
"showMoreAgents": "Show {{value0}} more agents→"
|
||||
"showMoreAgents": "Show {{value0}} more agents→",
|
||||
"yoloPermissionsLabel": "Yolo / Dangerously skip permissions",
|
||||
"yoloPermissionsInfo": "Agent permission info",
|
||||
"yoloPermissionsTooltip": "Skip permission checks for agents for less interruptions"
|
||||
},
|
||||
"FeatureSetupChecklist": {
|
||||
"77f74946f5": "Agents can message each other, take tasks, and coordinate handoffs.",
|
||||
|
||||
@@ -4280,7 +4280,13 @@
|
||||
"cfb3f35775": "Arguments",
|
||||
"6f99bf5dd0": "No default arguments",
|
||||
"8fbe1f37c1": "Environment",
|
||||
"2d133152fa": "No default environment"
|
||||
"2d133152fa": "No default environment",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsInfo": "Agent permissions info",
|
||||
"agentPermissionsTooltip": "Custom agent arguments stay unchanged when switching modes.",
|
||||
"agentPermissionsDescription": "Choose whether Orca launches agents with fewer permission prompts or with manual checks.",
|
||||
"agentPermissionsYolo": "Yolo",
|
||||
"agentPermissionsManual": "Manual"
|
||||
},
|
||||
"AppIconSelector": {
|
||||
"d5a112dc9b": "Icono siguiente",
|
||||
@@ -6314,7 +6320,9 @@
|
||||
"5784ae8c43": "rebautizar",
|
||||
"8a17fd6026": "estable",
|
||||
"a79d266f71": "sesión",
|
||||
"afbf35be68": "sesión estable"
|
||||
"afbf35be68": "sesión estable",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsDescription": "Switch agent permission defaults between Yolo and Manual."
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
@@ -8811,7 +8819,10 @@
|
||||
"69af7e9c1c": "aún no está en tu RUTA. Orca lo configurará como predeterminado y podrás instalarlo en cualquier momento.",
|
||||
"1eee1c7bd8": "No se detectaron agents en su RUTA. Elija uno para instalarlo más tarde o continúe con un terminal en blanco.",
|
||||
"hideAgents": "Ocultar agents",
|
||||
"showMoreAgents": "Mostrar {{value0}} más agents→"
|
||||
"showMoreAgents": "Mostrar {{value0}} más agents→",
|
||||
"yoloPermissionsLabel": "Yolo / Dangerously skip permissions",
|
||||
"yoloPermissionsInfo": "Agent permission info",
|
||||
"yoloPermissionsTooltip": "Skip permission checks for agents for less interruptions"
|
||||
},
|
||||
"FeatureSetupChecklist": {
|
||||
"77f74946f5": "Los Agents pueden enviarse mensajes entre sí, realizar tareas y coordinar traspasos.",
|
||||
|
||||
@@ -4265,7 +4265,13 @@
|
||||
"cfb3f35775": "Arguments",
|
||||
"6f99bf5dd0": "No default arguments",
|
||||
"8fbe1f37c1": "Environment",
|
||||
"2d133152fa": "No default environment"
|
||||
"2d133152fa": "No default environment",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsInfo": "Agent permissions info",
|
||||
"agentPermissionsTooltip": "Custom agent arguments stay unchanged when switching modes.",
|
||||
"agentPermissionsDescription": "Choose whether Orca launches agents with fewer permission prompts or with manual checks.",
|
||||
"agentPermissionsYolo": "Yolo",
|
||||
"agentPermissionsManual": "Manual"
|
||||
},
|
||||
"AppIconSelector": {
|
||||
"d5a112dc9b": "次へのアイコン",
|
||||
@@ -6336,7 +6342,9 @@
|
||||
"5784ae8c43": "名前変更",
|
||||
"8a17fd6026": "安定",
|
||||
"a79d266f71": "セッション",
|
||||
"afbf35be68": "安定したセッション"
|
||||
"afbf35be68": "安定したセッション",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsDescription": "Switch agent permission defaults between Yolo and Manual."
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
@@ -8811,7 +8819,10 @@
|
||||
"69af7e9c1c": "はまだ PATH 上にありません。 Orca はこれをデフォルトとして設定し、いつでもインストールできます。",
|
||||
"1eee1c7bd8": "PATH 上に agents が検出されませんでした。後でインストールするものを選択するか、空の terminal を使用して続行します。",
|
||||
"hideAgents": "agents を非表示にする",
|
||||
"showMoreAgents": "{{value0}} 件の agents をさらに表示→"
|
||||
"showMoreAgents": "{{value0}} 件の agents をさらに表示→",
|
||||
"yoloPermissionsLabel": "Yolo / Dangerously skip permissions",
|
||||
"yoloPermissionsInfo": "Agent permission info",
|
||||
"yoloPermissionsTooltip": "Skip permission checks for agents for less interruptions"
|
||||
},
|
||||
"FeatureSetupChecklist": {
|
||||
"77f74946f5": "Agents は相互にメッセージを送信し、タスクを実行し、引き継ぎを調整できます。",
|
||||
|
||||
@@ -4265,7 +4265,13 @@
|
||||
"cfb3f35775": "Arguments",
|
||||
"6f99bf5dd0": "No default arguments",
|
||||
"8fbe1f37c1": "Environment",
|
||||
"2d133152fa": "No default environment"
|
||||
"2d133152fa": "No default environment",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsInfo": "Agent permissions info",
|
||||
"agentPermissionsTooltip": "Custom agent arguments stay unchanged when switching modes.",
|
||||
"agentPermissionsDescription": "Choose whether Orca launches agents with fewer permission prompts or with manual checks.",
|
||||
"agentPermissionsYolo": "Yolo",
|
||||
"agentPermissionsManual": "Manual"
|
||||
},
|
||||
"AppIconSelector": {
|
||||
"d5a112dc9b": "다음 아이콘",
|
||||
@@ -6299,7 +6305,9 @@
|
||||
"5784ae8c43": "이름 변경",
|
||||
"8a17fd6026": "안정적",
|
||||
"a79d266f71": "세션",
|
||||
"afbf35be68": "안정적인 세션"
|
||||
"afbf35be68": "안정적인 세션",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsDescription": "Switch agent permission defaults between Yolo and Manual."
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
@@ -8811,7 +8819,10 @@
|
||||
"69af7e9c1c": "아직 PATH에 없습니다. Orca는 이를 기본값으로 설정하며 언제든지 설치할 수 있습니다.",
|
||||
"1eee1c7bd8": "PATH에서 agents가 감지되지 않습니다. 나중에 설치할 항목을 선택하거나 빈 terminal을 계속 사용하세요.",
|
||||
"hideAgents": "agents 숨기기",
|
||||
"showMoreAgents": "{{value0}}개 더 많은 agents 표시→"
|
||||
"showMoreAgents": "{{value0}}개 더 많은 agents 표시→",
|
||||
"yoloPermissionsLabel": "Yolo / Dangerously skip permissions",
|
||||
"yoloPermissionsInfo": "Agent permission info",
|
||||
"yoloPermissionsTooltip": "Skip permission checks for agents for less interruptions"
|
||||
},
|
||||
"FeatureSetupChecklist": {
|
||||
"77f74946f5": "Agents는 서로 메시지를 보내고, 작업을 수행하고, 핸드오프를 조정할 수 있습니다.",
|
||||
|
||||
@@ -4265,7 +4265,13 @@
|
||||
"cfb3f35775": "Arguments",
|
||||
"6f99bf5dd0": "No default arguments",
|
||||
"8fbe1f37c1": "Environment",
|
||||
"2d133152fa": "No default environment"
|
||||
"2d133152fa": "No default environment",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsInfo": "Agent permissions info",
|
||||
"agentPermissionsTooltip": "Custom agent arguments stay unchanged when switching modes.",
|
||||
"agentPermissionsDescription": "Choose whether Orca launches agents with fewer permission prompts or with manual checks.",
|
||||
"agentPermissionsYolo": "Yolo",
|
||||
"agentPermissionsManual": "Manual"
|
||||
},
|
||||
"AppIconSelector": {
|
||||
"d5a112dc9b": "下一个图标",
|
||||
@@ -6299,7 +6305,9 @@
|
||||
"5784ae8c43": "重命名",
|
||||
"8a17fd6026": "稳定",
|
||||
"a79d266f71": "会话",
|
||||
"afbf35be68": "稳定会话"
|
||||
"afbf35be68": "稳定会话",
|
||||
"agentPermissions": "Agent Permissions",
|
||||
"agentPermissionsDescription": "Switch agent permission defaults between Yolo and Manual."
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
@@ -8811,7 +8819,10 @@
|
||||
"69af7e9c1c": "尚未加入 PATH。Orca 会将其设为默认,你可随时安装。",
|
||||
"1eee1c7bd8": "PATH 中未检测到 agents。可选择一个稍后安装,或使用空白 terminal 继续。",
|
||||
"hideAgents": "隐藏 Agent",
|
||||
"showMoreAgents": "显示另外 {{value0}} 个 Agent→"
|
||||
"showMoreAgents": "显示另外 {{value0}} 个 Agent→",
|
||||
"yoloPermissionsLabel": "Yolo / Dangerously skip permissions",
|
||||
"yoloPermissionsInfo": "Agent permission info",
|
||||
"yoloPermissionsTooltip": "Skip permission checks for agents for less interruptions"
|
||||
},
|
||||
"FeatureSetupChecklist": {
|
||||
"77f74946f5": "Agent 可互相通信、领取任务并协调交接。",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isTuiAgent } from './tui-agent-config'
|
||||
import { YOLO_TUI_AGENT_ARGS, YOLO_TUI_AGENT_ENV } from './tui-agent-permissions'
|
||||
import type { TuiAgent } from './types'
|
||||
|
||||
const UNSUPPORTED_TUI_AGENT_ARGS: Partial<Record<TuiAgent, readonly string[]>> = {
|
||||
@@ -6,35 +7,10 @@ const UNSUPPORTED_TUI_AGENT_ARGS: Partial<Record<TuiAgent, readonly string[]>> =
|
||||
kilo: ['--dangerously-skip-permissions']
|
||||
}
|
||||
|
||||
export const DEFAULT_TUI_AGENT_ARGS: Partial<Record<TuiAgent, string>> = {
|
||||
claude: '--dangerously-skip-permissions',
|
||||
'claude-agent-teams': '--dangerously-skip-permissions',
|
||||
openclaude: '--dangerously-skip-permissions',
|
||||
codex: '--dangerously-bypass-approvals-and-sandbox',
|
||||
gemini: '--yolo',
|
||||
antigravity: '--dangerously-skip-permissions',
|
||||
aider: '--yes-always',
|
||||
amp: '--dangerously-allow-all',
|
||||
kiro: '--trust-all-tools',
|
||||
crush: '--yolo',
|
||||
autohand: '--unrestricted',
|
||||
cline: '--auto-approve true',
|
||||
'command-code': '--yolo',
|
||||
continue: '--allow "*"',
|
||||
cursor: '--yolo',
|
||||
kimi: '--yolo',
|
||||
'mistral-vibe': '--agent auto-approve',
|
||||
'qwen-code': '--approval-mode yolo',
|
||||
rovo: '--yolo',
|
||||
hermes: '--yolo',
|
||||
copilot: '--yolo',
|
||||
grok: '--permission-mode bypassPermissions',
|
||||
devin: '--permission-mode bypass'
|
||||
}
|
||||
export const DEFAULT_TUI_AGENT_ARGS: Partial<Record<TuiAgent, string>> = YOLO_TUI_AGENT_ARGS
|
||||
|
||||
export const DEFAULT_TUI_AGENT_ENV: Partial<Record<TuiAgent, Record<string, string>>> = {
|
||||
goose: { GOOSE_MODE: 'auto' }
|
||||
}
|
||||
export const DEFAULT_TUI_AGENT_ENV: Partial<Record<TuiAgent, Record<string, string>>> =
|
||||
YOLO_TUI_AGENT_ENV
|
||||
|
||||
function argPattern(arg: string): RegExp {
|
||||
return new RegExp(`(^|\\s)${arg.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?=\\s|$)`, 'g')
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
applyAgentPermissionMode,
|
||||
resolveAgentPermissionModeSummary,
|
||||
YOLO_TUI_AGENT_ARGS,
|
||||
YOLO_TUI_AGENT_ENV
|
||||
} from './tui-agent-permissions'
|
||||
|
||||
describe('tui agent permissions', () => {
|
||||
it('recognizes the current default profile as yolo', () => {
|
||||
expect(
|
||||
resolveAgentPermissionModeSummary({
|
||||
agentDefaultArgs: YOLO_TUI_AGENT_ARGS,
|
||||
agentDefaultEnv: YOLO_TUI_AGENT_ENV
|
||||
})
|
||||
).toBe('yolo')
|
||||
})
|
||||
|
||||
it('recognizes an empty profile as manual', () => {
|
||||
expect(resolveAgentPermissionModeSummary({ agentDefaultArgs: {}, agentDefaultEnv: {} })).toBe(
|
||||
'manual'
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves custom agent arguments when applying manual mode', () => {
|
||||
const result = applyAgentPermissionMode({
|
||||
mode: 'manual',
|
||||
agentDefaultArgs: {
|
||||
claude: '--dangerously-skip-permissions',
|
||||
codex: '--model gpt-5'
|
||||
},
|
||||
agentDefaultEnv: YOLO_TUI_AGENT_ENV
|
||||
})
|
||||
|
||||
expect(result.agentDefaultArgs.claude).toBe('')
|
||||
expect(result.agentDefaultArgs.codex).toBe('--model gpt-5')
|
||||
expect(result.agentDefaultEnv.goose).toEqual({})
|
||||
})
|
||||
|
||||
it('reports mixed when custom arguments are present', () => {
|
||||
expect(
|
||||
resolveAgentPermissionModeSummary({
|
||||
agentDefaultArgs: {
|
||||
...YOLO_TUI_AGENT_ARGS,
|
||||
codex: '--model gpt-5'
|
||||
},
|
||||
agentDefaultEnv: YOLO_TUI_AGENT_ENV
|
||||
})
|
||||
).toBe('mixed')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,143 @@
|
||||
import { TUI_AGENT_CONFIG } from './tui-agent-config'
|
||||
import type { TuiAgent } from './types'
|
||||
|
||||
export type AgentPermissionMode = 'yolo' | 'manual' | 'mixed'
|
||||
|
||||
export const YOLO_TUI_AGENT_ARGS: Partial<Record<TuiAgent, string>> = {
|
||||
claude: '--dangerously-skip-permissions',
|
||||
'claude-agent-teams': '--dangerously-skip-permissions',
|
||||
openclaude: '--dangerously-skip-permissions',
|
||||
codex: '--dangerously-bypass-approvals-and-sandbox',
|
||||
gemini: '--yolo',
|
||||
antigravity: '--dangerously-skip-permissions',
|
||||
aider: '--yes-always',
|
||||
amp: '--dangerously-allow-all',
|
||||
kiro: '--trust-all-tools',
|
||||
crush: '--yolo',
|
||||
autohand: '--unrestricted',
|
||||
cline: '--auto-approve true',
|
||||
'command-code': '--yolo',
|
||||
continue: '--allow "*"',
|
||||
cursor: '--yolo',
|
||||
kimi: '--yolo',
|
||||
'mistral-vibe': '--agent auto-approve',
|
||||
'qwen-code': '--approval-mode yolo',
|
||||
rovo: '--yolo',
|
||||
hermes: '--yolo',
|
||||
copilot: '--yolo',
|
||||
grok: '--permission-mode bypassPermissions',
|
||||
devin: '--permission-mode bypass'
|
||||
}
|
||||
|
||||
export const YOLO_TUI_AGENT_ENV: Partial<Record<TuiAgent, Record<string, string>>> = {
|
||||
goose: { GOOSE_MODE: 'auto' }
|
||||
}
|
||||
|
||||
const PERMISSION_AGENT_IDS = Object.keys(TUI_AGENT_CONFIG).filter(
|
||||
(agent): agent is TuiAgent => agent in YOLO_TUI_AGENT_ARGS || agent in YOLO_TUI_AGENT_ENV
|
||||
)
|
||||
|
||||
function normalizeArgs(value: string | null | undefined): string {
|
||||
return value?.trim() ?? ''
|
||||
}
|
||||
|
||||
function sameEnv(
|
||||
left: Record<string, string> | null | undefined,
|
||||
right: Record<string, string> | null | undefined
|
||||
): boolean {
|
||||
const leftEntries = Object.entries(left ?? {})
|
||||
const rightEntries = Object.entries(right ?? {})
|
||||
if (leftEntries.length !== rightEntries.length) {
|
||||
return false
|
||||
}
|
||||
return leftEntries.every(([name, value]) => right?.[name] === value)
|
||||
}
|
||||
|
||||
function resolveAgentPermissionMode(args: string, yoloArgs: string): AgentPermissionMode {
|
||||
if (!args) {
|
||||
return 'manual'
|
||||
}
|
||||
return args === yoloArgs ? 'yolo' : 'mixed'
|
||||
}
|
||||
|
||||
function resolveAgentEnvPermissionMode(
|
||||
env: Record<string, string> | null | undefined,
|
||||
yoloEnv: Record<string, string> | undefined
|
||||
): AgentPermissionMode {
|
||||
if (sameEnv(env, {})) {
|
||||
return 'manual'
|
||||
}
|
||||
return sameEnv(env, yoloEnv) ? 'yolo' : 'mixed'
|
||||
}
|
||||
|
||||
export function resolveAgentPermissionModeSummary(args: {
|
||||
agentDefaultArgs?: Partial<Record<TuiAgent, string>> | null
|
||||
agentDefaultEnv?: Partial<Record<TuiAgent, Record<string, string>>> | null
|
||||
}): AgentPermissionMode {
|
||||
let sawYolo = false
|
||||
let sawManual = false
|
||||
let sawMixed = false
|
||||
|
||||
for (const agent of PERMISSION_AGENT_IDS) {
|
||||
const modes: AgentPermissionMode[] = []
|
||||
if (agent in YOLO_TUI_AGENT_ARGS) {
|
||||
modes.push(
|
||||
resolveAgentPermissionMode(
|
||||
normalizeArgs(args.agentDefaultArgs?.[agent]),
|
||||
YOLO_TUI_AGENT_ARGS[agent] ?? ''
|
||||
)
|
||||
)
|
||||
}
|
||||
if (agent in YOLO_TUI_AGENT_ENV) {
|
||||
modes.push(
|
||||
resolveAgentEnvPermissionMode(args.agentDefaultEnv?.[agent], YOLO_TUI_AGENT_ENV[agent])
|
||||
)
|
||||
}
|
||||
for (const mode of modes) {
|
||||
if (mode === 'yolo') {
|
||||
sawYolo = true
|
||||
} else if (mode === 'manual') {
|
||||
sawManual = true
|
||||
} else {
|
||||
sawMixed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sawMixed || (sawYolo && sawManual)) {
|
||||
return 'mixed'
|
||||
}
|
||||
return sawYolo ? 'yolo' : 'manual'
|
||||
}
|
||||
|
||||
export function applyAgentPermissionMode(args: {
|
||||
mode: Exclude<AgentPermissionMode, 'mixed'>
|
||||
agentDefaultArgs?: Partial<Record<TuiAgent, string>> | null
|
||||
agentDefaultEnv?: Partial<Record<TuiAgent, Record<string, string>>> | null
|
||||
}): {
|
||||
agentDefaultArgs: Partial<Record<TuiAgent, string>>
|
||||
agentDefaultEnv: Partial<Record<TuiAgent, Record<string, string>>>
|
||||
} {
|
||||
const nextArgs = { ...args.agentDefaultArgs }
|
||||
const nextEnv = { ...args.agentDefaultEnv }
|
||||
|
||||
for (const agent of PERMISSION_AGENT_IDS) {
|
||||
if (agent in YOLO_TUI_AGENT_ARGS) {
|
||||
const yoloArgs = YOLO_TUI_AGENT_ARGS[agent] ?? ''
|
||||
const currentArgs = normalizeArgs(nextArgs[agent])
|
||||
if (!currentArgs || currentArgs === yoloArgs) {
|
||||
nextArgs[agent] = args.mode === 'yolo' ? yoloArgs : ''
|
||||
}
|
||||
}
|
||||
|
||||
if (agent in YOLO_TUI_AGENT_ENV) {
|
||||
const yoloEnv = YOLO_TUI_AGENT_ENV[agent]
|
||||
const currentEnv = nextEnv[agent]
|
||||
if (sameEnv(currentEnv, {}) || sameEnv(currentEnv, yoloEnv)) {
|
||||
nextEnv[agent] = args.mode === 'yolo' ? { ...yoloEnv } : {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { agentDefaultArgs: nextArgs, agentDefaultEnv: nextEnv }
|
||||
}
|
||||
Reference in New Issue
Block a user