Skip to content

Commit 9044daf

Browse files
committed
♻️ refactor(logger): rename 'warning' log level to 'warn' and add normalizeLogLevel
Align internal log level naming with Sentry SDK conventions ('warn' instead of 'warning'). Add normalizeLogLevel() to safely map external level strings (including MCP protocol's 'warning') to internal LogLevel values. Also removes the CLI daemon logLevel passthrough (debug flag no longer overrides daemon log level) and filters 'log-level' from tool command args.
1 parent 71bc636 commit 9044daf

32 files changed

Lines changed: 87 additions & 103 deletions

src/cli.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ async function buildLightweightYargsApp(): Promise<ReturnType<typeof import('yar
4848
.option('log-level', {
4949
type: 'string',
5050
describe: 'Set log verbosity level',
51-
choices: ['none', 'error', 'warning', 'info', 'debug'] as const,
51+
choices: ['none', 'error', 'warn', 'info', 'debug'] as const,
5252
default: 'none',
5353
})
5454
.option('style', {
@@ -133,7 +133,6 @@ async function main(): Promise<void> {
133133
socketPath: defaultSocketPath,
134134
workspaceRoot,
135135
cliExposedWorkflowIds,
136-
logLevel: result.runtime.config.debug ? 'info' : undefined,
137136
discoveryMode,
138137
});
139138

src/cli/cli-tool-catalog.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ interface BuildCliToolCatalogOptions {
1515
socketPath: string;
1616
workspaceRoot: string;
1717
cliExposedWorkflowIds: string[];
18-
logLevel?: string;
1918
discoveryMode?: 'none' | 'quick';
2019
}
2120

@@ -50,16 +49,6 @@ function jsonSchemaToToolSchemaShape(inputSchema: unknown): ToolSchemaShape {
5049
return shape;
5150
}
5251

53-
function buildDaemonEnvOverrides(opts: BuildCliToolCatalogOptions): Record<string, string> {
54-
const env: Record<string, string> = {};
55-
56-
if (opts.logLevel) {
57-
env.XCODEBUILDMCP_DAEMON_LOG_LEVEL = opts.logLevel;
58-
}
59-
60-
return env;
61-
}
62-
6352
async function invokeRemoteToolOneShot(
6453
remoteToolName: string,
6554
args: Record<string, unknown>,
@@ -123,11 +112,10 @@ async function loadDaemonBackedXcodeProxyTools(
123112
startDaemonBackground({
124113
socketPath: opts.socketPath,
125114
workspaceRoot: opts.workspaceRoot,
126-
env: buildDaemonEnvOverrides(opts),
127115
});
128116
} catch (startError) {
129117
const message = startError instanceof Error ? startError.message : String(startError);
130-
log('warning', `[xcode-ide] Failed to start daemon in background: ${message}`);
118+
log('warn', `[xcode-ide] Failed to start daemon in background: ${message}`);
131119
}
132120
return [];
133121
}
@@ -149,7 +137,7 @@ async function loadDaemonBackedXcodeProxyTools(
149137
} catch (error) {
150138
const message = error instanceof Error ? error.message : String(error);
151139
if (quickMode) {
152-
log('warning', `[xcode-ide] CLI daemon-backed bridge discovery failed: ${message}`);
140+
log('warn', `[xcode-ide] CLI daemon-backed bridge discovery failed: ${message}`);
153141
} else {
154142
log('debug', `[xcode-ide] CLI cached bridge discovery skipped: ${message}`);
155143
}

src/cli/commands/daemon.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export function registerDaemonCommands(app: Argv, opts: DaemonCommandsOptions):
4848
'alert',
4949
'critical',
5050
'error',
51-
'warning',
51+
'warn',
5252
'notice',
5353
'info',
5454
'debug',

src/cli/register-tool-commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ function registerToolSubcommand(
162162

163163
// Convert CLI argv to tool params (kebab-case -> camelCase)
164164
// Filter out internal CLI options before converting
165-
const internalKeys = new Set(['json', 'output', 'style', 'socket', '_', '$0']);
165+
const internalKeys = new Set(['json', 'output', 'style', 'socket', 'log-level', '_', '$0']);
166166
const flagArgs: Record<string, unknown> = {};
167167
for (const [key, value] of Object.entries(argv as Record<string, unknown>)) {
168168
if (!internalKeys.has(key)) {

src/cli/yargs-app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export function buildYargsApp(opts: YargsAppOptions): ReturnType<typeof yargs> {
4444
.option('log-level', {
4545
type: 'string',
4646
describe: 'Set log verbosity level',
47-
choices: ['none', 'error', 'warning', 'info', 'debug'] as const,
47+
choices: ['none', 'error', 'warn', 'info', 'debug'] as const,
4848
default: 'none',
4949
})
5050
.option('style', {

src/daemon.ts

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
removeDaemonRegistryEntry,
2020
cleanupWorkspaceDaemonFiles,
2121
} from './daemon/daemon-registry.ts';
22-
import { log, setLogFile, setLogLevel, type LogLevel } from './utils/logger.ts';
22+
import { log, normalizeLogLevel, setLogFile, setLogLevel } from './utils/logger.ts';
2323
import { version } from './version.ts';
2424
import {
2525
DAEMON_IDLE_TIMEOUT_ENV_KEY,
@@ -102,29 +102,12 @@ function ensureLogDir(logPath: string): void {
102102
}
103103
}
104104

105-
function resolveLogLevel(): LogLevel | null {
106-
const raw = process.env.XCODEBUILDMCP_DAEMON_LOG_LEVEL?.trim().toLowerCase();
105+
function resolveLogLevel(): ReturnType<typeof normalizeLogLevel> {
106+
const raw = process.env.XCODEBUILDMCP_DAEMON_LOG_LEVEL;
107107
if (!raw) {
108108
return null;
109109
}
110-
111-
const knownLevels: LogLevel[] = [
112-
'none',
113-
'emergency',
114-
'alert',
115-
'critical',
116-
'error',
117-
'warning',
118-
'notice',
119-
'info',
120-
'debug',
121-
];
122-
123-
if (knownLevels.includes(raw as LogLevel)) {
124-
return raw as LogLevel;
125-
}
126-
127-
return null;
110+
return normalizeLogLevel(raw);
128111
}
129112

130113
async function main(): Promise<void> {
@@ -315,7 +298,7 @@ async function main(): Promise<void> {
315298

316299
// Force exit if server doesn't close in time
317300
setTimeout(() => {
318-
log('warning', '[Daemon] Forced shutdown after timeout');
301+
log('warn', '[Daemon] Forced shutdown after timeout');
319302
cleanupWorkspaceDaemonFiles(workspaceKey);
320303
void flushAndCloseSentry(1000).finally(() => {
321304
process.exit(1);
@@ -408,7 +391,7 @@ async function main(): Promise<void> {
408391
setImmediate(() => {
409392
void enrichSentryMetadata().catch((error) => {
410393
const message = error instanceof Error ? error.message : String(error);
411-
log('warning', `[Daemon] Failed to enrich Sentry metadata: ${message}`);
394+
log('warn', `[Daemon] Failed to enrich Sentry metadata: ${message}`);
412395
});
413396
});
414397
});

src/daemon/daemon-server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ export function startDaemonServer(ctx: DaemonServerContext): net.Server {
212212
}
213213
},
214214
(err) => {
215-
log('warning', `[Daemon] Frame parse error: ${err.message}`);
215+
log('warn', `[Daemon] Frame parse error: ${err.message}`);
216216
},
217217
);
218218

@@ -221,12 +221,12 @@ export function startDaemonServer(ctx: DaemonServerContext): net.Server {
221221
log('info', '[Daemon] Client disconnected');
222222
});
223223
socket.on('error', (err) => {
224-
log('warning', `[Daemon] Socket error: ${err.message}`);
224+
log('warn', `[Daemon] Socket error: ${err.message}`);
225225
});
226226
});
227227

228228
server.on('error', (err) => {
229-
log('warning', `[Daemon] Server error: ${err.message}`);
229+
log('warn', `[Daemon] Server error: ${err.message}`);
230230
});
231231
server.on('close', () => {
232232
void xcodeIdeService.disconnect();

src/mcp/tools/logging/stop_device_log_cap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export async function stop_device_log_capLogic(
3535

3636
const session = activeDeviceLogSessions.get(logSessionId);
3737
if (!session) {
38-
log('warning', `Device log session not found: ${logSessionId}`);
38+
log('warn', `Device log session not found: ${logSessionId}`);
3939
return {
4040
content: [
4141
{

src/mcp/tools/project-discovery/discover_projs.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,7 @@ async function _findProjectsRecursive(
131131
if (code === 'EPERM' || code === 'EACCES') {
132132
log('debug', `Permission denied scanning directory: ${currentDirAbs}`);
133133
} else {
134-
log(
135-
'warning',
136-
`Error scanning directory ${currentDirAbs}: ${message} (Code: ${code ?? 'N/A'})`,
137-
);
134+
log('warn', `Error scanning directory ${currentDirAbs}: ${message} (Code: ${code ?? 'N/A'})`);
138135
}
139136
}
140137
}

src/mcp/tools/simulator/build_run_sim.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ async function _handleSimulatorBuildLogic(
9191
// Log warning if useLatestOS is provided with simulatorId
9292
if (params.simulatorId && params.useLatestOS !== undefined) {
9393
log(
94-
'warning',
94+
'warn',
9595
`useLatestOS parameter is ignored when using simulatorId (UUID implies exact device/OS)`,
9696
);
9797
}
@@ -270,7 +270,7 @@ export async function build_run_simLogic(
270270
}
271271

272272
if (uuidResult.warning) {
273-
log('warning', uuidResult.warning);
273+
log('warn', uuidResult.warning);
274274
}
275275

276276
const simulatorId = uuidResult.uuid;
@@ -364,7 +364,7 @@ export async function build_run_simLogic(
364364
}
365365
} catch (error) {
366366
const errorMessage = error instanceof Error ? error.message : String(error);
367-
log('warning', `Warning: Could not open Simulator app: ${errorMessage}`);
367+
log('warn', `Warning: Could not open Simulator app: ${errorMessage}`);
368368
// Don't fail the whole operation for this
369369
}
370370

0 commit comments

Comments
 (0)