Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
} from '@switch-console/core/deps/runtime';
import { agentTypeOf } from '@main/core/telemetry/agent-type';
import { cliFailureReason } from '@main/core/telemetry/cli-failure';
import { startTimer } from '@main/core/telemetry/duration';
import type { TelemetryCliAction } from '@main/core/telemetry/events';
import { installMethodOf } from '@main/core/telemetry/narrow';
import { trackEvent } from '@main/core/telemetry/telemetry-service';
Expand Down Expand Up @@ -43,7 +44,8 @@ function reportCliAction(
action: TelemetryCliAction,
id: string,
method: InstallMethod | undefined,
result: { success: boolean; error?: { type?: string } }
result: { success: boolean; error?: { type?: string } },
durationMs: number
): void {
trackEvent('agent_cli_action', {
agent_type: agentTypeOf(id),
Expand All @@ -52,6 +54,7 @@ function reportCliAction(
action,
outcome: result.success ? 'success' : 'failure',
failure_reason: cliFailureReason(result),
duration_ms: durationMs,
});
}

Expand Down Expand Up @@ -98,8 +101,12 @@ export const providersController = createRPCController({

install: async (id: AgentProviderId, connectionId?: string, method?: InstallMethod) => {
const mgr = await getDependencyManager(connectionId);
// Timed around the operation alone. Resolving the manager is a lookup that
// says nothing about how long an install takes, and including it would make
// the first measurement of a session differ from the rest for no reason.
const elapsed = startTimer();
const result = await mgr.install(id, method);
reportCliAction('install', id, method, result);
reportCliAction('install', id, method, result, elapsed());
if (result.success) {
// Persist the chosen method as an override, or clear to auto when no method was chosen.
// Do NOT auto-promote the inferred method — that would freeze a heuristic guess.
Expand All @@ -112,15 +119,17 @@ export const providersController = createRPCController({

update: async (id: AgentProviderId, connectionId?: string, method?: InstallMethod) => {
const mgr = await getDependencyManager(connectionId);
const elapsed = startTimer();
const result = await mgr.update(id, method);
reportCliAction('update', id, method, result);
reportCliAction('update', id, method, result, elapsed());
return result;
},

uninstall: async (id: AgentProviderId, connectionId?: string, method?: InstallMethod) => {
const mgr = await getDependencyManager(connectionId);
const elapsed = startTimer();
const result = await mgr.uninstall(id, method);
reportCliAction('uninstall', id, method, result);
reportCliAction('uninstall', id, method, result, elapsed());
return result;
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import { getRemoteSwitchSetupService } from '@main/core/switch-setup/remote-switch-setup';
import { agentTypeOf } from '@main/core/telemetry/agent-type';
import { cliFailureReason } from '@main/core/telemetry/cli-failure';
import { startTimer } from '@main/core/telemetry/duration';
import type { TelemetryCliAction } from '@main/core/telemetry/events';
import { installMethodOf } from '@main/core/telemetry/narrow';
import { trackEvent } from '@main/core/telemetry/telemetry-service';
Expand Down Expand Up @@ -102,7 +103,8 @@ function reportRemoteCliAction(
action: TelemetryCliAction,
id: string,
method: InstallMethod | undefined,
result: { success: boolean; error?: { type?: string } }
result: { success: boolean; error?: { type?: string } },
durationMs: number
): void {
trackEvent('agent_cli_action', {
agent_type: agentTypeOf(id),
Expand All @@ -111,6 +113,7 @@ function reportRemoteCliAction(
action,
outcome: result.success ? 'success' : 'failure',
failure_reason: cliFailureReason(result),
duration_ms: durationMs,
});
}

Expand Down Expand Up @@ -237,15 +240,20 @@ export const remoteHostsController = createRPCController({
method?: InstallMethod;
}): Promise<DependencyInstallResult> => {
const manager = await getRemoteDependencyManager(params.sshHost);
// Timed around the operation alone: resolving the manager may open the SSH
// connection, which is not part of how long an install takes and would show
// up only on the first one of a session.
const elapsed = startTimer();
const result = await manager.install(params.id, params.method);
reportRemoteCliAction('install', params.id, params.method, result);
reportRemoteCliAction('install', params.id, params.method, result, elapsed());
return result;
},

updateDep: async (params: { sshHost: string; id: string }): Promise<DependencyUpdateResult> => {
const manager = await getRemoteDependencyManager(params.sshHost);
const elapsed = startTimer();
const result = await manager.update(params.id);
reportRemoteCliAction('update', params.id, undefined, result);
reportRemoteCliAction('update', params.id, undefined, result, elapsed());
return result;
},

Expand All @@ -254,8 +262,9 @@ export const remoteHostsController = createRPCController({
id: string;
}): Promise<DependencyUninstallResult> => {
const manager = await getRemoteDependencyManager(params.sshHost);
const elapsed = startTimer();
const result = await manager.uninstall(params.id);
reportRemoteCliAction('uninstall', params.id, undefined, result);
reportRemoteCliAction('uninstall', params.id, undefined, result, elapsed());
return result;
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,9 @@ describe('RemoteSwitchSetupService.install', () => {
agent_type: 'codex',
target: 'remote',
outcome: 'success',
failure_reason: 'none',
// Elapsed wall time: a real number, but not one a test can pin.
duration_ms: expect.any(Number),
});
});

Expand All @@ -430,6 +433,8 @@ describe('RemoteSwitchSetupService.install', () => {
agent_type: 'codex',
target: 'remote',
outcome: 'failure',
failure_reason: 'install_command_failed',
duration_ms: expect.any(Number),
});
});

Expand Down Expand Up @@ -489,6 +494,8 @@ describe('RemoteSwitchSetupService.install', () => {
agent_type: 'opencode',
target: 'remote',
outcome: 'success',
failure_reason: 'none',
duration_ms: expect.any(Number),
});
});

Expand All @@ -503,6 +510,8 @@ describe('RemoteSwitchSetupService.install', () => {
agent_type: 'opencode',
target: 'remote',
outcome: 'failure',
failure_reason: 'files_write_failed',
duration_ms: expect.any(Number),
});
});

Expand All @@ -519,10 +528,14 @@ describe('RemoteSwitchSetupService.install', () => {
const result = await service.install('opencode');

expect(result.success).toBe(false);
// Its own code, not `files_write_failed`: a fault in the plugin rather
// than on the host, and the two would otherwise be one number.
expect(mocks.trackEvent).toHaveBeenCalledWith('connector_installed', {
agent_type: 'opencode',
target: 'remote',
outcome: 'failure',
failure_reason: 'files_unimplemented',
duration_ms: expect.any(Number),
});
});
});
Expand Down
Loading
Loading