()
| 115 | } |
| 116 | |
| 117 | async function main(): Promise<void> { |
| 118 | const daemonBootstrapStart = Date.now(); |
| 119 | const result = await bootstrapRuntime({ |
| 120 | runtime: 'daemon', |
| 121 | configOverrides: { |
| 122 | disableSessionDefaults: true, |
| 123 | }, |
| 124 | }); |
| 125 | |
| 126 | const { workspaceRoot, workspaceKey } = result; |
| 127 | const daemonInstanceId = randomUUID(); |
| 128 | |
| 129 | const logPath = resolveDaemonLogPath(workspaceKey); |
| 130 | if (logPath) { |
| 131 | ensureLogDir(logPath); |
| 132 | rotateLogIfNeeded(logPath); |
| 133 | setLogFile(logPath); |
| 134 | |
| 135 | setLogLevel(resolveLogLevel() ?? 'info'); |
| 136 | } |
| 137 | |
| 138 | await hydrateSentryDisabledEnvFromProjectConfig({ |
| 139 | cwd: result.runtime.cwd, |
| 140 | }); |
| 141 | initSentry({ mode: 'cli-daemon' }); |
| 142 | recordDaemonLifecycleMetric('start'); |
| 143 | |
| 144 | log('info', `[Daemon] xcodebuildmcp daemon ${version} starting...`); |
| 145 | |
| 146 | const socketPath = getSocketPath({ |
| 147 | cwd: result.runtime.cwd, |
| 148 | projectConfigPath: result.configPath, |
| 149 | }); |
| 150 | |
| 151 | log('info', `[Daemon] Workspace: ${workspaceRoot}`); |
| 152 | log('info', `[Daemon] Socket: ${socketPath}`); |
| 153 | |
| 154 | const runStartupLifecycleSweep = async (): Promise<void> => { |
| 155 | try { |
| 156 | const lifecycle = await runWorkspaceFilesystemLifecycleSweep({ |
| 157 | workspaceKey, |
| 158 | trigger: 'startup', |
| 159 | }); |
| 160 | if (lifecycle.stopped > 0 || lifecycle.deleted > 0 || lifecycle.errors.length > 0) { |
| 161 | log( |
| 162 | lifecycle.errors.length > 0 ? 'warn' : 'info', |
| 163 | `[Daemon] Filesystem lifecycle: ${JSON.stringify(lifecycle)}`, |
| 164 | ); |
| 165 | } |
| 166 | } catch (error) { |
| 167 | log( |
| 168 | 'warn', |
| 169 | `[Daemon] Filesystem lifecycle failed: ${error instanceof Error ? error.message : String(error)}`, |
| 170 | ); |
| 171 | } |
| 172 | }; |
| 173 | |
| 174 | if (logPath) { |
no test coverage detected