From 5dbff5d8ea8929449f5448e4c75ea6410bfb72ed Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:29:13 -0700 Subject: [PATCH] Revert "Fix Claude PR hyperlinks in terminal" (#5826) --- src/main/daemon/pty-subprocess.ts | 17 +++++++++++++++-- src/main/ipc/pty.test.ts | 21 +++++++++++---------- src/main/providers/local-pty-provider.ts | 18 ++++++++++++++++-- src/relay/pty-handler.test.ts | 9 --------- src/relay/pty-handler.ts | 7 +------ src/shared/terminal-capability-env.test.ts | 18 ------------------ src/shared/terminal-capability-env.ts | 19 ------------------- 7 files changed, 43 insertions(+), 66 deletions(-) delete mode 100644 src/shared/terminal-capability-env.test.ts delete mode 100644 src/shared/terminal-capability-env.ts diff --git a/src/main/daemon/pty-subprocess.ts b/src/main/daemon/pty-subprocess.ts index 19726c7a9..769797ee9 100644 --- a/src/main/daemon/pty-subprocess.ts +++ b/src/main/daemon/pty-subprocess.ts @@ -21,7 +21,6 @@ import { resolveEffectiveWindowsPowerShell } from '../providers/windows-powershe import { isPwshAvailable } from '../pwsh' import { isHostCodexHomeForWsl, isWslCodexHomeForHost } from '../pty/codex-home-wsl-env' import { removeInheritedNoColor } from '../pty/terminal-color-env' -import { buildTerminalCapabilityEnv } from '../../shared/terminal-capability-env' import { parseWslPath } from '../wsl' import { addWslEnvKeys } from '../wsl-env' import { getWslContextFromSessionId } from './wsl-session-context' @@ -402,7 +401,21 @@ export function createPtySubprocess(opts: PtySubprocessOptions): SubprocessHandl const env: Record = { ...process.env, ...opts.env, - ...buildTerminalCapabilityEnv(process.env.ORCA_APP_VERSION ?? '0.0.0-dev') + TERM: 'xterm-256color', + COLORTERM: 'truecolor', + TERM_PROGRAM: 'Orca', + // Why: TUIs feature-gate on TERM_PROGRAM_VERSION. The daemon is forked + // by main (daemon-init.ts:93) with the parent's env, so ORCA_APP_VERSION + // — set in src/main/index.ts from app.getVersion() — is inherited here. + TERM_PROGRAM_VERSION: process.env.ORCA_APP_VERSION ?? '0.0.0-dev', + // Why: opt tools (Claude Code, ls --hyperlink, etc.) into emitting OSC 8 + // hyperlinks. The `supports-hyperlinks` npm package gates on a hard-coded + // TERM_PROGRAM allowlist (iTerm.app / WezTerm / vscode) and returns false + // for TERM_PROGRAM=Orca, so callers drop OSC 8 output entirely and emit + // bare text instead. xterm.js in Orca parses OSC 8 and the pane's + // linkHandler routes clicks, so forcing the advertisement is safe and + // restores clickable refs like `owner/repo#123` / `PR#123`. + FORCE_HYPERLINK: '1' } as Record for (const key of opts.envToDelete ?? []) { delete env[key] diff --git a/src/main/ipc/pty.test.ts b/src/main/ipc/pty.test.ts index 67185ee15..e27685f05 100644 --- a/src/main/ipc/pty.test.ts +++ b/src/main/ipc/pty.test.ts @@ -629,30 +629,31 @@ describe('registerPtyHandlers', () => { expect(env.LANG).toBe('fr_FR.UTF-8') }) - it('advertises xterm.js-compatible terminal capabilities while preserving Orca identity', async () => { + it('always sets TERM and COLORTERM regardless of env', async () => { const env = await spawnAndGetEnv() expect(env.TERM).toBe('xterm-256color') expect(env.COLORTERM).toBe('truecolor') - expect(env.TERM_PROGRAM).toBe('vscode') - expect(env.TERM_PROGRAM_VERSION).toBe('1.100.0') - expect(env.ORCA_TERM_PROGRAM).toBe('Orca') + expect(env.TERM_PROGRAM).toBe('Orca') }) it('advertises OSC 8 hyperlink support via FORCE_HYPERLINK', async () => { - // Why: some hyperlink detectors still miss Electron embedders even with - // xterm.js-compatible TERM_PROGRAM values; Orca routes OSC 8 natively. + // Why: the supports-hyperlinks npm package hard-codes a TERM_PROGRAM + // allowlist (iTerm.app / WezTerm / vscode) and reports false for + // TERM_PROGRAM=Orca, so tools like Claude Code emit plain text instead + // of ESC]8;; wrappers. Setting FORCE_HYPERLINK=1 forces the detector to + // return true; xterm.js + our linkHandler handle the sequences natively. const env = await spawnAndGetEnv() expect(env.FORCE_HYPERLINK).toBe('1') }) - it('surfaces ORCA_APP_VERSION as ORCA_TERM_PROGRAM_VERSION for Orca identity', async () => { + it('surfaces ORCA_APP_VERSION as TERM_PROGRAM_VERSION for TUI feature gating', async () => { const env = await spawnAndGetEnv(undefined, { ORCA_APP_VERSION: '1.2.3-test' }) - expect(env.ORCA_TERM_PROGRAM_VERSION).toBe('1.2.3-test') + expect(env.TERM_PROGRAM_VERSION).toBe('1.2.3-test') }) - it('falls back to a placeholder Orca version when ORCA_APP_VERSION is unset', async () => { + it('falls back to a placeholder version when ORCA_APP_VERSION is unset', async () => { const env = await spawnAndGetEnv(undefined, { ORCA_APP_VERSION: undefined }) - expect(env.ORCA_TERM_PROGRAM_VERSION).toBe('0.0.0-dev') + expect(env.TERM_PROGRAM_VERSION).toBe('0.0.0-dev') }) it('injects the selected Codex home into Orca terminal PTYs', async () => { diff --git a/src/main/providers/local-pty-provider.ts b/src/main/providers/local-pty-provider.ts index 410d41e6b..142548390 100644 --- a/src/main/providers/local-pty-provider.ts +++ b/src/main/providers/local-pty-provider.ts @@ -31,7 +31,6 @@ import { STARTUP_COMMAND_READY_MAX_WAIT_MS } from './local-pty-shell-ready' import { removeInheritedNoColor } from '../pty/terminal-color-env' -import { buildTerminalCapabilityEnv } from '../../shared/terminal-capability-env' import { isHostCodexHomeForWsl, isWslCodexHomeForHost } from '../pty/codex-home-wsl-env' import { addWslEnvKeys } from '../wsl-env' import { @@ -407,7 +406,22 @@ export class LocalPtyProvider implements IPtyProvider { const spawnEnv: Record = { ...process.env, ...args.env, - ...buildTerminalCapabilityEnv(process.env.ORCA_APP_VERSION ?? '0.0.0-dev') + TERM: 'xterm-256color', + COLORTERM: 'truecolor', + TERM_PROGRAM: 'Orca', + // Why: TUIs feature-gate on TERM_PROGRAM_VERSION (Neovim's termcap + // autodetection, bat/delta paging hints). Sourced from ORCA_APP_VERSION + // which main/index.ts seeds from app.getVersion() at startup; the + // fallback keeps tests and non-Electron runs working. + TERM_PROGRAM_VERSION: process.env.ORCA_APP_VERSION ?? '0.0.0-dev', + // Why: opt tools (Claude Code, ls --hyperlink, etc.) into emitting OSC 8 + // hyperlinks. The `supports-hyperlinks` npm package gates on a hard-coded + // TERM_PROGRAM allowlist (iTerm.app / WezTerm / vscode) and returns false + // for TERM_PROGRAM=Orca, so callers drop OSC 8 output entirely and emit + // bare text instead. xterm.js in Orca parses OSC 8 and the pane's + // linkHandler routes clicks, so forcing the advertisement is safe and + // restores clickable refs like `owner/repo#123` / `PR#123`. + FORCE_HYPERLINK: '1' } as Record // Why: Orca can be launched from an Orca terminal while developing. Pane // identity belongs to the child PTY, not the parent shell that spawned app. diff --git a/src/relay/pty-handler.test.ts b/src/relay/pty-handler.test.ts index 61d5f5b92..983ac2348 100644 --- a/src/relay/pty-handler.test.ts +++ b/src/relay/pty-handler.test.ts @@ -162,15 +162,6 @@ describe('PtyHandler', () => { const result = await dispatcher.callRequest('pty.spawn', { cols: 80, rows: 24 }) expect(result).toEqual({ id: 'pty-1' }) expect(mockPtySpawn).toHaveBeenCalled() - const spawnOptions = mockPtySpawn.mock.calls[0]?.[2] - expect(spawnOptions?.env).toMatchObject({ - TERM: 'xterm-256color', - COLORTERM: 'truecolor', - TERM_PROGRAM: 'vscode', - TERM_PROGRAM_VERSION: '1.100.0', - ORCA_TERM_PROGRAM: 'Orca', - FORCE_HYPERLINK: '1' - }) expect(handler.activePtyCount).toBe(1) }) diff --git a/src/relay/pty-handler.ts b/src/relay/pty-handler.ts index bcc21f8c6..b1419e2fa 100644 --- a/src/relay/pty-handler.ts +++ b/src/relay/pty-handler.ts @@ -13,7 +13,6 @@ import { import { getRelayShellLaunchConfig } from './pty-shell-launch' import { DEFAULT_SSH_RELAY_GRACE_PERIOD_SECONDS } from '../shared/ssh-types' import { shouldUseShellReadyStartupDelivery } from '../shared/codex-startup-delivery' -import { buildTerminalCapabilityEnv } from '../shared/terminal-capability-env' // Why: node-pty is a native addon that may not be installed on the remote. // Dynamic import keeps the require() lazy so loadPty() returns null gracefully @@ -209,11 +208,7 @@ export class PtyHandler { rendererEnv: Record | undefined, ctx: { id: string; paneKey?: string; shell: string; command?: string } ): Record { - const baseEnv = { - ...process.env, - ...rendererEnv, - ...buildTerminalCapabilityEnv(process.env.ORCA_APP_VERSION ?? '0.0.0-dev') - } as Record + const baseEnv = { ...process.env, ...rendererEnv } as Record const augmented: Record = {} for (const augmenter of this.envAugmenters) { try { diff --git a/src/shared/terminal-capability-env.test.ts b/src/shared/terminal-capability-env.test.ts deleted file mode 100644 index bfff4f2d5..000000000 --- a/src/shared/terminal-capability-env.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildTerminalCapabilityEnv } from './terminal-capability-env' - -describe('buildTerminalCapabilityEnv', () => { - it('advertises xterm.js-compatible hyperlink capabilities and Orca identity', () => { - const env = buildTerminalCapabilityEnv('1.2.3') - - expect(env).toEqual({ - TERM: 'xterm-256color', - COLORTERM: 'truecolor', - TERM_PROGRAM: 'vscode', - TERM_PROGRAM_VERSION: '1.100.0', - ORCA_TERM_PROGRAM: 'Orca', - ORCA_TERM_PROGRAM_VERSION: '1.2.3', - FORCE_HYPERLINK: '1' - }) - }) -}) diff --git a/src/shared/terminal-capability-env.ts b/src/shared/terminal-capability-env.ts deleted file mode 100644 index 30d7bef5d..000000000 --- a/src/shared/terminal-capability-env.ts +++ /dev/null @@ -1,19 +0,0 @@ -const XTERM_JS_COMPATIBLE_TERM_PROGRAM = 'vscode' -const XTERM_JS_COMPATIBLE_TERM_PROGRAM_VERSION = '1.100.0' - -export function buildTerminalCapabilityEnv(appVersion: string): Record { - return { - TERM: 'xterm-256color', - COLORTERM: 'truecolor', - // Why: Claude Code and other CLIs gate OSC 8 links on known xterm.js - // embedders. Do not change this back to "Orca": that makes PR links - // render as plain text. ORCA_* keeps our real app identity available. - TERM_PROGRAM: XTERM_JS_COMPATIBLE_TERM_PROGRAM, - TERM_PROGRAM_VERSION: XTERM_JS_COMPATIBLE_TERM_PROGRAM_VERSION, - ORCA_TERM_PROGRAM: 'Orca', - ORCA_TERM_PROGRAM_VERSION: appVersion, - // Why: supports-hyperlinks can still miss Electron embedders; force OSC 8 - // output because Orca parses and routes those links natively. - FORCE_HYPERLINK: '1' - } -}