diff --git a/test/main/features/runtime-provider-management/AgentTeamsRuntimeProviderManagementCliClient.test.ts b/test/main/features/runtime-provider-management/AgentTeamsRuntimeProviderManagementCliClient.test.ts index 20d00cca..351256a4 100644 --- a/test/main/features/runtime-provider-management/AgentTeamsRuntimeProviderManagementCliClient.test.ts +++ b/test/main/features/runtime-provider-management/AgentTeamsRuntimeProviderManagementCliClient.test.ts @@ -3,6 +3,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; const buildProviderAwareCliEnvMock = vi.fn(); const resolveBinaryMock = vi.fn(); const execCliMock = vi.fn(); +const spawnCliMock = vi.fn(); const resolveInteractiveShellEnvMock = vi.fn(); vi.mock('@main/services/runtime/providerAwareCliEnv', () => ({ @@ -17,7 +18,7 @@ vi.mock('@main/services/team/ClaudeBinaryResolver', () => ({ vi.mock('@main/utils/childProcess', () => ({ execCli: (...args: unknown[]) => execCliMock(...args), - spawnCli: vi.fn(), + spawnCli: (...args: unknown[]) => spawnCliMock(...args), killProcessTree: vi.fn(), })); @@ -86,4 +87,41 @@ describe('AgentTeamsRuntimeProviderManagementCliClient', () => { 'Provider opencode must be connected before testing a model' ); }); + + it('passes project path as cwd and CLI flag for project-aware provider management', async () => { + execCliMock.mockResolvedValue({ + stdout: JSON.stringify({ + schemaVersion: 1, + runtimeId: 'opencode', + view: { + runtimeId: 'opencode', + title: 'OpenCode', + runtime: { + state: 'ready', + cliPath: '/opt/homebrew/bin/opencode', + version: '1.0.0', + managedProfile: 'active', + localAuth: 'synced', + }, + providers: [], + defaultModel: null, + fallbackModel: null, + diagnostics: [], + }, + }), + stderr: '', + }); + + const client = new AgentTeamsRuntimeProviderManagementCliClient(); + await client.loadView({ + runtimeId: 'opencode', + projectPath: '/Users/test/project', + }); + + expect(execCliMock).toHaveBeenCalledWith( + '/repo/cli-dev', + expect.arrayContaining(['--project-path', '/Users/test/project']), + expect.objectContaining({ cwd: '/Users/test/project' }) + ); + }); }); diff --git a/test/renderer/components/runtime/ProviderRuntimeSettingsDialog.test.ts b/test/renderer/components/runtime/ProviderRuntimeSettingsDialog.test.ts index ab517ea9..79d9ed35 100644 --- a/test/renderer/components/runtime/ProviderRuntimeSettingsDialog.test.ts +++ b/test/renderer/components/runtime/ProviderRuntimeSettingsDialog.test.ts @@ -67,10 +67,12 @@ vi.mock('@features/runtime-provider-management/renderer', () => ({ runtimeId, open, disabled, + projectPath, }: { runtimeId: string; open: boolean; disabled?: boolean; + projectPath?: string | null; }) => React.createElement( 'section', @@ -79,6 +81,7 @@ vi.mock('@features/runtime-provider-management/renderer', () => ({ 'data-runtime-id': runtimeId, 'data-open': String(open), 'data-disabled': String(Boolean(disabled)), + 'data-project-path': projectPath ?? '', }, `Runtime provider management: ${runtimeId}` ), @@ -1453,6 +1456,7 @@ describe('ProviderRuntimeSettingsDialog', () => { onOpenChange: vi.fn(), providers: [createOpenCodeProvider()], initialProviderId: 'opencode', + projectPath: '/tmp/project-a', onSelectBackend: vi.fn(), onRefreshProvider: vi.fn(() => Promise.resolve(undefined)), }) @@ -1464,6 +1468,7 @@ describe('ProviderRuntimeSettingsDialog', () => { expect(panel).not.toBeNull(); expect(panel?.getAttribute('data-runtime-id')).toBe('opencode'); expect(panel?.getAttribute('data-open')).toBe('true'); + expect(panel?.getAttribute('data-project-path')).toBe('/tmp/project-a'); expect(host.textContent).toContain('Runtime provider management: opencode'); expect(host.textContent).not.toContain('Desktop currently exposes status only.'); }); diff --git a/test/renderer/features/runtime-provider-management/useRuntimeProviderManagement.test.ts b/test/renderer/features/runtime-provider-management/useRuntimeProviderManagement.test.ts index e544447c..fb591286 100644 --- a/test/renderer/features/runtime-provider-management/useRuntimeProviderManagement.test.ts +++ b/test/renderer/features/runtime-provider-management/useRuntimeProviderManagement.test.ts @@ -41,6 +41,17 @@ describe('useRuntimeProviderManagement', () => { return React.createElement('div'); } + function EnabledHarness(props: { projectPath?: string | null }): React.ReactElement { + const hook = useRuntimeProviderManagement({ + runtimeId: 'opencode', + enabled: true, + projectPath: props.projectPath, + }); + state = hook[0]; + actions = hook[1]; + return React.createElement('div'); + } + beforeEach(() => { vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); host = document.createElement('div'); @@ -74,6 +85,49 @@ describe('useRuntimeProviderManagement', () => { expect(getStoredCreateTeamModel('opencode')).toBe(modelId); }); + it('passes projectPath to the runtime provider management API', async () => { + const loadView = vi.fn(() => + Promise.resolve({ + schemaVersion: 1, + runtimeId: 'opencode', + view: { + runtimeId: 'opencode', + title: 'OpenCode', + runtime: { + state: 'ready', + cliPath: '/opt/homebrew/bin/opencode', + version: '1.0.0', + managedProfile: 'active', + localAuth: 'synced', + }, + providers: [], + defaultModel: null, + fallbackModel: null, + diagnostics: [], + }, + }) + ); + Object.defineProperty(window, 'electronAPI', { + configurable: true, + value: { + runtimeProviderManagement: { + loadView, + }, + } as unknown as ElectronAPI, + }); + + const root = createRoot(host); + await act(async () => { + root.render(React.createElement(EnabledHarness, { projectPath: '/tmp/project-a' })); + await Promise.resolve(); + }); + + expect(loadView).toHaveBeenCalledWith({ + runtimeId: 'opencode', + projectPath: '/tmp/project-a', + }); + }); + it('keeps failed model probes scoped to the model result instead of a global success banner', async () => { const modelId = 'openrouter/anthropic/claude-3.5-haiku'; const message =