feat(settings): let Codex terminals opt back into Codex's shared server (#23929)

* feat(settings): add a setting to run Codex terminals on Codex's shared server

Off injects ORCA_CODEX_ISOLATE=0 into new terminals on every host (local,
daemon, SSH relay, WSL), which the codex shell wrapper from #23900 reads
to skip --no-daemon. On (the default) injects nothing.

* feat(terminal): announce per-terminal Codex servers once

Shows a one-time toast the first time a Codex terminal starts, with an
Open Settings action that lands on the new Codex server setting. The
seen flag persists in UI state and is set when the toast is shown.

* fix(settings): drop the status warning from the Codex server setting

* fix(terminal): simplify the Codex shared-server notice

* fix(terminal): say agent status in the Codex notice

* fix(settings): hide the Codex server setting from paired web search

Gives its search entry an id and gates it with
includeCodexTerminalServerIsolation, as the other host-only rows are, so
a paired web client cannot find a row it never renders. Its search
keywords now use catalogued agents-search keys instead of missing ones;
CODEX_ISOLATE_ENV is no longer exported; the toast id comment names the
case it guards.

* test(settings): assert the Codex server search gate through the metadata builder

Calling getAgentsPaneSearchEntries directly stayed green with the web
gate deleted; the metadata builder test fails without it.
This commit is contained in:
Jinwoo Hong
2026-09-29 21:44:27 -04:00
committed by GitHub
parent 8a38a7a3e6
commit a0abcb6818
26 changed files with 568 additions and 17 deletions
@@ -0,0 +1,26 @@
import type { GlobalSettings } from './global-settings-types'
type CodexTerminalServerIsolationSettings =
| Partial<Pick<GlobalSettings, 'codexTerminalServerIsolation'>>
| null
| undefined
// Why this name: the codex shell wrapper (codex-shell-launch-preflight.ts) reads it to skip --no-daemon.
const CODEX_ISOLATE_ENV = 'ORCA_CODEX_ISOLATE'
export function isCodexTerminalServerIsolationEnabled(
settings: CodexTerminalServerIsolationSettings
): boolean {
return settings?.codexTerminalServerIsolation !== false
}
/** Opt-out only: with isolation on nothing is injected, so behaviour matches the pre-setting default. */
export function withCodexTerminalServerIsolationEnv(
env: Record<string, string> | undefined,
settings: CodexTerminalServerIsolationSettings
): Record<string, string> | undefined {
if (isCodexTerminalServerIsolationEnabled(settings)) {
return env
}
return { ...env, [CODEX_ISOLATE_ENV]: '0' }
}
+1
View File
@@ -221,6 +221,7 @@ export function buildDefaultSettings(args: {
agentYoloDefaultsMigrated: true,
agentStatusHooksEnabled: true,
agentWorkspaceTrustEnabled: true,
codexTerminalServerIsolation: true,
tabAutoGenerateTitle: false,
confirmClosePinnedTab: true,
editorPreviewTabsEnabled: true,
+2
View File
@@ -419,6 +419,8 @@ export type GlobalSettings = {
agentStatusHooksEnabled: boolean
/** Pre-trust the worktree or folder Orca starts an agent in, so its "trust this folder?" prompt is skipped. Defaults on. */
agentWorkspaceTrustEnabled: boolean
/** Why: Codex's shared server runs every tab's hooks with the first tab's env; off opts new terminals back into it. Absent reads as on. */
codexTerminalServerIsolation?: boolean
/** Dismissed freshness tuples: no write authority, just suppress re-nudging the same official placement/revision. */
dismissedSkillFreshnessNudges?: string[]
/** Why: generated tab titles are subjective, so they stay opt-in and manual renames win. */
+2
View File
@@ -170,6 +170,8 @@ export type PersistedUIState = {
usagePercentageDisplayChangeNoticeDismissed?: boolean
/** User-hidden empty-state usage CTA; permanently hides the "Connect AI accounts" prompt even if providers are later disconnected. */
usageEmptyStateDismissed?: boolean
/** One-shot toast announcing per-terminal Codex servers; set when shown, so absent means not yet seen. */
codexTerminalServerIsolationNoticeSeen?: boolean
/** URL for new browser tabs; null = blank tab. */
browserDefaultUrl?: string | null
browserDefaultSearchEngine?: 'google' | 'duckduckgo' | 'bing' | 'kagi' | null
@@ -238,6 +238,7 @@ export const UiUpdateFields = z
projectOrderManualDefaultNoticeDismissed: z.boolean().optional(),
usagePercentageDisplayChangeNoticeDismissed: z.boolean().optional(),
usageEmptyStateDismissed: z.boolean().optional(),
codexTerminalServerIsolationNoticeSeen: z.boolean().optional(),
petVisible: z.boolean().optional(),
petId: z.string().optional(),
customPets: UnknownRecordArray.optional(),