MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / startSidecar

Function startSidecar

apps/desktop/src/main/sidecar.ts:212–373  ·  view source on GitHub ↗
(options: StartOptions = {})

Source from the content-addressed store, hash-verified

210 new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
211
212export async function startSidecar(options: StartOptions = {}): Promise<SidecarConnection> {
213 const hostname = options.hostname ?? "127.0.0.1";
214 const settings = getServerSettings();
215 // data.db and the optional executor.jsonc plugin manifest live under
216 // ~/.executor — the same path the CLI's `executor web` uses. Desktop and CLI
217 // share state on the same machine so sources/secrets/policies set up in one
218 // show up in the other, and user-facing commands like
219 // `executor mcp --scope ~/.executor` stay copy-paste-friendly. Electron's
220 // userData (set in main/index.ts) is still used for electron-store,
221 // electron-log, and window-state — those stay app-scoped to avoid colliding
222 // with anything else under HOME.
223 const scopeDir = join(homedir(), ".executor");
224 const dataDir = scopeDir;
225 mkdirSync(dataDir, { recursive: true });
226
227 // The stable bearer token from auth.json (shared with the CLI). The main
228 // process holds it so it can inject the header into the webview; the child
229 // validates against the same value. Always present — auth is unconditional.
230 const authToken = loadOrMintLocalAuthToken(dataDir);
231 const { command, args, cwd, cliManagedManifest } = resolveSidecarCommand({
232 port: settings.port,
233 hostname,
234 authToken,
235 });
236 const clientDir = cliManagedManifest ? null : resolveClientDir();
237
238 if (!cliManagedManifest && clientDir && !existsSync(clientDir)) {
239 // oxlint-disable-next-line executor/no-error-constructor, executor/no-try-catch-or-throw -- boundary: startup failure is surfaced in the Electron main process
240 throw new Error(
241 `Executor client bundle not found at ${clientDir}. Run \`bun run --filter @executor-js/local build\` before launching desktop.`,
242 );
243 }
244
245 // No process-level startup lock: the dev sidecar child opens the DB through
246 // openOwnedLocalDatabase, whose ownership lock is the real gate. If the child
247 // loses the race, startup fails as before; only the packaged supervised boot
248 // path attaches to an existing daemon.
249 const webBaseUrl = `http://${hostname}:${settings.port}`;
250 const child = spawn(command, args, {
251 cwd,
252 stdio: ["ignore", "pipe", "pipe"],
253 env: {
254 ...process.env,
255 EXECUTOR_PORT: String(settings.port),
256 EXECUTOR_HOST: hostname,
257 EXECUTOR_WEB_BASE_URL: webBaseUrl,
258 PORT: String(settings.port),
259 // The bearer token the child validates and the main process injects into
260 // the webview. Always set — auth is unconditional.
261 EXECUTOR_AUTH_TOKEN: authToken,
262 ...(clientDir ? { EXECUTOR_CLIENT_DIR: clientDir } : {}),
263 EXECUTOR_SCOPE_DIR: scopeDir,
264 EXECUTOR_DATA_DIR: dataDir,
265 EXECUTOR_CLIENT: "desktop",
266 // Crash reporting (desktop builds with a baked-in DSN only). The
267 // CLI's `executor web` never sets these, so the shared server code
268 // stays telemetry-free outside the desktop app.
269 ...sidecarCrashReportingEnv(),

Callers 1

startWithCurrentSettingsFunction · 0.90

Calls 8

getServerSettingsFunction · 0.90
loadOrMintLocalAuthTokenFunction · 0.90
sidecarCrashReportingEnvFunction · 0.90
resolveSidecarCommandFunction · 0.85
resolveClientDirFunction · 0.85
makeLineSplitterFunction · 0.85
errorMethod · 0.80
infoMethod · 0.65

Tested by

no test coverage detected