mirror of
https://github.com/stablyai/orca.git
synced 2026-10-26 08:02:44 +00:00
Diagnose Claude launches using Orca proxy
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { warnIfConfiguredClaudeProxy } from './claude-launch-proxy-notice'
|
||||
|
||||
const warning = vi.hoisted(() => vi.fn())
|
||||
vi.mock('sonner', () => ({ toast: { warning } }))
|
||||
|
||||
describe('warnIfConfiguredClaudeProxy', () => {
|
||||
beforeEach(() => warning.mockClear())
|
||||
|
||||
it('explains the configured proxy for Claude launches', () => {
|
||||
warnIfConfiguredClaudeProxy('claude', { httpProxyUrl: 'http://127.0.0.1:9' })
|
||||
expect(warning).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
'target host is routed through it unless covered by its bypass rules'
|
||||
),
|
||||
{
|
||||
duration: 12_000
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('does not warn for agents without a configured proxy', () => {
|
||||
warnIfConfiguredClaudeProxy('codex', { httpProxyUrl: 'http://127.0.0.1:9' })
|
||||
warnIfConfiguredClaudeProxy('claude', {})
|
||||
expect(warning).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
import { toast } from 'sonner'
|
||||
import type { TuiAgent } from '../../../shared/tui-agent'
|
||||
|
||||
type ProxySettings = { httpProxyUrl?: string }
|
||||
|
||||
/** Explain the app-level proxy context before a Claude process makes its first request. */
|
||||
export function warnIfConfiguredClaudeProxy(
|
||||
agent: TuiAgent,
|
||||
settings: ProxySettings | null | undefined
|
||||
): void {
|
||||
if (agent !== 'claude' || !settings?.httpProxyUrl?.trim()) {
|
||||
return
|
||||
}
|
||||
toast.warning(
|
||||
'Orca network proxy is configured for this Claude launch; the target host is routed through it unless covered by its bypass rules. If Claude reports ConnectionRefused, check Settings → Advanced → Network.',
|
||||
{ duration: 12_000 }
|
||||
)
|
||||
}
|
||||
@@ -13,6 +13,7 @@ const mockSeedNativeChatLaunchDraft = vi.fn()
|
||||
const mockMarkNativeChatLaunchPromptFailed = vi.fn()
|
||||
const mockTrack = vi.fn()
|
||||
const mockToastMessage = vi.fn()
|
||||
const mockToastWarning = vi.fn()
|
||||
|
||||
const LEAF_ID = '11111111-1111-4111-8111-111111111111'
|
||||
|
||||
@@ -93,9 +94,8 @@ vi.mock('@/store', () => ({
|
||||
}))
|
||||
|
||||
const mockToastError = vi.fn()
|
||||
|
||||
vi.mock('sonner', () => ({
|
||||
toast: { message: mockToastMessage, error: mockToastError }
|
||||
toast: { message: mockToastMessage, error: mockToastError, warning: mockToastWarning }
|
||||
}))
|
||||
|
||||
vi.mock('@/components/tab-bar/reconcile-order', () => ({
|
||||
@@ -173,6 +173,16 @@ describe('launchAgentInNewTab', () => {
|
||||
mockPasteDraftWhenAgentReady.mockResolvedValue(true)
|
||||
})
|
||||
|
||||
it('does not attribute a local proxy to Claude launches on SSH hosts', async () => {
|
||||
Reflect.set(store.settings, 'httpProxyUrl', 'http://127.0.0.1:9')
|
||||
store.repos = [{ id: 'repo-1', connectionId: 'ssh-target-1', path: '/repo' }]
|
||||
const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab')
|
||||
|
||||
launchAgentInNewTab({ agent: 'claude', worktreeId: 'wt-1' })
|
||||
|
||||
expect(mockToastWarning).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('stamps the launched agent on the new tab for immediate provider icon bootstrap', async () => {
|
||||
const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab')
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import type { LaunchSource } from '../../../shared/telemetry-events'
|
||||
import { getConnectionIdFromState } from '@/lib/connection-context'
|
||||
import { resolveInitialNativeChatSessionOptions } from '@/components/native-chat/native-chat-launch-session-options'
|
||||
import { seedNativeChatAppliedSessionOptions } from '@/components/native-chat/native-chat-session-option-cache'
|
||||
import { warnIfConfiguredClaudeProxy } from '@/lib/claude-launch-proxy-notice'
|
||||
|
||||
export type LaunchAgentInNewTabArgs = {
|
||||
agent: TuiAgent
|
||||
@@ -173,6 +174,11 @@ export function launchAgentInNewTab(args: LaunchAgentInNewTabArgs): LaunchAgentI
|
||||
}
|
||||
}
|
||||
|
||||
// The app-level proxy is injected into local PTYs (including WSL), not SSH or paired web hosts.
|
||||
if (!isRemote) {
|
||||
warnIfConfiguredClaudeProxy(agent, store.settings)
|
||||
}
|
||||
|
||||
// Why: queue startup BEFORE TerminalPane mounts — it snapshots pendingStartupByTabId in useState on first render.
|
||||
// Why: followup path pastes an unsubmitted draft, so gate the initial chat view like a draft launch, not auto-submit.
|
||||
const tab = store.createTab(worktreeId, groupId, undefined, {
|
||||
|
||||
Reference in New Issue
Block a user