@kainoa/simplybuild 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +62 -0
  2. package/dist/app/runSimplyBuild.d.ts +25 -0
  3. package/dist/app/runSimplyBuild.js +287 -0
  4. package/dist/app/runSimplyBuild.js.map +1 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +146 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/discovery/projects.d.ts +2 -0
  9. package/dist/discovery/projects.js +51 -0
  10. package/dist/discovery/projects.js.map +1 -0
  11. package/dist/discovery/schemes.d.ts +3 -0
  12. package/dist/discovery/schemes.js +67 -0
  13. package/dist/discovery/schemes.js.map +1 -0
  14. package/dist/discovery/targets.d.ts +6 -0
  15. package/dist/discovery/targets.js +133 -0
  16. package/dist/discovery/targets.js.map +1 -0
  17. package/dist/matching/targetMatcher.d.ts +15 -0
  18. package/dist/matching/targetMatcher.js +104 -0
  19. package/dist/matching/targetMatcher.js.map +1 -0
  20. package/dist/runner/commandRunner.d.ts +2 -0
  21. package/dist/runner/commandRunner.js +41 -0
  22. package/dist/runner/commandRunner.js.map +1 -0
  23. package/dist/runner/pipelines.d.ts +23 -0
  24. package/dist/runner/pipelines.js +159 -0
  25. package/dist/runner/pipelines.js.map +1 -0
  26. package/dist/runner/xcodebuildmcpRunner.d.ts +14 -0
  27. package/dist/runner/xcodebuildmcpRunner.js +53 -0
  28. package/dist/runner/xcodebuildmcpRunner.js.map +1 -0
  29. package/dist/setup/xcodebuildmcpPrereq.d.ts +9 -0
  30. package/dist/setup/xcodebuildmcpPrereq.js +120 -0
  31. package/dist/setup/xcodebuildmcpPrereq.js.map +1 -0
  32. package/dist/state/store.d.ts +14 -0
  33. package/dist/state/store.js +126 -0
  34. package/dist/state/store.js.map +1 -0
  35. package/dist/types.d.ts +73 -0
  36. package/dist/types.js +20 -0
  37. package/dist/types.js.map +1 -0
  38. package/dist/ui/prompts.d.ts +22 -0
  39. package/dist/ui/prompts.js +93 -0
  40. package/dist/ui/prompts.js.map +1 -0
  41. package/package.json +38 -0
@@ -0,0 +1,67 @@
1
+ import { runCommand } from "../runner/commandRunner.js";
2
+ function parseJsonObject(raw) {
3
+ const start = raw.indexOf("{");
4
+ const end = raw.lastIndexOf("}");
5
+ if (start === -1 || end === -1 || end <= start) {
6
+ return null;
7
+ }
8
+ try {
9
+ return JSON.parse(raw.slice(start, end + 1));
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ function parseSchemesFromText(raw) {
16
+ const match = raw.match(/Schemes:([\s\S]*?)(\n\n|$)/);
17
+ if (!match) {
18
+ return [];
19
+ }
20
+ return match[1]
21
+ .split("\n")
22
+ .map((line) => line.trim())
23
+ .filter(Boolean);
24
+ }
25
+ export function isLikelyTestScheme(name) {
26
+ return /(^|[-_\s])(tests?|uitests?|snapshot)([-_\s]|$)/i.test(name);
27
+ }
28
+ export async function discoverSchemes(container) {
29
+ const args = ["-list", "-json"];
30
+ if (container.kind === "workspace") {
31
+ args.push("-workspace", container.path);
32
+ }
33
+ else {
34
+ args.push("-project", container.path);
35
+ }
36
+ const jsonResult = await runCommand("xcodebuild", args);
37
+ let schemes = [];
38
+ if (jsonResult.ok) {
39
+ const parsed = parseJsonObject(jsonResult.stdout || jsonResult.stderr);
40
+ if (parsed) {
41
+ const rootObj = parsed.workspace ??
42
+ parsed.project;
43
+ const schemeValues = rootObj?.schemes;
44
+ if (Array.isArray(schemeValues)) {
45
+ schemes = schemeValues.filter((s) => typeof s === "string");
46
+ }
47
+ }
48
+ }
49
+ if (schemes.length === 0) {
50
+ const fallbackArgs = ["-list"];
51
+ if (container.kind === "workspace") {
52
+ fallbackArgs.push("-workspace", container.path);
53
+ }
54
+ else {
55
+ fallbackArgs.push("-project", container.path);
56
+ }
57
+ const textResult = await runCommand("xcodebuild", fallbackArgs);
58
+ schemes = parseSchemesFromText(`${textResult.stdout}\n${textResult.stderr}`);
59
+ }
60
+ return schemes
61
+ .map((name) => ({
62
+ name,
63
+ isLikelyTestScheme: isLikelyTestScheme(name),
64
+ }))
65
+ .sort((a, b) => a.name.localeCompare(b.name));
66
+ }
67
+ //# sourceMappingURL=schemes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemes.js","sourceRoot":"","sources":["../../src/discovery/schemes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { TargetCandidate } from "../types.js";
2
+ export declare function isLikelyIosPhysicalPlatform(platformIdentifier?: string): boolean;
3
+ export declare function isIosSimulatorRuntime(runtimeKey: string): boolean;
4
+ export declare function discoverPhysicalDevices(): Promise<TargetCandidate[]>;
5
+ export declare function discoverSimulators(): Promise<TargetCandidate[]>;
6
+ export declare function discoverTargets(): Promise<TargetCandidate[]>;
@@ -0,0 +1,133 @@
1
+ import { promises as fs } from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { runCommand } from "../runner/commandRunner.js";
5
+ export function isLikelyIosPhysicalPlatform(platformIdentifier) {
6
+ if (!platformIdentifier) {
7
+ return true;
8
+ }
9
+ const normalized = platformIdentifier.toLowerCase();
10
+ return (normalized.includes("iphoneos") ||
11
+ normalized === "ios" ||
12
+ normalized.endsWith(".ios"));
13
+ }
14
+ export function isIosSimulatorRuntime(runtimeKey) {
15
+ const runtime = runtimeKey.split("SimRuntime.").pop() ?? runtimeKey;
16
+ return runtime.toLowerCase().startsWith("ios-");
17
+ }
18
+ function parseRuntimeLabel(runtimeKey) {
19
+ const runtime = runtimeKey.split("SimRuntime.").pop() ?? runtimeKey;
20
+ const parts = runtime.split("-");
21
+ if (parts.length < 2) {
22
+ return runtimeKey;
23
+ }
24
+ const platform = parts[0];
25
+ const version = parts.slice(1).join(".");
26
+ return `${platform} ${version}`;
27
+ }
28
+ function normalizeState(pairingState, tunnelState) {
29
+ if (pairingState !== "paired") {
30
+ return "Unpaired";
31
+ }
32
+ if (tunnelState === "connected") {
33
+ return "Available";
34
+ }
35
+ return "Available (WiFi)";
36
+ }
37
+ export async function discoverPhysicalDevices() {
38
+ const outputPath = path.join(os.tmpdir(), `simplybuild-devicectl-${Date.now()}.json`);
39
+ const result = await runCommand("xcrun", [
40
+ "devicectl",
41
+ "list",
42
+ "devices",
43
+ "--json-output",
44
+ outputPath,
45
+ ]);
46
+ if (!result.ok) {
47
+ return [];
48
+ }
49
+ try {
50
+ const raw = await fs.readFile(outputPath, "utf8");
51
+ const parsed = JSON.parse(raw);
52
+ const items = parsed.result?.devices;
53
+ if (!Array.isArray(items)) {
54
+ return [];
55
+ }
56
+ return items
57
+ .filter((item) => item.visibilityClass !== "Simulator")
58
+ .filter((item) => isLikelyIosPhysicalPlatform(item.deviceProperties?.platformIdentifier))
59
+ .filter((item) => typeof item.identifier === "string")
60
+ .map((item) => {
61
+ const state = normalizeState(item.connectionProperties?.pairingState, item.connectionProperties?.tunnelState);
62
+ return {
63
+ kind: "physical",
64
+ id: item.identifier ?? "",
65
+ name: item.deviceProperties?.name?.trim() || "Unknown Device",
66
+ os: item.deviceProperties?.osVersionNumber ||
67
+ item.deviceProperties?.platformIdentifier ||
68
+ "iOS",
69
+ state,
70
+ isBooted: false,
71
+ };
72
+ })
73
+ .filter((item) => item.state.startsWith("Available"))
74
+ .sort((a, b) => a.name.localeCompare(b.name));
75
+ }
76
+ catch {
77
+ return [];
78
+ }
79
+ finally {
80
+ await fs.rm(outputPath, { force: true }).catch(() => undefined);
81
+ }
82
+ }
83
+ export async function discoverSimulators() {
84
+ const result = await runCommand("xcrun", ["simctl", "list", "devices", "available", "--json"]);
85
+ if (!result.ok) {
86
+ return [];
87
+ }
88
+ let parsed;
89
+ try {
90
+ parsed = JSON.parse(result.stdout);
91
+ }
92
+ catch {
93
+ return [];
94
+ }
95
+ const devices = parsed.devices ?? {};
96
+ const targets = [];
97
+ for (const [runtime, simulatorList] of Object.entries(devices)) {
98
+ if (!isIosSimulatorRuntime(runtime)) {
99
+ continue;
100
+ }
101
+ for (const item of simulatorList) {
102
+ const name = typeof item.name === "string" ? item.name : undefined;
103
+ const id = typeof item.udid === "string" ? item.udid : undefined;
104
+ const state = typeof item.state === "string" ? item.state : "Unknown";
105
+ const isAvailable = item.isAvailable === true;
106
+ if (!name || !id || !isAvailable) {
107
+ continue;
108
+ }
109
+ targets.push({
110
+ kind: "simulator",
111
+ id,
112
+ name,
113
+ os: parseRuntimeLabel(runtime),
114
+ state,
115
+ isBooted: state === "Booted",
116
+ });
117
+ }
118
+ }
119
+ return targets.sort((a, b) => {
120
+ if (a.isBooted !== b.isBooted) {
121
+ return a.isBooted ? -1 : 1;
122
+ }
123
+ return a.name.localeCompare(b.name);
124
+ });
125
+ }
126
+ export async function discoverTargets() {
127
+ const [physical, simulators] = await Promise.all([
128
+ discoverPhysicalDevices(),
129
+ discoverSimulators(),
130
+ ]);
131
+ return [...physical, ...simulators];
132
+ }
133
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../../src/discovery/targets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type TargetCandidate } from "../types.js";
2
+ export interface RankedTarget {
3
+ target: TargetCandidate;
4
+ score: number;
5
+ }
6
+ export interface QueryMatchDecision {
7
+ selected?: TargetCandidate;
8
+ ranked: RankedTarget[];
9
+ requiresInteractive: boolean;
10
+ reason: "no-targets" | "below-threshold" | "ambiguous" | "selected" | "selected-physical-preference";
11
+ }
12
+ export declare function normalizeMatchString(value: string): string;
13
+ export declare function scoreTarget(query: string, target: TargetCandidate): number;
14
+ export declare function rankTargets(query: string, targets: TargetCandidate[]): RankedTarget[];
15
+ export declare function decideTargetFromQuery(query: string, targets: TargetCandidate[]): QueryMatchDecision;
@@ -0,0 +1,104 @@
1
+ import { MATCHING_THRESHOLDS } from "../types.js";
2
+ function compactWhitespace(value) {
3
+ return value.replace(/\s+/g, " ").trim();
4
+ }
5
+ export function normalizeMatchString(value) {
6
+ const normalized = value
7
+ .toLowerCase()
8
+ .replace(/[^\p{L}\p{N}]+/gu, " ");
9
+ return compactWhitespace(normalized);
10
+ }
11
+ function tokenize(value) {
12
+ const normalized = normalizeMatchString(value);
13
+ if (!normalized) {
14
+ return [];
15
+ }
16
+ return normalized.split(" ").filter(Boolean);
17
+ }
18
+ function tokenOverlapScore(query, candidate) {
19
+ const queryTokens = new Set(tokenize(query));
20
+ const candidateTokens = new Set(tokenize(candidate));
21
+ if (queryTokens.size === 0 || candidateTokens.size === 0) {
22
+ return 0;
23
+ }
24
+ let matches = 0;
25
+ for (const token of queryTokens) {
26
+ if (candidateTokens.has(token)) {
27
+ matches += 1;
28
+ }
29
+ }
30
+ const union = new Set([...queryTokens, ...candidateTokens]).size;
31
+ return union === 0 ? 0 : matches / union;
32
+ }
33
+ export function scoreTarget(query, target) {
34
+ const q = normalizeMatchString(query);
35
+ const candidate = normalizeMatchString(target.name);
36
+ if (!q || !candidate) {
37
+ return 0;
38
+ }
39
+ const exact = q === candidate ? 1 : 0;
40
+ const prefix = candidate.startsWith(q) || q.startsWith(candidate) ? 0.9 : 0;
41
+ const substring = candidate.includes(q) || q.includes(candidate) ? 0.82 : 0;
42
+ const tokenOverlap = tokenOverlapScore(q, candidate);
43
+ return Math.max(exact, prefix, substring, tokenOverlap);
44
+ }
45
+ function sortRanked(a, b) {
46
+ if (a.score !== b.score) {
47
+ return b.score - a.score;
48
+ }
49
+ if (a.target.kind !== b.target.kind) {
50
+ return a.target.kind === "physical" ? -1 : 1;
51
+ }
52
+ return a.target.name.localeCompare(b.target.name);
53
+ }
54
+ export function rankTargets(query, targets) {
55
+ return targets
56
+ .map((target) => ({ target, score: scoreTarget(query, target) }))
57
+ .sort(sortRanked);
58
+ }
59
+ export function decideTargetFromQuery(query, targets) {
60
+ const ranked = rankTargets(query, targets);
61
+ if (ranked.length === 0) {
62
+ return {
63
+ ranked,
64
+ requiresInteractive: true,
65
+ reason: "no-targets",
66
+ };
67
+ }
68
+ const top = ranked[0];
69
+ const second = ranked[1];
70
+ if (top.score < MATCHING_THRESHOLDS.closeMatch) {
71
+ return {
72
+ ranked,
73
+ requiresInteractive: true,
74
+ reason: "below-threshold",
75
+ };
76
+ }
77
+ const bestPhysical = ranked.find((entry) => entry.target.kind === "physical");
78
+ const bestSimulator = ranked.find((entry) => entry.target.kind === "simulator");
79
+ if (bestPhysical && bestSimulator) {
80
+ const delta = Math.abs(bestPhysical.score - bestSimulator.score);
81
+ if (delta <= MATCHING_THRESHOLDS.physicalPreferenceWindow) {
82
+ return {
83
+ ranked,
84
+ selected: bestPhysical.target,
85
+ requiresInteractive: false,
86
+ reason: "selected-physical-preference",
87
+ };
88
+ }
89
+ }
90
+ if (second && top.score - second.score < MATCHING_THRESHOLDS.ambiguityDelta) {
91
+ return {
92
+ ranked,
93
+ requiresInteractive: true,
94
+ reason: "ambiguous",
95
+ };
96
+ }
97
+ return {
98
+ ranked,
99
+ selected: top.target,
100
+ requiresInteractive: false,
101
+ reason: "selected",
102
+ };
103
+ }
104
+ //# sourceMappingURL=targetMatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targetMatcher.js","sourceRoot":"","sources":["../../src/matching/targetMatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { CommandResult, CommandRunOptions } from "../types.js";
2
+ export declare function runCommand(command: string, args: string[], options?: CommandRunOptions): Promise<CommandResult>;
@@ -0,0 +1,41 @@
1
+ import { spawn } from "node:child_process";
2
+ export async function runCommand(command, args, options = {}) {
3
+ const child = spawn(command, args, {
4
+ cwd: options.cwd,
5
+ env: options.env,
6
+ stdio: options.verbose ? "inherit" : "pipe",
7
+ });
8
+ if (options.verbose) {
9
+ return new Promise((resolve, reject) => {
10
+ child.on("error", reject);
11
+ child.on("close", (code) => {
12
+ resolve({
13
+ ok: code === 0,
14
+ code: code ?? 1,
15
+ stdout: "",
16
+ stderr: "",
17
+ });
18
+ });
19
+ });
20
+ }
21
+ let stdout = "";
22
+ let stderr = "";
23
+ child.stdout?.on("data", (chunk) => {
24
+ stdout += String(chunk);
25
+ });
26
+ child.stderr?.on("data", (chunk) => {
27
+ stderr += String(chunk);
28
+ });
29
+ return new Promise((resolve, reject) => {
30
+ child.on("error", reject);
31
+ child.on("close", (code) => {
32
+ resolve({
33
+ ok: code === 0,
34
+ code: code ?? 1,
35
+ stdout,
36
+ stderr,
37
+ });
38
+ });
39
+ });
40
+ }
41
+ //# sourceMappingURL=commandRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandRunner.js","sourceRoot":"","sources":["../../src/runner/commandRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAe,EACf,IAAc,EACd,UAA6B,EAAE;IAE/B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;QACjC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;KAC5C,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,OAAO,CAAC;oBACN,EAAE,EAAE,IAAI,KAAK,CAAC;oBACd,IAAI,EAAE,IAAI,IAAI,CAAC;oBACf,MAAM,EAAE,EAAE;oBACV,MAAM,EAAE,EAAE;iBACX,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,MAAM,GAAG,EAAE,CAAC;IAEhB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;QACjC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;QACjC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,OAAO,CAAC;gBACN,EAAE,EAAE,IAAI,KAAK,CAAC;gBACd,IAAI,EAAE,IAAI,IAAI,CAAC;gBACf,MAAM;gBACN,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { ProjectCandidate, TargetCandidate } from "../types.js";
2
+ import type { PromptApi } from "../ui/prompts.js";
3
+ import type { CommandResult } from "../types.js";
4
+ import { type ToolCommandResult } from "./xcodebuildmcpRunner.js";
5
+ export interface PipelineContext {
6
+ container: ProjectCandidate;
7
+ scheme: string;
8
+ target: TargetCandidate;
9
+ verbose: boolean;
10
+ }
11
+ export interface PipelineDependencies {
12
+ runTool: (args: string[], options: {
13
+ verbose?: boolean;
14
+ }) => Promise<ToolCommandResult>;
15
+ runRaw: (command: string, args: string[], options: {
16
+ verbose?: boolean;
17
+ }) => Promise<CommandResult>;
18
+ }
19
+ export declare function parseAppPathFromToolText(text: string): string | undefined;
20
+ export declare function parseBundleIdFromToolText(text: string): string | undefined;
21
+ export declare function parseAppPathFromBuildSettings(settings: string): string | undefined;
22
+ export declare function runSimulatorPipeline(ctx: PipelineContext, prompts: PromptApi, deps?: PipelineDependencies): Promise<void>;
23
+ export declare function runPhysicalPipeline(ctx: PipelineContext, prompts: PromptApi, deps?: PipelineDependencies): Promise<void>;
@@ -0,0 +1,159 @@
1
+ import { UserFacingError } from "../types.js";
2
+ import { runCommand } from "./commandRunner.js";
3
+ import { runXcodebuildmcpTool, } from "./xcodebuildmcpRunner.js";
4
+ function containerArgs(container) {
5
+ return container.kind === "workspace"
6
+ ? ["--workspace-path", container.path]
7
+ : ["--project-path", container.path];
8
+ }
9
+ function formatToolFailure(result, fallbackLabel) {
10
+ const text = result.response.text || result.stderr || result.stdout;
11
+ return text.trim().length > 0 ? text.trim() : fallbackLabel;
12
+ }
13
+ function assertToolSuccess(result, fallbackLabel) {
14
+ if (!result.ok || result.response.isError) {
15
+ throw new UserFacingError(formatToolFailure(result, fallbackLabel));
16
+ }
17
+ }
18
+ export function parseAppPathFromToolText(text) {
19
+ const patterns = [
20
+ /App path retrieved successfully:\s*(.+?\.app)\b/i,
21
+ /\b(CODESIGNING_FOLDER_PATH|APP_PATH)\s*[=:]\s*(.+?\.app)\b/i,
22
+ /\b(\/[^\s]+\.app)\b/g,
23
+ ];
24
+ const direct = text.match(patterns[0]) || text.match(patterns[1]);
25
+ if (direct?.[2]) {
26
+ return direct[2].trim();
27
+ }
28
+ if (direct?.[1] && direct[0].includes(".app")) {
29
+ return direct[1].trim();
30
+ }
31
+ const all = [...text.matchAll(patterns[2])];
32
+ if (all.length > 0) {
33
+ return all[all.length - 1][1].trim();
34
+ }
35
+ return undefined;
36
+ }
37
+ export function parseBundleIdFromToolText(text) {
38
+ const match = text.match(/Bundle ID:\s*([A-Za-z0-9._-]+)/i);
39
+ if (match?.[1]) {
40
+ return match[1].trim();
41
+ }
42
+ return undefined;
43
+ }
44
+ export function parseAppPathFromBuildSettings(settings) {
45
+ const codeSigningMatch = settings.match(/CODESIGNING_FOLDER_PATH\s*=\s*(.+\.app)/);
46
+ if (codeSigningMatch?.[1]) {
47
+ return codeSigningMatch[1].trim();
48
+ }
49
+ const builtDirMatch = settings.match(/^\s*BUILT_PRODUCTS_DIR\s*=\s*(.+)$/m);
50
+ const productMatch = settings.match(/^\s*FULL_PRODUCT_NAME\s*=\s*(.+)$/m);
51
+ if (builtDirMatch?.[1] && productMatch?.[1]) {
52
+ return `${builtDirMatch[1].trim()}/${productMatch[1].trim()}`;
53
+ }
54
+ return undefined;
55
+ }
56
+ async function fallbackResolveAppPath(ctx, deps) {
57
+ const args = ["-showBuildSettings"];
58
+ if (ctx.container.kind === "workspace") {
59
+ args.push("-workspace", ctx.container.path);
60
+ }
61
+ else {
62
+ args.push("-project", ctx.container.path);
63
+ }
64
+ args.push("-scheme", ctx.scheme, "-configuration", "Debug", "-destination", "generic/platform=iOS");
65
+ const result = await deps.runRaw("xcodebuild", args, { verbose: false });
66
+ if (!result.ok) {
67
+ throw new UserFacingError("Failed to determine built app path from build settings.", [result.stderr || result.stdout]);
68
+ }
69
+ const appPath = parseAppPathFromBuildSettings(result.stdout);
70
+ if (!appPath) {
71
+ throw new UserFacingError("Could not extract app path from xcodebuild settings output.");
72
+ }
73
+ return appPath;
74
+ }
75
+ async function fallbackResolveBundleId(appPath, deps) {
76
+ const plistPath = `${appPath}/Info.plist`;
77
+ const result = await deps.runRaw("/usr/libexec/PlistBuddy", ["-c", "Print :CFBundleIdentifier", plistPath], { verbose: false });
78
+ if (!result.ok) {
79
+ throw new UserFacingError("Failed to extract bundle ID from app bundle.", [result.stderr || result.stdout]);
80
+ }
81
+ const value = result.stdout.trim();
82
+ if (!value) {
83
+ throw new UserFacingError("Bundle ID extraction returned an empty value.");
84
+ }
85
+ return value;
86
+ }
87
+ export async function runSimulatorPipeline(ctx, prompts, deps = {
88
+ runTool: (args, options) => runXcodebuildmcpTool(args, options),
89
+ runRaw: (command, args, options) => runCommand(command, args, options),
90
+ }) {
91
+ await prompts.stage(`Building and launching ${ctx.scheme} on simulator ${ctx.target.name}`, async () => {
92
+ const result = await deps.runTool([
93
+ "simulator",
94
+ "build-run-sim",
95
+ ...containerArgs(ctx.container),
96
+ "--scheme",
97
+ ctx.scheme,
98
+ "--simulator-id",
99
+ ctx.target.id,
100
+ "--configuration",
101
+ "Debug",
102
+ ], { verbose: ctx.verbose });
103
+ assertToolSuccess(result, "Simulator build/run failed.");
104
+ }, {
105
+ success: `Launched ${ctx.scheme} on ${ctx.target.name}`,
106
+ error: `Failed to launch ${ctx.scheme} on ${ctx.target.name}`,
107
+ });
108
+ }
109
+ export async function runPhysicalPipeline(ctx, prompts, deps = {
110
+ runTool: (args, options) => runXcodebuildmcpTool(args, options),
111
+ runRaw: (command, args, options) => runCommand(command, args, options),
112
+ }) {
113
+ const baseArgs = containerArgs(ctx.container);
114
+ await prompts.stage(`Building ${ctx.scheme} for physical device`, async () => {
115
+ const result = await deps.runTool(["device", "build-device", ...baseArgs, "--scheme", ctx.scheme, "--configuration", "Debug"], { verbose: ctx.verbose });
116
+ assertToolSuccess(result, "Device build failed.");
117
+ });
118
+ const appPath = await prompts.stage("Resolving built app path", async () => {
119
+ const pathResult = await deps.runTool(["device", "get-device-app-path", ...baseArgs, "--scheme", ctx.scheme, "--platform", "iOS"], { verbose: false });
120
+ assertToolSuccess(pathResult, "Failed to get built app path.");
121
+ const parsed = parseAppPathFromToolText(pathResult.response.text);
122
+ if (parsed) {
123
+ return parsed;
124
+ }
125
+ return fallbackResolveAppPath(ctx, deps);
126
+ });
127
+ const bundleId = await prompts.stage("Resolving app bundle identifier", async () => {
128
+ const bundleResult = await deps.runTool(["project-discovery", "get-app-bundle-id", "--app-path", appPath], { verbose: false });
129
+ assertToolSuccess(bundleResult, "Failed to resolve app bundle identifier.");
130
+ const parsed = parseBundleIdFromToolText(bundleResult.response.text);
131
+ if (parsed) {
132
+ return parsed;
133
+ }
134
+ return fallbackResolveBundleId(appPath, deps);
135
+ });
136
+ await prompts.stage(`Installing app on ${ctx.target.name}`, async () => {
137
+ const installResult = await deps.runTool([
138
+ "device",
139
+ "install-app-device",
140
+ "--device-id",
141
+ ctx.target.id,
142
+ "--app-path",
143
+ appPath,
144
+ ], { verbose: ctx.verbose });
145
+ assertToolSuccess(installResult, "Failed to install app on physical device.");
146
+ });
147
+ await prompts.stage(`Launching app (${bundleId}) on ${ctx.target.name}`, async () => {
148
+ const launchResult = await deps.runTool([
149
+ "device",
150
+ "launch-app-device",
151
+ "--device-id",
152
+ ctx.target.id,
153
+ "--bundle-id",
154
+ bundleId,
155
+ ], { verbose: ctx.verbose });
156
+ assertToolSuccess(launchResult, "Failed to launch app on physical device.");
157
+ });
158
+ }
159
+ //# sourceMappingURL=pipelines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipelines.js","sourceRoot":"","sources":["../../src/runner/pipelines.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { CommandResult } from "../types.js";
2
+ export interface XcodebuildMcpResponse {
3
+ text: string;
4
+ isError: boolean;
5
+ json: Record<string, unknown> | null;
6
+ }
7
+ export interface ToolCommandResult extends CommandResult {
8
+ response: XcodebuildMcpResponse;
9
+ }
10
+ export declare function parseXcodebuildMcpOutput(stdout: string): XcodebuildMcpResponse;
11
+ export declare function runXcodebuildmcpTool(args: string[], options?: {
12
+ cwd?: string;
13
+ verbose?: boolean;
14
+ }): Promise<ToolCommandResult>;