| 1016 | } |
| 1017 | |
| 1018 | export async function runSetupWizard(deps?: Partial<SetupDependencies>): Promise<SetupRunResult> { |
| 1019 | const isTTY = isInteractiveTTY(); |
| 1020 | if (!isTTY) { |
| 1021 | throw new Error('`xcodebuildmcp setup` requires an interactive TTY.'); |
| 1022 | } |
| 1023 | |
| 1024 | const resolvedDeps: SetupDependencies = { |
| 1025 | cwd: deps?.cwd ?? process.cwd(), |
| 1026 | fs: deps?.fs ?? getDefaultFileSystemExecutor(), |
| 1027 | executor: deps?.executor ?? getDefaultCommandExecutor(), |
| 1028 | prompter: deps?.prompter ?? createPrompter(), |
| 1029 | quietOutput: deps?.quietOutput ?? false, |
| 1030 | outputFormat: deps?.outputFormat ?? 'yaml', |
| 1031 | }; |
| 1032 | |
| 1033 | const isMcpJson = resolvedDeps.outputFormat === 'mcp-json'; |
| 1034 | |
| 1035 | if (!resolvedDeps.quietOutput) { |
| 1036 | clack.intro('XcodeBuildMCP Setup'); |
| 1037 | if (isMcpJson) { |
| 1038 | clack.log.info( |
| 1039 | 'This wizard will configure your project defaults for XcodeBuildMCP.\n' + |
| 1040 | 'You will select target platforms, workflows, a project or workspace,\n' + |
| 1041 | 'scheme, and any simulator/device defaults required by the workflows\n' + |
| 1042 | 'you enable. A ready-to-paste MCP config JSON block will be printed\n' + |
| 1043 | 'at the end. You can rerun this wizard at any time — previous choices\n' + |
| 1044 | 'are pre-loaded automatically.', |
| 1045 | ); |
| 1046 | } else { |
| 1047 | clack.log.info( |
| 1048 | 'This wizard will configure your project defaults for XcodeBuildMCP.\n' + |
| 1049 | 'You will select target platforms, workflows, a project or workspace,\n' + |
| 1050 | 'scheme, and any simulator/device defaults required by the workflows\n' + |
| 1051 | 'you enable. Settings are saved to .xcodebuildmcp/config.yaml in your\n' + |
| 1052 | 'project directory. You can rerun this wizard at any time — previous\n' + |
| 1053 | 'choices are pre-loaded automatically.', |
| 1054 | ); |
| 1055 | } |
| 1056 | } |
| 1057 | |
| 1058 | await ensureSetupPrerequisites({ |
| 1059 | executor: resolvedDeps.executor, |
| 1060 | isTTY, |
| 1061 | quietOutput: resolvedDeps.quietOutput, |
| 1062 | }); |
| 1063 | |
| 1064 | const beforeResult = await loadProjectConfig({ fs: resolvedDeps.fs, cwd: resolvedDeps.cwd }); |
| 1065 | const beforeConfig = beforeResult.found ? beforeResult.config : undefined; |
| 1066 | |
| 1067 | const selection = await collectSetupSelection(beforeConfig, resolvedDeps); |
| 1068 | |
| 1069 | if (isMcpJson) { |
| 1070 | const mcpConfigJson = selectionToMcpConfigJson(selection); |
| 1071 | |
| 1072 | if (!resolvedDeps.quietOutput) { |
| 1073 | clack.log.info( |
| 1074 | 'Copy the following JSON block into your MCP client config\n' + |
| 1075 | '(e.g. mcp_config.json for Windsurf, .vscode/mcp.json for VS Code,\n' + |