(config: Config)
| 138 | public readonly agentStatusService: AgentStatusService; |
| 139 | |
| 140 | constructor(config: Config) { |
| 141 | this.config = config; |
| 142 | |
| 143 | // Cross-cutting services: created first so they can be passed to core |
| 144 | // services via constructor params (no setter injection needed). |
| 145 | this.policyService = new PolicyService(config); |
| 146 | this.telemetryService = new TelemetryService(config.rootDir); |
| 147 | this.experimentsService = new ExperimentsService({ |
| 148 | telemetryService: this.telemetryService, |
| 149 | muxHome: config.rootDir, |
| 150 | }); |
| 151 | this.sessionTimingService = new SessionTimingService(config, this.telemetryService); |
| 152 | this.analyticsService = new AnalyticsService(config); |
| 153 | this.devToolsService = new DevToolsService(config); |
| 154 | this.browserBridgeTokenManager = new BrowserBridgeTokenManager(); |
| 155 | |
| 156 | // Desktop passes WorkspaceMcpOverridesService explicitly so AIService uses |
| 157 | // the persistent config rather than creating a default with an ephemeral one. |
| 158 | this.workspaceMcpOverridesService = new WorkspaceMcpOverridesService(config); |
| 159 | |
| 160 | // 1Password integration — resolve references lazily so config updates are picked |
| 161 | // up without requiring an app restart. |
| 162 | const opResolver: ExternalSecretResolver = async (ref: string) => { |
| 163 | const service = this.onePasswordService; |
| 164 | if (!service) { |
| 165 | return undefined; |
| 166 | } |
| 167 | |
| 168 | return service.resolve(ref); |
| 169 | }; |
| 170 | |
| 171 | const core = createCoreServices({ |
| 172 | config, |
| 173 | extensionMetadataPath: path.join(config.rootDir, "extensionMetadata.json"), |
| 174 | workspaceMcpOverridesService: this.workspaceMcpOverridesService, |
| 175 | policyService: this.policyService, |
| 176 | telemetryService: this.telemetryService, |
| 177 | analyticsService: this.analyticsService, |
| 178 | experimentsService: this.experimentsService, |
| 179 | sessionTimingService: this.sessionTimingService, |
| 180 | devToolsService: this.devToolsService, |
| 181 | opResolver, |
| 182 | }); |
| 183 | |
| 184 | // Spread core services into class fields |
| 185 | this.historyService = core.historyService; |
| 186 | this.aiService = core.aiService; |
| 187 | this.aiService.setAnalyticsService(this.analyticsService); |
| 188 | this.browserSessionDiscoveryService = new AgentBrowserSessionDiscoveryService({ |
| 189 | resolveWorkspaceCandidatePathsFn: async (workspaceId: string) => { |
| 190 | const allWorkspaceMetadata = await config.getAllWorkspaceMetadata(); |
| 191 | const workspaceMetadata = |
| 192 | allWorkspaceMetadata.find((candidate) => candidate.id === workspaceId) ?? null; |
| 193 | if (workspaceMetadata == null) { |
| 194 | return []; |
| 195 | } |
| 196 | |
| 197 | const runtime = createRuntimeForWorkspace(workspaceMetadata); |
nothing calls this directly
no test coverage detected