mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 16:02:03 +00:00
feat(native-chat): enable Windows structured sessions
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import type { ChildProcessHandle, ProcessSpec } from '../../shared/child-process/process-spec'
|
||||
import { spawnProcess } from '../../shared/child-process/run-process'
|
||||
import { normalizeHookTrustKeyForLookup } from './config-toml-trust'
|
||||
import { runCodexAppServerSession, type CodexAppServerInvocation } from './codex-app-server-session'
|
||||
|
||||
@@ -105,7 +106,12 @@ function collectHookListings(result: unknown): CodexHookListing[] {
|
||||
*/
|
||||
export async function runCodexHookTrustGrantSession(
|
||||
request: CodexHookTrustGrantRequest,
|
||||
spawnImpl: typeof spawn = spawn
|
||||
spawnImpl: (
|
||||
program: string,
|
||||
args: string[],
|
||||
options: Record<string, unknown>
|
||||
) => ChildProcessHandle = (program, args, options) =>
|
||||
spawnProcess({ program, args, ...options } as ProcessSpec)
|
||||
): Promise<CodexHookTrustGrantSessionResult> {
|
||||
return runCodexAppServerSession(
|
||||
request.invocation,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { spawn, type ChildProcess, type ChildProcessWithoutNullStreams } from 'node:child_process'
|
||||
import { spawnProcess } from '../../shared/child-process/run-process'
|
||||
import type { ChildProcessHandle, ProcessSpec } from '../../shared/child-process/process-spec'
|
||||
import type { ChildProcessWithoutNullStreams } from 'node:child_process'
|
||||
import { waitForProcessExitUntil } from './codex-process-exit-deadline'
|
||||
import { stderrIndicatesMissingAppServer } from './codex-app-server-capability-signal'
|
||||
import { withCliRuntimeOnPath } from '../../shared/node-cli-command-resolution'
|
||||
@@ -68,11 +70,17 @@ const STDERR_TAIL_MAX_BYTES = 8192
|
||||
const STDOUT_LINE_MAX_BYTES = 1024 * 1024
|
||||
|
||||
export function killCodexAppServerProcessTree(
|
||||
child: Pick<ChildProcess, 'pid' | 'kill'>,
|
||||
options: { platform?: NodeJS.Platform; spawnImpl?: typeof spawn } = {}
|
||||
child: Pick<ChildProcessHandle, 'pid' | 'kill'>,
|
||||
options: {
|
||||
platform?: NodeJS.Platform
|
||||
spawnImpl?: (program: string, args: string[], options: Record<string, unknown>) => ChildProcessHandle
|
||||
} = {}
|
||||
): void {
|
||||
const platform = options.platform ?? process.platform
|
||||
const spawnImpl = options.spawnImpl ?? spawn
|
||||
const spawnImpl =
|
||||
options.spawnImpl ??
|
||||
((program: string, args: string[], spawnOptions: Record<string, unknown>) =>
|
||||
spawnProcess({ program, args, ...spawnOptions } as ProcessSpec))
|
||||
if (platform === 'win32' && child.pid) {
|
||||
try {
|
||||
// Why: npm-installed Codex runs behind cmd.exe; killing only that wrapper
|
||||
@@ -139,7 +147,8 @@ export function isCodexMethodNotFoundError(error: unknown): boolean {
|
||||
export async function runCodexAppServerSession<T>(
|
||||
invocation: CodexAppServerInvocation,
|
||||
body: (rpc: CodexAppServerRpc) => Promise<T>,
|
||||
spawnImpl: typeof spawn = spawn
|
||||
spawnImpl: (program: string, args: string[], options: Record<string, unknown>) => ChildProcessHandle =
|
||||
(program, args, options) => spawnProcess({ program, args, ...options } as ProcessSpec)
|
||||
): Promise<T> {
|
||||
// Why: a default-home grant must run against the real ~/.codex, so strip an
|
||||
// inherited CODEX_HOME (envToDelete) after applying the overlay, not before.
|
||||
|
||||
@@ -724,6 +724,7 @@ import {
|
||||
RUNTIME_CAPABILITIES,
|
||||
RUNTIME_PROTOCOL_VERSION,
|
||||
SESSION_TABS_AUTHORITATIVE_INVENTORY_RUNTIME_CAPABILITY,
|
||||
STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY,
|
||||
TERMINAL_PAIRED_PARKING_RUNTIME_CAPABILITY,
|
||||
type RuntimeCapability
|
||||
} from '../../shared/protocol-version'
|
||||
@@ -732,6 +733,7 @@ import {
|
||||
listAiVaultSessions
|
||||
} from '../ai-vault/cached-session-list'
|
||||
import { configureHostReadableTranscriptPathSources } from '../native-chat/host-readable-transcript-path'
|
||||
import { isWindowsProcessStartTimeAvailable } from '../windows/windows-process-table'
|
||||
import { resolveLocalAiVaultSessionTitles } from '../ai-vault/session-title-resolver'
|
||||
import type { AiVaultListArgs, AiVaultListResult } from '../../shared/ai-vault-types'
|
||||
import type {
|
||||
@@ -6619,7 +6621,13 @@ export class OrcaRuntimeService {
|
||||
(process.env.ORCA_E2E_DISABLE_PAIRED_TERMINAL_PARKING !== '1' ||
|
||||
capability !== TERMINAL_PAIRED_PARKING_RUNTIME_CAPABILITY) &&
|
||||
(process.env.ORCA_E2E_DISABLE_AUTHORITATIVE_SESSION_TABS_INVENTORY !== '1' ||
|
||||
capability !== SESSION_TABS_AUTHORITATIVE_INVENTORY_RUNTIME_CAPABILITY)
|
||||
capability !== SESSION_TABS_AUTHORITATIVE_INVENTORY_RUNTIME_CAPABILITY) &&
|
||||
// Structured ownership on Windows requires the native process-table
|
||||
// creation-time field; an older host must honestly fall back to the
|
||||
// terminal bridge rather than advertise an unsafe capability.
|
||||
(capability !== STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY ||
|
||||
process.platform !== 'win32' ||
|
||||
isWindowsProcessStartTimeAvailable())
|
||||
)
|
||||
if (hasOffscreen || hasHeadlessCommands) {
|
||||
capabilities.push(BROWSER_HEADLESS_RUNTIME_CAPABILITY)
|
||||
|
||||
@@ -152,11 +152,9 @@ describe('canUseStructuredNativeChat', () => {
|
||||
expect(canUseStructuredNativeChat(stateFor({ windowsRuntime: 'wsl' }), 'wt-1')).toBe(false)
|
||||
})
|
||||
|
||||
it('keeps Windows-host projects on the terminal path until native start-time proof is advertised', () => {
|
||||
it('allows Windows-host projects when structured chat is enabled', () => {
|
||||
mockGetRendererAppPlatform.mockReturnValue('win32')
|
||||
expect(canUseStructuredNativeChat(stateFor({ windowsRuntime: 'windows-host' }), 'wt-1')).toBe(
|
||||
false
|
||||
)
|
||||
expect(canUseStructuredNativeChat(stateFor({ windowsRuntime: 'windows-host' }), 'wt-1')).toBe(true)
|
||||
})
|
||||
|
||||
it('refuses a Windows folder workspace even though its key resolves no project runtime', () => {
|
||||
@@ -166,7 +164,7 @@ describe('canUseStructuredNativeChat', () => {
|
||||
activeRepoId: null,
|
||||
activeWorktreeId: null
|
||||
} as unknown as AppState
|
||||
expect(canUseStructuredNativeChat(state, 'folder:folder-1')).toBe(false)
|
||||
expect(canUseStructuredNativeChat(state, 'folder:folder-1')).toBe(true)
|
||||
})
|
||||
|
||||
it('allows a folder workspace on a non-Windows platform', () => {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { AppState } from '@/store/types'
|
||||
import { getLocalProjectExecutionRuntimeContext } from '@/lib/local-preflight-context'
|
||||
import { getExecutionHostIdForWorktree } from '@/lib/worktree-runtime-owner'
|
||||
import { getRendererAppPlatform } from '@/lib/renderer-app-platform'
|
||||
|
||||
export function canUseStructuredNativeChat(state: AppState, worktreeId: string): boolean {
|
||||
if (state.settings?.experimentalStructuredNativeChat !== true) {
|
||||
@@ -16,15 +15,8 @@ export function canUseStructuredNativeChat(state: AppState, worktreeId: string):
|
||||
if (getExecutionHostIdForWorktree(state, worktreeId) !== 'local') {
|
||||
return false
|
||||
}
|
||||
// The shipped Windows process-tree addon may not expose creation time. Until
|
||||
// the host advertises that proof, refuse every local Windows execution path —
|
||||
// windows-host, WSL, and keys that resolve no project runtime (folder
|
||||
// workspaces, floating terminal) — so create cannot fail after the click.
|
||||
if (getRendererAppPlatform() === 'win32') {
|
||||
return false
|
||||
}
|
||||
// Refuse WSL and repair-required runtimes even if resolution ever runs
|
||||
// off-win32; the gate must not depend on the resolver's platform guard.
|
||||
// Refuse WSL and repair-required runtimes; Windows native execution is
|
||||
// supported when the host advertises the process identity capability.
|
||||
const projectRuntime = getLocalProjectExecutionRuntimeContext(state, worktreeId)
|
||||
return !(projectRuntime?.status === 'repair-required' || projectRuntime?.runtime.kind === 'wsl')
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ src/main/codex-accounts/legacy-wsl-runtime-auth-drain-recovery-script-harness.ts
|
||||
src/main/codex-accounts/legacy-wsl-runtime-auth-drain-script-harness.ts
|
||||
src/main/codex-accounts/legacy-wsl-runtime-auth-drain-script-interference-shims.ts
|
||||
src/main/codex-accounts/service.ts
|
||||
src/main/codex/codex-app-server-client.ts
|
||||
src/main/codex/codex-app-server-posix-supervisor.ts
|
||||
src/main/codex/codex-app-server-session.ts
|
||||
src/main/codex/codex-state-db-backfill-recovery.ts
|
||||
|
||||
Reference in New Issue
Block a user