Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

### Fixed

- Clarified `debug_attach_sim` PID attach arguments so the schema documents that `pid` must be used without `bundleId` or `waitFor`, and invalid `pid` + `waitFor: true` calls now fail validation before LLDB is invoked ([#417](https://github.com/getsentry/XcodeBuildMCP/issues/417)).
- Fixed Claude UI benchmark preflight so transient malformed or still-loading UI snapshots no longer crash the harness or finish before app UI is observable.
- Fixed Claude UI benchmark preflight so configured first-run dismissals require a concrete simulator ID, suite-provided simulator IDs are recorded in command logs, and preflight-launched apps are terminated after post-launch failures.
- Fixed Claude UI benchmark config handling so invalid `failurePatterns` regexes and runtime-incompatible `sessionDefaults` fail before a suite starts and partial `allowedVariance` overrides preserve defaults for omitted metrics.
Expand Down
34 changes: 34 additions & 0 deletions src/mcp/tools/debugging/__tests__/debugging-tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ describe('debug_attach_sim', () => {
it('should expose schema with expected shape', () => {
expect(attachSchema).toBeDefined();
});

it('documents PID attach argument constraints in the public schema', () => {
expect(attachSchema.pid.description).toContain('without bundleId');
expect(attachSchema.pid.description).toContain('without waitFor');
expect(attachSchema.waitFor.description).toContain('Only valid when attaching by bundleId');
});
});

describe('Handler Requirements', () => {
Expand Down Expand Up @@ -171,6 +177,34 @@ describe('debug_attach_sim', () => {
expect(text).toContain('bundleId');
expect(text).toContain('pid');
});

it('rejects waitFor true when attaching by pid', async () => {
__setTestDebuggerToolContextOverride(createTestContext());
sessionStore.setDefaults({ simulatorId: 'test-sim-uuid' });

const result = await callHandler(attachHandler, {
pid: 1234,
waitFor: true,
});

expect(result.isError).toBe(true);
const text = result.content[0].text;
expect(text).toContain('waitFor is only valid when attaching by bundleId');
expect(text).toContain('For PID attach, omit waitFor or set it to false');
});

it('allows waitFor false when attaching by pid', async () => {
__setTestDebuggerToolContextOverride(createTestContext());
sessionStore.setDefaults({ simulatorId: 'test-sim-uuid' });

const result = await callHandler(attachHandler, {
pid: 1234,
waitFor: false,
});

expect(result.isError).toBeFalsy();
expect(result.content[0].text).toContain('Attached');
});
});

describe('Logic Behavior', () => {
Expand Down
34 changes: 29 additions & 5 deletions src/mcp/tools/debugging/debug_attach_sim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import {
type DebuggerToolContext,
} from '../../../utils/debugger/index.ts';

const DEBUG_ATTACH_MODE_HELP =
'Valid attach modes: provide bundleId without pid, or provide pid without bundleId and omit waitFor or set waitFor to false.';

const baseSchemaObject = z.object({
simulatorId: z
.string()
Expand All @@ -32,9 +35,26 @@ const baseSchemaObject = z.object({
.describe(
"Name of the simulator (e.g., 'iPhone 17'). Provide EITHER this OR simulatorId, not both",
),
bundleId: z.string().optional(),
pid: z.number().int().positive().optional(),
waitFor: z.boolean().optional().describe('Wait for the process to appear when attaching'),
bundleId: z
.string()
.optional()
.describe(
'Attach by bundle identifier. Provide bundleId without pid; waitFor may be used with this mode.',
),
pid: z
.number()
.int()
.positive()
.optional()
.describe(
'Attach to an already-running process by PID. Provide pid without bundleId and without waitFor.',
),
waitFor: z
.boolean()
.optional()
.describe(
'Only valid when attaching by bundleId. For PID attach, omit waitFor or set it to false.',
),
continueOnAttach: z.boolean().optional().default(true).describe('default: true'),
makeCurrent: z
.boolean()
Expand All @@ -47,10 +67,14 @@ const debugAttachSchema = z.preprocess(
nullifyEmptyStrings,
withSimulatorIdOrName(baseSchemaObject)
.refine((val) => val.bundleId !== undefined || val.pid !== undefined, {
message: 'Provide either bundleId or pid to attach.',
message: `Provide either bundleId or pid to attach. ${DEBUG_ATTACH_MODE_HELP}`,
})
.refine((val) => !(val.bundleId && val.pid), {
message: 'bundleId and pid are mutually exclusive. Provide only one.',
message: 'Provide either bundleId or pid, not both.',
})
.refine((val) => !(val.pid !== undefined && val.waitFor === true), {
message:
'waitFor is only valid when attaching by bundleId. For PID attach, omit waitFor or set it to false.',
}),
);

Expand Down
Loading