@ai-development-environment/control-agent 0.0.34 → 0.0.36

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 (2) hide show
  1. package/dist/control-agent.js +801 -123
  2. package/package.json +1 -1
@@ -842,6 +842,18 @@ var AgentGraphQLClient = class {
842
842
  );
843
843
  return data.claimAgentJob;
844
844
  }
845
+ async claimSigningSecretTransfer(transferId) {
846
+ const data = await this.request(
847
+ `mutation ClaimSigningSecretTransfer($transferId: ID!) {
848
+ claimSigningSecretTransfer(transferId: $transferId) {
849
+ p12Base64
850
+ passphrase
851
+ }
852
+ }`,
853
+ { transferId }
854
+ );
855
+ return data.claimSigningSecretTransfer;
856
+ }
845
857
  appendLog(jobId, log) {
846
858
  return this.request(
847
859
  `mutation AppendLog($jobId: ID!, $logs: [AgentJobLogInput!]!) {
@@ -2651,7 +2663,11 @@ function parseBuildSourceParsePayload(value) {
2651
2663
  return {
2652
2664
  ...worktreeIdentity(input),
2653
2665
  source: parseBuildSource(input.source),
2654
- scheme: nullableString4(input.scheme, "source parse payload.scheme")
2666
+ scheme: nullableString4(input.scheme, "source parse payload.scheme"),
2667
+ configuration: nullableString4(
2668
+ input.configuration,
2669
+ "source parse payload.configuration"
2670
+ )
2655
2671
  };
2656
2672
  }
2657
2673
  function parseBuildDestinationsPayload(value) {
@@ -2870,6 +2886,23 @@ function parseBuildExportSettings(value) {
2870
2886
  testFlightInternalTestingOnly: booleanValue2(
2871
2887
  input.testFlightInternalTestingOnly,
2872
2888
  "export settings.testFlightInternalTestingOnly"
2889
+ ),
2890
+ stripSwiftSymbols: input.stripSwiftSymbols === void 0 ? true : booleanValue2(
2891
+ input.stripSwiftSymbols,
2892
+ "export settings.stripSwiftSymbols"
2893
+ ),
2894
+ thinning: nullableString4(
2895
+ input.thinning ?? null,
2896
+ "export settings.thinning"
2897
+ ),
2898
+ iCloudContainerEnvironment: input.iCloudContainerEnvironment === null || input.iCloudContainerEnvironment === void 0 ? null : enumValue3(
2899
+ input.iCloudContainerEnvironment,
2900
+ ["Development", "Production"],
2901
+ "export settings.iCloudContainerEnvironment"
2902
+ ),
2903
+ distributionBundleIdentifier: nullableString4(
2904
+ input.distributionBundleIdentifier ?? null,
2905
+ "export settings.distributionBundleIdentifier"
2873
2906
  )
2874
2907
  };
2875
2908
  }
@@ -2914,6 +2947,81 @@ function parseBuildSigningInspectPayload(value) {
2914
2947
  };
2915
2948
  }
2916
2949
 
2950
+ // ../agent-contract/src/signing-assets.ts
2951
+ var SIGNING_ASSETS_SCAN_JOB_KIND = "ios.signing.assets.scan";
2952
+ var SIGNING_PROFILE_READ_JOB_KIND = "ios.signing.profile.read";
2953
+ var SIGNING_PROFILE_INSTALL_JOB_KIND = "ios.signing.profile.install";
2954
+ var SIGNING_PROFILE_DELETE_JOB_KIND = "ios.signing.profile.delete";
2955
+ var SIGNING_IDENTITY_IMPORT_JOB_KIND = "ios.signing.identity.import";
2956
+ var SIGNING_IDENTITY_DELETE_JOB_KIND = "ios.signing.identity.delete";
2957
+ var SIGNING_ASSET_JOB_KINDS = [
2958
+ SIGNING_ASSETS_SCAN_JOB_KIND,
2959
+ SIGNING_PROFILE_READ_JOB_KIND,
2960
+ SIGNING_PROFILE_INSTALL_JOB_KIND,
2961
+ SIGNING_PROFILE_DELETE_JOB_KIND,
2962
+ SIGNING_IDENTITY_IMPORT_JOB_KIND,
2963
+ SIGNING_IDENTITY_DELETE_JOB_KIND
2964
+ ];
2965
+ function objectValue7(value, name) {
2966
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2967
+ throw new Error(`${name} must be an object`);
2968
+ }
2969
+ return value;
2970
+ }
2971
+ function stringValue7(value, name) {
2972
+ if (typeof value !== "string" || !value.trim() || value.includes("\0")) {
2973
+ throw new Error(`${name} must be a non-empty string`);
2974
+ }
2975
+ return value;
2976
+ }
2977
+ function exactKeys2(value, allowed, name) {
2978
+ const unexpected = Object.keys(value).find((key) => !allowed.includes(key));
2979
+ if (unexpected) throw new Error(`Unexpected ${name} field: ${unexpected}`);
2980
+ }
2981
+ function signingScanPayload(value) {
2982
+ const input = objectValue7(value, "signing scan payload");
2983
+ exactKeys2(input, [], "signing scan payload");
2984
+ return {};
2985
+ }
2986
+ function signingProfileKeyPayload(value) {
2987
+ const input = objectValue7(value, "signing profile payload");
2988
+ exactKeys2(input, ["uuid"], "signing profile payload");
2989
+ return { uuid: stringValue7(input.uuid, "signing profile payload.uuid") };
2990
+ }
2991
+ function signingProfileInstallPayload(value) {
2992
+ const input = objectValue7(value, "signing profile install payload");
2993
+ exactKeys2(input, ["contentBase64"], "signing profile install payload");
2994
+ const contentBase64 = stringValue7(
2995
+ input.contentBase64,
2996
+ "signing profile install payload.contentBase64"
2997
+ );
2998
+ if (contentBase64.length > 2 * 1024 * 1024) {
2999
+ throw new Error("Provisioning profile payload is too large");
3000
+ }
3001
+ return { contentBase64 };
3002
+ }
3003
+ function signingIdentityImportPayload(value) {
3004
+ const input = objectValue7(value, "signing identity import payload");
3005
+ exactKeys2(input, ["transferId", "sha256"], "signing identity import payload");
3006
+ const sha256 = stringValue7(input.sha256, "signing identity import sha256");
3007
+ if (!/^[A-Fa-f0-9]{64}$/.test(sha256)) {
3008
+ throw new Error("Signing identity import SHA-256 is invalid");
3009
+ }
3010
+ return {
3011
+ transferId: stringValue7(input.transferId, "signing identity transfer ID"),
3012
+ sha256: sha256.toUpperCase()
3013
+ };
3014
+ }
3015
+ function signingIdentityDeletePayload(value) {
3016
+ const input = objectValue7(value, "signing identity delete payload");
3017
+ exactKeys2(input, ["sha1"], "signing identity delete payload");
3018
+ const sha1 = stringValue7(input.sha1, "signing identity SHA-1");
3019
+ if (!/^[A-Fa-f0-9]{40}$/.test(sha1)) {
3020
+ throw new Error("Signing identity SHA-1 is invalid");
3021
+ }
3022
+ return { sha1: sha1.toUpperCase() };
3023
+ }
3024
+
2917
3025
  // src/inventory.ts
2918
3026
  var AGENT_VERSION = "0.1.0";
2919
3027
  var AGENT_CAPABILITIES = [
@@ -2924,7 +3032,8 @@ var AGENT_CAPABILITIES = [
2924
3032
  CODEBASE_RECONCILE_EVENT_CAPABILITY,
2925
3033
  ...WORKTREE_JOB_KINDS,
2926
3034
  ...SKILL_JOB_KINDS,
2927
- ...IOS_BUILD_JOB_KINDS
3035
+ ...IOS_BUILD_JOB_KINDS,
3036
+ ...SIGNING_ASSET_JOB_KINDS
2928
3037
  ];
2929
3038
  function collectInventory() {
2930
3039
  const disk = statfsSync("/", { bigint: true });
@@ -3054,9 +3163,17 @@ function runCloudflared(payload, timeoutMs, signal, onLog) {
3054
3163
  }
3055
3164
 
3056
3165
  // src/handlers/signing.ts
3057
- import { createHash as createHash2 } from "node:crypto";
3058
- import { readdir, stat as stat2 } from "node:fs/promises";
3059
- import { homedir as homedir2 } from "node:os";
3166
+ import { createHash as createHash2, randomUUID, X509Certificate } from "node:crypto";
3167
+ import {
3168
+ mkdir as mkdir2,
3169
+ mkdtemp,
3170
+ readFile as readFile2,
3171
+ readdir,
3172
+ rm,
3173
+ stat as stat2,
3174
+ writeFile as writeFile2
3175
+ } from "node:fs/promises";
3176
+ import { homedir as homedir2, tmpdir } from "node:os";
3060
3177
  import { basename, join as join2, relative, sep } from "node:path";
3061
3178
 
3062
3179
  // ../agent-contract/src/plist.ts
@@ -3211,12 +3328,23 @@ function parsePlist(xml) {
3211
3328
  import { spawn as spawn2 } from "node:child_process";
3212
3329
  var MAX_OUTPUT_BYTES = 2 * 1024 * 1024;
3213
3330
  function captureCommand(options) {
3331
+ if (options.signal.aborted || options.timeoutMs <= 0) {
3332
+ return Promise.resolve({
3333
+ exitCode: null,
3334
+ signal: null,
3335
+ timedOut: !options.signal.aborted,
3336
+ cancelled: options.signal.aborted,
3337
+ stdout: "",
3338
+ stderr: ""
3339
+ });
3340
+ }
3214
3341
  return new Promise((resolve6, reject) => {
3215
3342
  let stdout = "";
3216
3343
  let stderr = "";
3217
3344
  let timedOut = false;
3218
3345
  let cancelled = false;
3219
3346
  let settled = false;
3347
+ let killTimer = null;
3220
3348
  const child = spawn2(options.command, options.args, {
3221
3349
  shell: false,
3222
3350
  stdio: [
@@ -3237,8 +3365,10 @@ function captureCommand(options) {
3237
3365
  const terminate = () => {
3238
3366
  if (child.exitCode !== null || child.killed) return;
3239
3367
  child.kill("SIGTERM");
3240
- const timer = setTimeout(() => child.kill("SIGKILL"), 5e3);
3241
- timer.unref();
3368
+ killTimer = setTimeout(() => {
3369
+ if (child.exitCode === null) child.kill("SIGKILL");
3370
+ }, 5e3);
3371
+ killTimer.unref();
3242
3372
  };
3243
3373
  const timeout = setTimeout(() => {
3244
3374
  timedOut = true;
@@ -3255,6 +3385,7 @@ function captureCommand(options) {
3255
3385
  if (settled) return;
3256
3386
  settled = true;
3257
3387
  clearTimeout(timeout);
3388
+ if (killTimer) clearTimeout(killTimer);
3258
3389
  options.signal.removeEventListener("abort", abort);
3259
3390
  reject(error);
3260
3391
  });
@@ -3262,6 +3393,7 @@ function captureCommand(options) {
3262
3393
  if (settled) return;
3263
3394
  settled = true;
3264
3395
  clearTimeout(timeout);
3396
+ if (killTimer) clearTimeout(killTimer);
3265
3397
  options.signal.removeEventListener("abort", abort);
3266
3398
  resolve6({
3267
3399
  exitCode,
@@ -3294,7 +3426,7 @@ function text(value) {
3294
3426
  function stringList(value) {
3295
3427
  return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
3296
3428
  }
3297
- async function decodeProfile(path, timeoutMs, signal) {
3429
+ async function decodeProfile(path, timeoutMs, signal, strict = false) {
3298
3430
  try {
3299
3431
  const result = await captureCommand({
3300
3432
  command: "/usr/bin/security",
@@ -3302,16 +3434,29 @@ async function decodeProfile(path, timeoutMs, signal) {
3302
3434
  timeoutMs: Math.min(timeoutMs, 1e4),
3303
3435
  signal
3304
3436
  });
3437
+ if (strict) assertCommandSucceeded(result, `Reading profile ${path}`);
3305
3438
  if (result.exitCode !== 0 || !result.stdout.trim()) return null;
3306
3439
  const parsed = parsePlist(result.stdout);
3307
3440
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
3441
+ if (strict) throw new Error(`Profile ${path} did not contain a plist`);
3308
3442
  return null;
3309
3443
  }
3310
3444
  return parsed;
3311
- } catch {
3445
+ } catch (error) {
3446
+ if (strict) throw error;
3312
3447
  return null;
3313
3448
  }
3314
3449
  }
3450
+ function assertCommandSucceeded(result, action) {
3451
+ if (result.cancelled) throw new Error(`${action} was cancelled`);
3452
+ if (result.timedOut) throw new Error(`${action} timed out`);
3453
+ if (result.exitCode !== 0) {
3454
+ const detail = result.stderr.trim();
3455
+ throw new Error(
3456
+ `${action} failed${detail ? `: ${detail}` : ` with exit code ${String(result.exitCode)}`}`
3457
+ );
3458
+ }
3459
+ }
3315
3460
  function toProfile(uuid, raw, now) {
3316
3461
  const name = text(raw.Name);
3317
3462
  if (!name) return null;
@@ -3381,6 +3526,66 @@ async function readProfiles(timeoutMs, signal) {
3381
3526
  (left, right) => left.name.localeCompare(right.name)
3382
3527
  );
3383
3528
  }
3529
+ async function decodedProfiles(timeoutMs, signal, strict = false) {
3530
+ const profiles = [];
3531
+ if (strict) signal.throwIfAborted();
3532
+ for (const directory of PROFILE_DIRECTORIES) {
3533
+ let entries;
3534
+ try {
3535
+ entries = await readdir(directory);
3536
+ } catch (error) {
3537
+ if (strict && error.code !== "ENOENT") {
3538
+ throw error;
3539
+ }
3540
+ continue;
3541
+ }
3542
+ for (const entry of entries) {
3543
+ if (!PROFILE_EXTENSIONS.some((suffix) => entry.endsWith(suffix))) {
3544
+ continue;
3545
+ }
3546
+ signal.throwIfAborted();
3547
+ const path = join2(directory, entry);
3548
+ const raw = await decodeProfile(path, timeoutMs, signal, strict);
3549
+ if (!raw) continue;
3550
+ let content;
3551
+ try {
3552
+ content = await readFile2(path);
3553
+ } catch (error) {
3554
+ if (strict) throw error;
3555
+ continue;
3556
+ }
3557
+ profiles.push({
3558
+ path,
3559
+ content,
3560
+ raw,
3561
+ uuid: text(raw.UUID) ?? basename(entry).replace(/\.[^.]+$/, "")
3562
+ });
3563
+ }
3564
+ }
3565
+ return profiles;
3566
+ }
3567
+ function profileAsset(decoded, now) {
3568
+ const profile = toProfile(decoded.uuid, decoded.raw, now);
3569
+ if (!profile) return null;
3570
+ const createdAt = text(decoded.raw.CreationDate);
3571
+ return {
3572
+ uuid: profile.uuid,
3573
+ contentHash: createHash2("sha256").update(decoded.content).digest("hex").toUpperCase(),
3574
+ name: profile.name,
3575
+ profileType: profile.type,
3576
+ bundleId: profile.bundleId,
3577
+ teamId: profile.teamId,
3578
+ teamName: profile.teamName,
3579
+ platforms: profile.platforms,
3580
+ deviceCount: stringList(decoded.raw.ProvisionedDevices).length,
3581
+ deviceUdids: stringList(decoded.raw.ProvisionedDevices),
3582
+ certificateSha1s: profile.certificateSha1s,
3583
+ createdAt,
3584
+ expiresAt: profile.expiresAt,
3585
+ expired: profile.expired,
3586
+ xcodeManaged: profile.xcodeManaged
3587
+ };
3588
+ }
3384
3589
  function dedupeProfiles(profiles) {
3385
3590
  const best = /* @__PURE__ */ new Map();
3386
3591
  for (const profile of profiles) {
@@ -3401,7 +3606,7 @@ function dedupeProfiles(profiles) {
3401
3606
  return [...best.values()];
3402
3607
  }
3403
3608
  var IDENTITY_PATTERN = /^\s*\d+\)\s+([0-9A-F]{40})\s+"(.+)"\s*$/i;
3404
- async function readIdentities(timeoutMs, signal) {
3609
+ async function readIdentities(timeoutMs, signal, strict = false) {
3405
3610
  try {
3406
3611
  const result = await captureCommand({
3407
3612
  command: "/usr/bin/security",
@@ -3409,6 +3614,7 @@ async function readIdentities(timeoutMs, signal) {
3409
3614
  timeoutMs: Math.min(timeoutMs, 1e4),
3410
3615
  signal
3411
3616
  });
3617
+ if (strict) assertCommandSucceeded(result, "Reading signing identities");
3412
3618
  if (result.exitCode !== 0) return [];
3413
3619
  const identities = /* @__PURE__ */ new Map();
3414
3620
  for (const line of result.stdout.split("\n")) {
@@ -3419,10 +3625,80 @@ async function readIdentities(timeoutMs, signal) {
3419
3625
  identities.set(sha1, { sha1, name, teamId: team?.[1] ?? null });
3420
3626
  }
3421
3627
  return [...identities.values()];
3422
- } catch {
3628
+ } catch (error) {
3629
+ if (strict) throw error;
3423
3630
  return [];
3424
3631
  }
3425
3632
  }
3633
+ function commonName(certificate) {
3634
+ return certificate.subject.split(/\n|,\s*/).find((part) => part.startsWith("CN="))?.slice(3) ?? certificate.subject;
3635
+ }
3636
+ function certificateType(name) {
3637
+ const known = [
3638
+ "Apple Development",
3639
+ "Apple Distribution",
3640
+ "iPhone Developer",
3641
+ "iPhone Distribution",
3642
+ "iOS Developer",
3643
+ "iOS Distribution",
3644
+ "Mac Developer",
3645
+ "Mac App Distribution",
3646
+ "Developer ID Application",
3647
+ "Developer ID Installer"
3648
+ ];
3649
+ return known.find((prefix) => name.startsWith(prefix)) ?? null;
3650
+ }
3651
+ function pemCertificates(value) {
3652
+ return value.match(
3653
+ /-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g
3654
+ ) ?? [];
3655
+ }
3656
+ async function readCertificates(timeoutMs, signal, strict = false) {
3657
+ const [certificateResult, identities] = await Promise.all([
3658
+ captureCommand({
3659
+ command: "/usr/bin/security",
3660
+ args: ["find-certificate", "-a", "-p"],
3661
+ timeoutMs: Math.min(timeoutMs, 2e4),
3662
+ signal
3663
+ }),
3664
+ readIdentities(timeoutMs, signal, strict)
3665
+ ]);
3666
+ if (strict) {
3667
+ assertCommandSucceeded(certificateResult, "Reading signing certificates");
3668
+ }
3669
+ if (certificateResult.exitCode !== 0) return [];
3670
+ const identityHashes = new Set(
3671
+ identities.map((identity) => identity.sha1.toUpperCase())
3672
+ );
3673
+ const assets = /* @__PURE__ */ new Map();
3674
+ for (const pem of pemCertificates(certificateResult.stdout)) {
3675
+ try {
3676
+ const certificate = new X509Certificate(pem);
3677
+ const name = commonName(certificate);
3678
+ const type = certificateType(name);
3679
+ if (!type) continue;
3680
+ const sha1 = certificate.fingerprint.replaceAll(":", "").toUpperCase();
3681
+ const expiresAt = new Date(certificate.validTo);
3682
+ const team = /\(([A-Z0-9]{10})\)\s*$/.exec(name);
3683
+ assets.set(sha1, {
3684
+ sha1,
3685
+ sha256: certificate.fingerprint256.replaceAll(":", "").toUpperCase(),
3686
+ name,
3687
+ teamId: team?.[1] ?? null,
3688
+ certificateType: type,
3689
+ notBefore: new Date(certificate.validFrom).toISOString(),
3690
+ expiresAt: expiresAt.toISOString(),
3691
+ expired: expiresAt.getTime() < Date.now(),
3692
+ hasPrivateKey: identityHashes.has(sha1)
3693
+ });
3694
+ } catch {
3695
+ continue;
3696
+ }
3697
+ }
3698
+ return [...assets.values()].sort(
3699
+ (left, right) => left.name.localeCompare(right.name)
3700
+ );
3701
+ }
3426
3702
  async function readArchiveBundles(archivePath, timeoutMs, signal) {
3427
3703
  const products = join2(archivePath, "Products");
3428
3704
  const bundles = [];
@@ -3543,6 +3819,140 @@ var inspectIosSigning = async (payload, timeoutMs, signal) => {
3543
3819
  ...inspection
3544
3820
  };
3545
3821
  };
3822
+ var successfulProcess = {
3823
+ exitCode: 0,
3824
+ signal: null,
3825
+ timedOut: false,
3826
+ cancelled: false
3827
+ };
3828
+ var scanSigningAssets = async (payload, timeoutMs, signal) => {
3829
+ signingScanPayload(payload);
3830
+ signal.throwIfAborted();
3831
+ const [decoded, certificates] = await Promise.all([
3832
+ decodedProfiles(timeoutMs, signal, true),
3833
+ readCertificates(timeoutMs, signal, true)
3834
+ ]);
3835
+ const byUuid = /* @__PURE__ */ new Map();
3836
+ for (const profile of decoded) {
3837
+ const asset = profileAsset(profile, Date.now());
3838
+ if (!asset) continue;
3839
+ const existing = byUuid.get(asset.uuid);
3840
+ if (!existing || (asset.expiresAt ?? "") > (existing.expiresAt ?? "")) {
3841
+ byUuid.set(asset.uuid, asset);
3842
+ }
3843
+ }
3844
+ return {
3845
+ ...successfulProcess,
3846
+ profiles: [...byUuid.values()].sort(
3847
+ (left, right) => left.name.localeCompare(right.name)
3848
+ ),
3849
+ certificates,
3850
+ warnings: []
3851
+ };
3852
+ };
3853
+ async function findDecodedProfile(uuid, timeoutMs, signal) {
3854
+ const profile = (await decodedProfiles(timeoutMs, signal)).find(
3855
+ (entry) => entry.uuid === uuid
3856
+ );
3857
+ if (!profile) throw new Error("Provisioning profile is no longer installed");
3858
+ return profile;
3859
+ }
3860
+ var readSigningProfile = async (payload, timeoutMs, signal) => {
3861
+ const { uuid } = signingProfileKeyPayload(payload);
3862
+ const profile = await findDecodedProfile(uuid, timeoutMs, signal);
3863
+ return {
3864
+ ...successfulProcess,
3865
+ uuid,
3866
+ contentBase64: profile.content.toString("base64"),
3867
+ sha256: createHash2("sha256").update(profile.content).digest("hex").toUpperCase()
3868
+ };
3869
+ };
3870
+ var installSigningProfile = async (payload, timeoutMs, signal) => {
3871
+ const { contentBase64 } = signingProfileInstallPayload(payload);
3872
+ const content = Buffer.from(contentBase64, "base64");
3873
+ if (!content.length) throw new Error("Provisioning profile is empty");
3874
+ const temporaryRoot = await mkdtemp(join2(tmpdir(), "ade-profile-"));
3875
+ const temporaryPath = join2(temporaryRoot, `${randomUUID()}.mobileprovision`);
3876
+ try {
3877
+ await writeFile2(temporaryPath, content, { mode: 384 });
3878
+ const raw = await decodeProfile(temporaryPath, timeoutMs, signal);
3879
+ if (!raw) throw new Error("Provisioning profile is invalid or unsigned");
3880
+ const uuid = text(raw.UUID);
3881
+ if (!uuid) throw new Error("Provisioning profile UUID is missing");
3882
+ const directory = PROFILE_DIRECTORIES[0];
3883
+ await mkdir2(directory, { recursive: true, mode: 448 });
3884
+ const destination = join2(directory, `${uuid}.mobileprovision`);
3885
+ await writeFile2(destination, content, { mode: 384 });
3886
+ return { ...successfulProcess, uuid };
3887
+ } finally {
3888
+ await rm(temporaryRoot, { recursive: true, force: true });
3889
+ }
3890
+ };
3891
+ var deleteSigningProfile = async (payload, timeoutMs, signal) => {
3892
+ const { uuid } = signingProfileKeyPayload(payload);
3893
+ const matches = (await decodedProfiles(timeoutMs, signal)).filter(
3894
+ (entry) => entry.uuid === uuid
3895
+ );
3896
+ for (const profile of matches) {
3897
+ signal.throwIfAborted();
3898
+ await rm(profile.path, { force: false });
3899
+ }
3900
+ return { ...successfulProcess, uuid, deleted: matches.length };
3901
+ };
3902
+ var importSigningIdentity = async (payload, timeoutMs, signal, _onLog, context) => {
3903
+ const input = signingIdentityImportPayload(payload);
3904
+ if (!context?.claimSigningSecretTransfer) {
3905
+ throw new Error("This agent cannot claim signing secret transfers");
3906
+ }
3907
+ const secret = await context.claimSigningSecretTransfer(input.transferId);
3908
+ const p12 = Buffer.from(secret.p12Base64, "base64");
3909
+ const hash = createHash2("sha256").update(p12).digest("hex").toUpperCase();
3910
+ if (hash !== input.sha256)
3911
+ throw new Error("Signing identity transfer changed");
3912
+ const temporaryRoot = await mkdtemp(join2(tmpdir(), "ade-identity-"));
3913
+ const path = join2(temporaryRoot, "identity.p12");
3914
+ try {
3915
+ await writeFile2(path, p12, { mode: 384 });
3916
+ const result = await captureCommand({
3917
+ command: "/usr/bin/security",
3918
+ args: [
3919
+ "import",
3920
+ path,
3921
+ "-P",
3922
+ secret.passphrase,
3923
+ "-T",
3924
+ "/usr/bin/codesign",
3925
+ "-T",
3926
+ "/usr/bin/security"
3927
+ ],
3928
+ timeoutMs: Math.min(timeoutMs, 6e4),
3929
+ signal
3930
+ });
3931
+ if (result.exitCode !== 0) {
3932
+ throw new Error(
3933
+ result.stderr.trim() || "Could not import signing identity"
3934
+ );
3935
+ }
3936
+ return { ...successfulProcess, sha256: input.sha256 };
3937
+ } finally {
3938
+ await rm(temporaryRoot, { recursive: true, force: true });
3939
+ }
3940
+ };
3941
+ var deleteSigningIdentity = async (payload, timeoutMs, signal) => {
3942
+ const { sha1 } = signingIdentityDeletePayload(payload);
3943
+ const result = await captureCommand({
3944
+ command: "/usr/bin/security",
3945
+ args: ["delete-identity", "-Z", sha1],
3946
+ timeoutMs: Math.min(timeoutMs, 3e4),
3947
+ signal
3948
+ });
3949
+ if (result.exitCode !== 0) {
3950
+ throw new Error(
3951
+ result.stderr.trim() || "Could not delete signing identity"
3952
+ );
3953
+ }
3954
+ return { ...successfulProcess, sha1 };
3955
+ };
3546
3956
 
3547
3957
  // src/handlers/ccusage.ts
3548
3958
  import { Buffer as Buffer2 } from "node:buffer";
@@ -3599,10 +4009,10 @@ async function runCcusage(payload, timeoutMs, signal, onLog) {
3599
4009
  }
3600
4010
 
3601
4011
  // src/handlers/build-data.ts
3602
- import { lstat, opendir, readdir as readdir2, realpath, rm } from "node:fs/promises";
4012
+ import { lstat, opendir, readdir as readdir2, realpath, rm as rm2 } from "node:fs/promises";
3603
4013
  import { homedir as homedir3 } from "node:os";
3604
4014
  import { basename as basename2, dirname as dirname2, isAbsolute, join as join3, resolve } from "node:path";
3605
- var successfulProcess = {
4015
+ var successfulProcess2 = {
3606
4016
  exitCode: 0,
3607
4017
  signal: null,
3608
4018
  timedOut: false,
@@ -3695,6 +4105,43 @@ async function scanRoot(configuredRoot, timeoutMs, signal) {
3695
4105
  entries.sort((first, second) => first.name.localeCompare(second.name));
3696
4106
  return { entries, warning: null };
3697
4107
  }
4108
+ async function scanDeviceSupport(signal) {
4109
+ const configuredRoot = join3(
4110
+ process.env.ADE_IOS_DEVICE_SUPPORT_DIRECTORY ?? homedir3(),
4111
+ ...process.env.ADE_IOS_DEVICE_SUPPORT_DIRECTORY ? [] : ["Library", "Developer", "Xcode", "iOS DeviceSupport"]
4112
+ );
4113
+ signal.throwIfAborted();
4114
+ let rootPath2;
4115
+ try {
4116
+ rootPath2 = await realpath(configuredRoot);
4117
+ } catch (error) {
4118
+ if (error.code === "ENOENT") {
4119
+ return { entries: [], warning: null };
4120
+ }
4121
+ return {
4122
+ entries: [],
4123
+ warning: `${configuredRoot}: ${errorMessage(error)}`
4124
+ };
4125
+ }
4126
+ try {
4127
+ const children = await readdir2(rootPath2, { withFileTypes: true });
4128
+ return {
4129
+ entries: children.filter((child) => child.isDirectory() && !child.isSymbolicLink()).map((child) => ({
4130
+ path: join3(rootPath2, child.name),
4131
+ rootPath: rootPath2,
4132
+ name: child.name,
4133
+ kind: "DEVICE_SUPPORT",
4134
+ workspacePath: null
4135
+ })).sort((first, second) => first.name.localeCompare(second.name)),
4136
+ warning: null
4137
+ };
4138
+ } catch (error) {
4139
+ return {
4140
+ entries: [],
4141
+ warning: `${rootPath2}: ${errorMessage(error)}`
4142
+ };
4143
+ }
4144
+ }
3698
4145
  var scanBuildData = async (rawPayload, timeoutMs, signal) => {
3699
4146
  const payload = buildDataScanPayload(rawPayload);
3700
4147
  const roots = await configuredRoots(payload);
@@ -3714,7 +4161,10 @@ var scanBuildData = async (rawPayload, timeoutMs, signal) => {
3714
4161
  entries.push(...result.entries);
3715
4162
  if (result.warning) warnings.push(result.warning);
3716
4163
  }
3717
- return { ...successfulProcess, entries, warnings };
4164
+ const deviceSupport = await scanDeviceSupport(signal);
4165
+ entries.push(...deviceSupport.entries);
4166
+ if (deviceSupport.warning) warnings.push(deviceSupport.warning);
4167
+ return { ...successfulProcess2, entries, warnings };
3718
4168
  };
3719
4169
  function assertDirectChild(rootPath2, path) {
3720
4170
  if (!isAbsolute(rootPath2) || !isAbsolute(path)) {
@@ -3772,7 +4222,7 @@ var sizeBuildData = async (rawPayload, _timeoutMs, signal) => {
3772
4222
  });
3773
4223
  }
3774
4224
  }
3775
- return { ...successfulProcess, sizes };
4225
+ return { ...successfulProcess2, sizes };
3776
4226
  };
3777
4227
  var deleteBuildData = async (rawPayload, _timeoutMs, signal) => {
3778
4228
  const payload = buildDataTargetsPayload(rawPayload);
@@ -3789,7 +4239,7 @@ var deleteBuildData = async (rawPayload, _timeoutMs, signal) => {
3789
4239
  if (!stats.isDirectory() || stats.isSymbolicLink()) {
3790
4240
  throw new Error("Build Data target is not a directory");
3791
4241
  }
3792
- await rm(target2.path, { recursive: true, force: false, maxRetries: 3 });
4242
+ await rm2(target2.path, { recursive: true, force: false, maxRetries: 3 });
3793
4243
  deleted.push({ path: target2.path, deleted: true, error: null });
3794
4244
  } catch (error) {
3795
4245
  signal.throwIfAborted();
@@ -3800,14 +4250,14 @@ var deleteBuildData = async (rawPayload, _timeoutMs, signal) => {
3800
4250
  });
3801
4251
  }
3802
4252
  }
3803
- return { ...successfulProcess, deleted };
4253
+ return { ...successfulProcess2, deleted };
3804
4254
  };
3805
4255
 
3806
4256
  // src/handlers/codebases.ts
3807
4257
  import { readdir as readdir3, realpath as realpath2, stat as stat3 } from "node:fs/promises";
3808
4258
  import { homedir as homedir4 } from "node:os";
3809
4259
  import { dirname as dirname3, join as join4, resolve as resolve2 } from "node:path";
3810
- var successfulProcess2 = {
4260
+ var successfulProcess3 = {
3811
4261
  exitCode: 0,
3812
4262
  signal: null,
3813
4263
  timedOut: false,
@@ -3898,7 +4348,7 @@ async function inspectCodebaseProcess(selectedFolder, timeoutMs, signal, expecte
3898
4348
  throw new Error("Folder is not a directory");
3899
4349
  } catch (error) {
3900
4350
  return {
3901
- ...successfulProcess2,
4351
+ ...successfulProcess3,
3902
4352
  snapshot: {
3903
4353
  ...base,
3904
4354
  availability: "MISSING",
@@ -3915,7 +4365,7 @@ async function inspectCodebaseProcess(selectedFolder, timeoutMs, signal, expecte
3915
4365
  );
3916
4366
  if (rootResult.exitCode !== 0) {
3917
4367
  return {
3918
- ...successfulProcess2,
4368
+ ...successfulProcess3,
3919
4369
  snapshot: {
3920
4370
  ...base,
3921
4371
  folder: selected,
@@ -3935,7 +4385,7 @@ async function inspectCodebaseProcess(selectedFolder, timeoutMs, signal, expecte
3935
4385
  );
3936
4386
  if (bare.stdout.trim() === "true") {
3937
4387
  return {
3938
- ...successfulProcess2,
4388
+ ...successfulProcess3,
3939
4389
  snapshot: {
3940
4390
  ...base,
3941
4391
  folder,
@@ -3967,7 +4417,7 @@ async function inspectCodebaseProcess(selectedFolder, timeoutMs, signal, expecte
3967
4417
  ]);
3968
4418
  if (originResult.exitCode !== 0) {
3969
4419
  return {
3970
- ...successfulProcess2,
4420
+ ...successfulProcess3,
3971
4421
  snapshot: {
3972
4422
  ...base,
3973
4423
  folder,
@@ -4014,7 +4464,7 @@ async function inspectCodebaseProcess(selectedFolder, timeoutMs, signal, expecte
4014
4464
  const syncState = !branch ? "DETACHED" : !upstream ? "NO_UPSTREAM" : ahead === null || behind === null ? "UNKNOWN" : ahead > 0 && behind > 0 ? "DIVERGED" : ahead > 0 ? "AHEAD" : behind > 0 ? "BEHIND" : "IN_SYNC";
4015
4465
  const mismatch = expectedOrigin !== void 0 && origin2.canonicalOrigin !== expectedOrigin;
4016
4466
  return {
4017
- ...successfulProcess2,
4467
+ ...successfulProcess3,
4018
4468
  snapshot: {
4019
4469
  folder,
4020
4470
  observedOrigin: origin2.sanitizedOrigin,
@@ -4036,7 +4486,7 @@ async function inspectCodebaseProcess(selectedFolder, timeoutMs, signal, expecte
4036
4486
  } catch (error) {
4037
4487
  if (error instanceof InterruptedGitInspection) return error.result;
4038
4488
  return {
4039
- ...successfulProcess2,
4489
+ ...successfulProcess3,
4040
4490
  snapshot: {
4041
4491
  ...base,
4042
4492
  folder: selected,
@@ -4097,7 +4547,7 @@ var browseCodebaseDirectories = async (payload) => {
4097
4547
  entries: entries.slice(0, 1e3),
4098
4548
  truncated: entries.length > 1e3
4099
4549
  };
4100
- return { ...successfulProcess2, listing };
4550
+ return { ...successfulProcess3, listing };
4101
4551
  };
4102
4552
  var inspectCodebaseFolder = async (payload, timeoutMs, signal) => {
4103
4553
  const input = codebaseJobPayload(payload);
@@ -4183,7 +4633,7 @@ var fetchCodebase = async (payload, timeoutMs, signal) => {
4183
4633
  if (!("snapshot" in beforeResult)) return beforeResult;
4184
4634
  const before = beforeResult.snapshot;
4185
4635
  if (before.availability !== "AVAILABLE") {
4186
- return { ...successfulProcess2, exitCode: 1, snapshot: before };
4636
+ return { ...successfulProcess3, exitCode: 1, snapshot: before };
4187
4637
  }
4188
4638
  let result;
4189
4639
  try {
@@ -4379,7 +4829,7 @@ var inspectCodebaseGit = async (payload, timeoutMs, signal) => {
4379
4829
  );
4380
4830
  if (input.action === "STATE") {
4381
4831
  return {
4382
- ...successfulProcess2,
4832
+ ...successfulProcess3,
4383
4833
  state: await inspectCodebaseGitState(folder, timeoutMs, signal)
4384
4834
  };
4385
4835
  }
@@ -4404,7 +4854,7 @@ var inspectCodebaseGit = async (payload, timeoutMs, signal) => {
4404
4854
  );
4405
4855
  const patch = truncateUtf8(result.stdout, MAX_CODEBASE_STASH_PATCH_BYTES);
4406
4856
  return {
4407
- ...successfulProcess2,
4857
+ ...successfulProcess3,
4408
4858
  diff: {
4409
4859
  oid: input.stashOid,
4410
4860
  patch: patch.value,
@@ -4623,7 +5073,7 @@ var operateCodebaseGit = async (payload, timeoutMs, signal) => {
4623
5073
  }
4624
5074
  }
4625
5075
  return {
4626
- ...successfulProcess2,
5076
+ ...successfulProcess3,
4627
5077
  snapshot: await inspectCodebase(
4628
5078
  folder,
4629
5079
  Math.min(timeoutMs, 3e4),
@@ -4640,25 +5090,25 @@ var operateCodebaseGit = async (payload, timeoutMs, signal) => {
4640
5090
 
4641
5091
  // src/handlers/skills.ts
4642
5092
  import { execFile } from "node:child_process";
4643
- import { randomUUID } from "node:crypto";
5093
+ import { randomUUID as randomUUID2 } from "node:crypto";
4644
5094
  import {
4645
5095
  access,
4646
5096
  chmod as chmod2,
4647
5097
  lstat as lstat2,
4648
- mkdir as mkdir2,
4649
- readFile as readFile2,
5098
+ mkdir as mkdir3,
5099
+ readFile as readFile3,
4650
5100
  realpath as realpath3,
4651
5101
  readdir as readdir4,
4652
5102
  rename as rename2,
4653
- rm as rm2,
5103
+ rm as rm3,
4654
5104
  stat as stat4,
4655
- writeFile as writeFile2
5105
+ writeFile as writeFile3
4656
5106
  } from "node:fs/promises";
4657
5107
  import { homedir as homedir5 } from "node:os";
4658
5108
  import { dirname as dirname4, isAbsolute as isAbsolute2, join as join5, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
4659
5109
  import { promisify } from "node:util";
4660
5110
  var executeFile = promisify(execFile);
4661
- var successfulProcess3 = {
5111
+ var successfulProcess4 = {
4662
5112
  exitCode: 0,
4663
5113
  signal: null,
4664
5114
  timedOut: false,
@@ -4767,7 +5217,7 @@ async function listPackageFiles(skillDirectory) {
4767
5217
  throw new Error("Skill exceeds the package size limit");
4768
5218
  files.push({
4769
5219
  path: relative2(skillDirectory, path).split(sep2).join("/"),
4770
- contentsBase64: (await readFile2(path)).toString("base64"),
5220
+ contentsBase64: (await readFile3(path)).toString("base64"),
4771
5221
  executable: (metadata.mode & 73) !== 0
4772
5222
  });
4773
5223
  }
@@ -4889,7 +5339,7 @@ var scanSkills = async (payload) => {
4889
5339
  )
4890
5340
  )).flat();
4891
5341
  return {
4892
- ...successfulProcess3,
5342
+ ...successfulProcess4,
4893
5343
  configuredTools: observations,
4894
5344
  installations,
4895
5345
  warnings: warnings.slice(0, 500)
@@ -4914,7 +5364,7 @@ var readSkills = async (payload) => {
4914
5364
  package: await readPackage(join5(root, request.skillName))
4915
5365
  });
4916
5366
  }
4917
- return { ...successfulProcess3, packages };
5367
+ return { ...successfulProcess4, packages };
4918
5368
  };
4919
5369
  async function gitExcludePath(folder) {
4920
5370
  const result = await executeFile("git", [
@@ -4929,10 +5379,10 @@ async function gitExcludePath(folder) {
4929
5379
  }
4930
5380
  async function updateManagedExclude(folder, relativeSkillPath, present) {
4931
5381
  const excludePath = await gitExcludePath(folder);
4932
- await mkdir2(dirname4(excludePath), { recursive: true });
5382
+ await mkdir3(dirname4(excludePath), { recursive: true });
4933
5383
  let existing = "";
4934
5384
  try {
4935
- existing = await readFile2(excludePath, "utf8");
5385
+ existing = await readFile3(excludePath, "utf8");
4936
5386
  } catch {
4937
5387
  }
4938
5388
  const start = existing.indexOf(MANAGED_EXCLUDE_START);
@@ -4952,7 +5402,7 @@ async function updateManagedExclude(folder, relativeSkillPath, present) {
4952
5402
  const block = managed.size ? `${MANAGED_EXCLUDE_START}
4953
5403
  ${[...managed].sort().join("\n")}
4954
5404
  ${MANAGED_EXCLUDE_END}` : "";
4955
- await writeFile2(
5405
+ await writeFile3(
4956
5406
  excludePath,
4957
5407
  `${[before, block, after].filter(Boolean).join("\n\n")}
4958
5408
  `,
@@ -4975,17 +5425,17 @@ async function writePackage(location, skillPackage) {
4975
5425
  const root = rootPath(location);
4976
5426
  const destination = join5(root, skillPackage.name);
4977
5427
  await assertUntracked(location, destination);
4978
- await mkdir2(root, { recursive: true });
4979
- const temporary = join5(root, `.${skillPackage.name}.${randomUUID()}.tmp`);
4980
- const backup = join5(root, `.${skillPackage.name}.${randomUUID()}.bak`);
4981
- await mkdir2(temporary, { recursive: true });
5428
+ await mkdir3(root, { recursive: true });
5429
+ const temporary = join5(root, `.${skillPackage.name}.${randomUUID2()}.tmp`);
5430
+ const backup = join5(root, `.${skillPackage.name}.${randomUUID2()}.bak`);
5431
+ await mkdir3(temporary, { recursive: true });
4982
5432
  try {
4983
5433
  for (const file of skillPackage.files) {
4984
5434
  const path = resolve3(temporary, ...file.path.split("/"));
4985
5435
  if (!path.startsWith(`${temporary}${sep2}`))
4986
5436
  throw new Error("Skill file escaped temporary directory");
4987
- await mkdir2(dirname4(path), { recursive: true });
4988
- await writeFile2(path, Buffer.from(file.contentsBase64, "base64"));
5437
+ await mkdir3(dirname4(path), { recursive: true });
5438
+ await writeFile3(path, Buffer.from(file.contentsBase64, "base64"));
4989
5439
  await chmod2(path, file.executable ? 493 : 420);
4990
5440
  }
4991
5441
  let hadDestination = false;
@@ -4998,14 +5448,14 @@ async function writePackage(location, skillPackage) {
4998
5448
  }
4999
5449
  try {
5000
5450
  await rename2(temporary, destination);
5001
- if (hadDestination) await rm2(backup, { recursive: true, force: true });
5451
+ if (hadDestination) await rm3(backup, { recursive: true, force: true });
5002
5452
  } catch (error) {
5003
5453
  if (hadDestination) await rename2(backup, destination);
5004
5454
  throw error;
5005
5455
  }
5006
5456
  } finally {
5007
- await rm2(temporary, { recursive: true, force: true });
5008
- await rm2(backup, { recursive: true, force: true });
5457
+ await rm3(temporary, { recursive: true, force: true });
5458
+ await rm3(backup, { recursive: true, force: true });
5009
5459
  }
5010
5460
  return destination;
5011
5461
  }
@@ -5025,7 +5475,7 @@ var applySkills = async (payload) => {
5025
5475
  packageHash: operation.package.packageHash
5026
5476
  });
5027
5477
  } else {
5028
- await rm2(destination, { recursive: true, force: true });
5478
+ await rm3(destination, { recursive: true, force: true });
5029
5479
  results.push({
5030
5480
  kind: operation.kind,
5031
5481
  path: destination,
@@ -5040,13 +5490,13 @@ var applySkills = async (payload) => {
5040
5490
  );
5041
5491
  }
5042
5492
  }
5043
- return { ...successfulProcess3, results };
5493
+ return { ...successfulProcess4, results };
5044
5494
  };
5045
5495
 
5046
5496
  // src/handlers/worktrees.ts
5047
5497
  import { createWriteStream, watch } from "node:fs";
5048
- import { mkdtemp, open, readFile as readFile3, realpath as realpath4, rm as rm3, stat as stat5 } from "node:fs/promises";
5049
- import { tmpdir } from "node:os";
5498
+ import { mkdtemp as mkdtemp2, open, readFile as readFile4, realpath as realpath4, rm as rm4, stat as stat5 } from "node:fs/promises";
5499
+ import { tmpdir as tmpdir2 } from "node:os";
5050
5500
  import { basename as basename3, dirname as dirname5, join as join6, relative as relative4 } from "node:path";
5051
5501
  import { spawn as spawn4 } from "node:child_process";
5052
5502
 
@@ -5242,7 +5692,7 @@ async function worktreeCodeStateHash(folder, timeoutMs, signal) {
5242
5692
  }
5243
5693
 
5244
5694
  // src/handlers/worktrees.ts
5245
- var successfulProcess4 = {
5695
+ var successfulProcess5 = {
5246
5696
  exitCode: 0,
5247
5697
  signal: null,
5248
5698
  timedOut: false,
@@ -5686,7 +6136,7 @@ async function untrackedLines(folder, path) {
5686
6136
  try {
5687
6137
  const file = await stat5(`${folder}/${path}`);
5688
6138
  if (!file.isFile() || file.size > 1024 * 1024) return null;
5689
- const contents = await readFile3(`${folder}/${path}`);
6139
+ const contents = await readFile4(`${folder}/${path}`);
5690
6140
  if (contents.includes(0)) return null;
5691
6141
  const text2 = contents.toString("utf8");
5692
6142
  return text2 ? text2.split("\n").length - (text2.endsWith("\n") ? 1 : 0) : 0;
@@ -6137,7 +6587,7 @@ var inspectWorktreeDiff = async (payload, timeoutMs, signal) => {
6137
6587
  const input = worktreeDiffPayload(payload);
6138
6588
  const folder = await validateWorktree(input, timeoutMs, signal);
6139
6589
  return {
6140
- ...successfulProcess4,
6590
+ ...successfulProcess5,
6141
6591
  diff: await inspectRequestedDiff(input, folder, timeoutMs, signal)
6142
6592
  };
6143
6593
  };
@@ -6239,7 +6689,7 @@ var downloadWorktreeDiffAsset = async (payload, timeoutMs, signal, _onLog, conte
6239
6689
  if (!/^\d+$/.test(size) || Number(size) > 20 * 1024 * 1024) {
6240
6690
  throw new Error("Diff image exceeds the 20 MiB limit");
6241
6691
  }
6242
- temporaryDirectory = await mkdtemp(join6(tmpdir(), "ade-diff-image-"));
6692
+ temporaryDirectory = await mkdtemp2(join6(tmpdir2(), "ade-diff-image-"));
6243
6693
  uploadPath = join6(temporaryDirectory, basename3(input.path));
6244
6694
  await writeGitObject(
6245
6695
  folder,
@@ -6259,10 +6709,10 @@ var downloadWorktreeDiffAsset = async (payload, timeoutMs, signal, _onLog, conte
6259
6709
  filename: basename3(input.path),
6260
6710
  contentType: imageContentType(input.path)
6261
6711
  });
6262
- return successfulProcess4;
6712
+ return successfulProcess5;
6263
6713
  } finally {
6264
6714
  if (temporaryDirectory) {
6265
- await rm3(temporaryDirectory, { recursive: true, force: true });
6715
+ await rm4(temporaryDirectory, { recursive: true, force: true });
6266
6716
  }
6267
6717
  }
6268
6718
  };
@@ -6274,11 +6724,11 @@ var watchWorktree = async (payload, timeoutMs, signal, _onLog, context) => {
6274
6724
  closeWorktreeWatch(current);
6275
6725
  activeWorktreeWatches.delete(input.gitDirectory);
6276
6726
  }
6277
- return successfulProcess4;
6727
+ return successfulProcess5;
6278
6728
  }
6279
6729
  if (!context) throw new Error("Worktree activity reporting is unavailable");
6280
6730
  const folder = await validateWorktree(input, timeoutMs, signal);
6281
- if (current?.watchId === input.watchId) return successfulProcess4;
6731
+ if (current?.watchId === input.watchId) return successfulProcess5;
6282
6732
  if (current) {
6283
6733
  closeWorktreeWatch(current);
6284
6734
  activeWorktreeWatches.delete(input.gitDirectory);
@@ -6320,14 +6770,14 @@ var watchWorktree = async (payload, timeoutMs, signal, _onLog, context) => {
6320
6770
  activeWorktreeWatches.delete(input.gitDirectory);
6321
6771
  throw error;
6322
6772
  }
6323
- return successfulProcess4;
6773
+ return successfulProcess5;
6324
6774
  };
6325
6775
  var inspectWorktree = async (payload, timeoutMs, signal) => {
6326
6776
  const input = worktreeJobPayload(payload);
6327
6777
  const folder = await validateWorktree(input, timeoutMs, signal);
6328
6778
  if (!input.baseBranch) throw new Error("A base branch is required");
6329
6779
  return {
6330
- ...successfulProcess4,
6780
+ ...successfulProcess5,
6331
6781
  detail: await inspectWorktreeDetail(
6332
6782
  folder,
6333
6783
  input.baseBranch,
@@ -6558,7 +7008,7 @@ var branchWorktree = async (payload, timeoutMs, signal) => {
6558
7008
  throw new Error(worktree.error || "Could not inspect the updated worktree");
6559
7009
  }
6560
7010
  return {
6561
- ...successfulProcess4,
7011
+ ...successfulProcess5,
6562
7012
  worktree,
6563
7013
  branch,
6564
7014
  baseBranch: input.baseBranch,
@@ -6613,7 +7063,7 @@ var pushMovedWorktree = async (payload, timeoutMs, signal) => {
6613
7063
  throw new Error("The source branch changed while it was being pushed");
6614
7064
  }
6615
7065
  return {
6616
- ...successfulProcess4,
7066
+ ...successfulProcess5,
6617
7067
  moveId: input.moveId,
6618
7068
  branch,
6619
7069
  headSha: pushedHeadSha
@@ -6813,7 +7263,7 @@ var checkoutMovedWorktree = async (payload, timeoutMs, signal) => {
6813
7263
  if (switched.exitCode !== 0) {
6814
7264
  if (!input.stashOnFailure && hasChanges(targetChanges)) {
6815
7265
  return {
6816
- ...successfulProcess4,
7266
+ ...successfulProcess5,
6817
7267
  moveId: input.moveId,
6818
7268
  outcome: "NEEDS_STASH",
6819
7269
  message: cleanError2(
@@ -6858,7 +7308,7 @@ var checkoutMovedWorktree = async (payload, timeoutMs, signal) => {
6858
7308
  );
6859
7309
  }
6860
7310
  return {
6861
- ...successfulProcess4,
7311
+ ...successfulProcess5,
6862
7312
  moveId: input.moveId,
6863
7313
  outcome: "CHECKED_OUT",
6864
7314
  worktree,
@@ -6956,7 +7406,7 @@ var deleteWorktree = async (payload, timeoutMs, signal) => {
6956
7406
  );
6957
7407
  }
6958
7408
  return {
6959
- ...successfulProcess4,
7409
+ ...successfulProcess5,
6960
7410
  moveId: input.moveId,
6961
7411
  deleted: true,
6962
7412
  branch,
@@ -7050,7 +7500,7 @@ var operateWorktree = async (payload, timeoutMs, signal) => {
7050
7500
  break;
7051
7501
  }
7052
7502
  return {
7053
- ...successfulProcess4,
7503
+ ...successfulProcess5,
7054
7504
  worktree: await inspectWorktreeItem(
7055
7505
  folder,
7056
7506
  folder,
@@ -7063,22 +7513,22 @@ var operateWorktree = async (payload, timeoutMs, signal) => {
7063
7513
  };
7064
7514
 
7065
7515
  // src/handlers/builds.ts
7066
- import { createHash as createHash4, randomUUID as randomUUID2 } from "node:crypto";
7516
+ import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
7067
7517
  import {
7068
7518
  cp,
7069
- mkdir as mkdir3,
7070
- mkdtemp as mkdtemp2,
7519
+ mkdir as mkdir4,
7520
+ mkdtemp as mkdtemp3,
7071
7521
  open as open2,
7072
7522
  readdir as readdir5,
7073
- readFile as readFile4,
7523
+ readFile as readFile5,
7074
7524
  realpath as realpath5,
7075
7525
  rename as rename3,
7076
- rm as rm4,
7526
+ rm as rm5,
7077
7527
  stat as stat6,
7078
- writeFile as writeFile3
7528
+ writeFile as writeFile4
7079
7529
  } from "node:fs/promises";
7080
7530
  import { createReadStream as createReadStream3, createWriteStream as createWriteStream2 } from "node:fs";
7081
- import { tmpdir as tmpdir2 } from "node:os";
7531
+ import { tmpdir as tmpdir3 } from "node:os";
7082
7532
  import { pipeline } from "node:stream/promises";
7083
7533
  import {
7084
7534
  basename as basename4,
@@ -7090,7 +7540,7 @@ import {
7090
7540
  sep as sep4
7091
7541
  } from "node:path";
7092
7542
  import { spawn as spawn5 } from "node:child_process";
7093
- var successfulProcess5 = {
7543
+ var successfulProcess6 = {
7094
7544
  exitCode: 0,
7095
7545
  signal: null,
7096
7546
  timedOut: false,
@@ -7283,7 +7733,7 @@ async function workspaceProjectPaths(workspacePath2, folder) {
7283
7733
  const contentsPath = join7(workspacePath2, "contents.xcworkspacedata");
7284
7734
  let contents;
7285
7735
  try {
7286
- contents = await readFile4(contentsPath, "utf8");
7736
+ contents = await readFile5(contentsPath, "utf8");
7287
7737
  } catch {
7288
7738
  return [];
7289
7739
  }
@@ -7384,11 +7834,211 @@ async function testPlans(source, absolutePath, folder, scheme, timeoutMs, signal
7384
7834
  }
7385
7835
  return [];
7386
7836
  }
7837
+ function buildSetting(settings, key) {
7838
+ const value = settings[key];
7839
+ return typeof value === "string" && value.trim() ? value.trim() : null;
7840
+ }
7841
+ function signingPlatform(settings) {
7842
+ const platform = buildSetting(settings, "PLATFORM_NAME");
7843
+ if (platform === "iphoneos") return "iOS";
7844
+ if (platform === "watchos") return "watchOS";
7845
+ if (platform === "appletvos") return "tvOS";
7846
+ if (platform === "xros") return "visionOS";
7847
+ if (platform === "macosx") return "macOS";
7848
+ return platform;
7849
+ }
7850
+ function requiresProvisioningProfile(productType) {
7851
+ return typeof productType === "string" && (productType.includes("application") || productType.includes("app-extension") || productType.includes("watchkit"));
7852
+ }
7853
+ function pbxObject(objects, id) {
7854
+ if (typeof id !== "string") return null;
7855
+ const value = objects[id];
7856
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
7857
+ }
7858
+ function dependentSigningTargetNamesFromPbxProject(value, rootTargetNames) {
7859
+ if (!value || typeof value !== "object" || Array.isArray(value)) return [];
7860
+ const rawObjects = value.objects;
7861
+ if (!rawObjects || typeof rawObjects !== "object" || Array.isArray(rawObjects))
7862
+ return [];
7863
+ const objects = rawObjects;
7864
+ const roots = new Set(rootTargetNames);
7865
+ const targetEntries = Object.entries(objects).filter(([, target2]) => {
7866
+ if (!target2 || typeof target2 !== "object" || Array.isArray(target2)) {
7867
+ return false;
7868
+ }
7869
+ const record = target2;
7870
+ return (record.isa === "PBXNativeTarget" || record.isa === "PBXAggregateTarget") && typeof record.name === "string";
7871
+ });
7872
+ const queue = targetEntries.filter(
7873
+ ([, target2]) => roots.has(target2.name)
7874
+ ).map(([id]) => id);
7875
+ const visited = new Set(queue);
7876
+ const signingTargets = [];
7877
+ while (queue.length) {
7878
+ const target2 = pbxObject(objects, queue.shift());
7879
+ if (!target2 || !Array.isArray(target2.dependencies)) continue;
7880
+ for (const dependencyId of target2.dependencies) {
7881
+ const dependency = pbxObject(objects, dependencyId);
7882
+ const dependentTargetId = dependency?.target;
7883
+ if (typeof dependentTargetId !== "string") continue;
7884
+ const dependentTarget = pbxObject(objects, dependentTargetId);
7885
+ if (!dependentTarget) continue;
7886
+ if (!visited.has(dependentTargetId)) {
7887
+ visited.add(dependentTargetId);
7888
+ queue.push(dependentTargetId);
7889
+ }
7890
+ const name = dependentTarget.name;
7891
+ if (typeof name === "string" && !roots.has(name) && requiresProvisioningProfile(dependentTarget.productType)) {
7892
+ signingTargets.push(name);
7893
+ }
7894
+ }
7895
+ }
7896
+ return uniqueSorted(signingTargets);
7897
+ }
7898
+ function signingRequirementsFromBuildSettings(value) {
7899
+ if (!Array.isArray(value)) return [];
7900
+ const requirements = /* @__PURE__ */ new Map();
7901
+ for (const entry of value) {
7902
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) continue;
7903
+ const record = entry;
7904
+ const rawSettings = record.buildSettings;
7905
+ if (!rawSettings || typeof rawSettings !== "object" || Array.isArray(rawSettings)) {
7906
+ continue;
7907
+ }
7908
+ const settings = rawSettings;
7909
+ const bundleId = buildSetting(settings, "PRODUCT_BUNDLE_IDENTIFIER");
7910
+ if (!bundleId || buildSetting(settings, "CODE_SIGNING_ALLOWED") === "NO") {
7911
+ continue;
7912
+ }
7913
+ const productType = buildSetting(settings, "PRODUCT_TYPE") ?? "";
7914
+ if (productType && !requiresProvisioningProfile(productType)) {
7915
+ continue;
7916
+ }
7917
+ const target2 = typeof record.target === "string" && record.target.trim() || bundleId;
7918
+ const requirement = {
7919
+ bundleId,
7920
+ name: buildSetting(settings, "PRODUCT_NAME") ?? buildSetting(settings, "FULL_PRODUCT_NAME") ?? target2,
7921
+ target: target2,
7922
+ platform: signingPlatform(settings),
7923
+ teamId: buildSetting(settings, "DEVELOPMENT_TEAM"),
7924
+ provisioningProfileSpecifier: buildSetting(settings, "PROVISIONING_PROFILE_SPECIFIER") ?? buildSetting(settings, "PROVISIONING_PROFILE")
7925
+ };
7926
+ const existing = requirements.get(bundleId);
7927
+ if (!existing || !existing.provisioningProfileSpecifier && requirement.provisioningProfileSpecifier) {
7928
+ requirements.set(bundleId, requirement);
7929
+ }
7930
+ }
7931
+ return [...requirements.values()].sort(
7932
+ (left, right) => left.name.localeCompare(right.name)
7933
+ );
7934
+ }
7935
+ function mergeSigningRequirements(requirements) {
7936
+ const merged = /* @__PURE__ */ new Map();
7937
+ for (const requirement of requirements) {
7938
+ const existing = merged.get(requirement.bundleId);
7939
+ if (!existing || !existing.provisioningProfileSpecifier && requirement.provisioningProfileSpecifier) {
7940
+ merged.set(requirement.bundleId, requirement);
7941
+ }
7942
+ }
7943
+ return [...merged.values()].sort(
7944
+ (left, right) => left.name.localeCompare(right.name)
7945
+ );
7946
+ }
7947
+ async function dependentSigningRequirements(source, absolutePath, folder, rootTargetNames, configuration, timeoutMs, signal) {
7948
+ const projects = source.kind === "PROJECT" ? [absolutePath] : source.kind === "WORKSPACE" ? await workspaceProjectPaths(absolutePath, folder) : [];
7949
+ const targets = [];
7950
+ for (const project of projects.slice(0, 50)) {
7951
+ const converted = await command2(
7952
+ "plutil",
7953
+ ["-convert", "json", "-o", "-", join7(project, "project.pbxproj")],
7954
+ Math.min(timeoutMs, 15e3),
7955
+ signal,
7956
+ folder
7957
+ );
7958
+ if (converted.exitCode !== 0) continue;
7959
+ const names = dependentSigningTargetNamesFromPbxProject(
7960
+ parseJson(converted.stdout, "Xcode project graph"),
7961
+ rootTargetNames
7962
+ );
7963
+ targets.push(...names.map((name) => ({ project, name })));
7964
+ }
7965
+ const requirements = [];
7966
+ for (const target2 of targets.slice(0, 50)) {
7967
+ const result = await command2(
7968
+ "xcrun",
7969
+ [
7970
+ "xcodebuild",
7971
+ "-project",
7972
+ target2.project,
7973
+ "-target",
7974
+ target2.name,
7975
+ "-configuration",
7976
+ configuration,
7977
+ "-showBuildSettings",
7978
+ "-json"
7979
+ ],
7980
+ Math.min(timeoutMs, 6e4),
7981
+ signal,
7982
+ folder
7983
+ );
7984
+ if (result.exitCode !== 0) continue;
7985
+ try {
7986
+ requirements.push(
7987
+ ...signingRequirementsFromBuildSettings(JSON.parse(result.stdout))
7988
+ );
7989
+ } catch {
7990
+ }
7991
+ }
7992
+ return requirements;
7993
+ }
7994
+ async function inspectSigningRequirements(source, absolutePath, folder, scheme, configuration, timeoutMs, signal) {
7995
+ if (!scheme || !configuration) return [];
7996
+ const result = requireSuccess3(
7997
+ await command2(
7998
+ "xcrun",
7999
+ [
8000
+ "xcodebuild",
8001
+ ...sourceArguments(source, absolutePath),
8002
+ "-scheme",
8003
+ scheme,
8004
+ "-configuration",
8005
+ configuration,
8006
+ "-destination",
8007
+ "generic/platform=iOS",
8008
+ "-showBuildSettings",
8009
+ "-json"
8010
+ ],
8011
+ Math.min(timeoutMs, 6e4),
8012
+ signal,
8013
+ folder
8014
+ ),
8015
+ "Could not inspect signing requirements"
8016
+ );
8017
+ try {
8018
+ const direct = signingRequirementsFromBuildSettings(
8019
+ JSON.parse(result.stdout)
8020
+ );
8021
+ const dependent = await dependentSigningRequirements(
8022
+ source,
8023
+ absolutePath,
8024
+ folder,
8025
+ direct.map((requirement) => requirement.target),
8026
+ configuration,
8027
+ timeoutMs,
8028
+ signal
8029
+ );
8030
+ return mergeSigningRequirements([...direct, ...dependent]);
8031
+ } catch (error) {
8032
+ throw new Error(
8033
+ `Could not parse Xcode signing requirements: ${cleanError3(error)}`
8034
+ );
8035
+ }
8036
+ }
7387
8037
  var discoverBuildSources = async (payload, timeoutMs, signal) => {
7388
8038
  const input = parseBuildSourceDiscoverPayload(payload);
7389
8039
  const folder = await validateWorktree2(input, timeoutMs, signal);
7390
8040
  return {
7391
- ...successfulProcess5,
8041
+ ...successfulProcess6,
7392
8042
  sources: await discoverSourcesInFolder(folder)
7393
8043
  };
7394
8044
  };
@@ -7402,11 +8052,8 @@ var parseBuildSourceMetadata = async (payload, timeoutMs, signal) => {
7402
8052
  ]);
7403
8053
  const metadata = metadataFromList(list);
7404
8054
  const configurations = input.source.kind === "PACKAGE" ? ["Debug", "Release"] : input.source.kind === "WORKSPACE" && metadata.configurations.length === 0 ? await workspaceConfigurations(absolutePath, folder, timeoutMs, signal) : metadata.configurations;
7405
- return {
7406
- ...successfulProcess5,
7407
- schemes: uniqueSorted(metadata.schemes),
7408
- configurations: uniqueSorted(configurations),
7409
- testPlans: await testPlans(
8055
+ const [plans, signingRequirements] = await Promise.all([
8056
+ testPlans(
7410
8057
  input.source,
7411
8058
  absolutePath,
7412
8059
  folder,
@@ -7414,6 +8061,22 @@ var parseBuildSourceMetadata = async (payload, timeoutMs, signal) => {
7414
8061
  timeoutMs,
7415
8062
  signal
7416
8063
  ),
8064
+ inspectSigningRequirements(
8065
+ input.source,
8066
+ absolutePath,
8067
+ folder,
8068
+ input.scheme,
8069
+ input.configuration,
8070
+ timeoutMs,
8071
+ signal
8072
+ )
8073
+ ]);
8074
+ return {
8075
+ ...successfulProcess6,
8076
+ schemes: uniqueSorted(metadata.schemes),
8077
+ configurations: uniqueSorted(configurations),
8078
+ testPlans: plans,
8079
+ signingRequirements,
7417
8080
  xcodeVersion: version.exitCode === 0 ? version.stdout.trim().replace(/\n+/g, " \xB7 ") : null,
7418
8081
  headSha: input.headSha
7419
8082
  };
@@ -7524,7 +8187,7 @@ function genericBuildDestinations(action) {
7524
8187
  ];
7525
8188
  }
7526
8189
  async function listPhysicalDevices(timeoutMs, signal) {
7527
- const directory = await mkdtemp2(join7(tmpdir2(), "ade-devices-"));
8190
+ const directory = await mkdtemp3(join7(tmpdir3(), "ade-devices-"));
7528
8191
  const output = join7(directory, "devices.json");
7529
8192
  try {
7530
8193
  const result = await command2(
@@ -7543,9 +8206,9 @@ async function listPhysicalDevices(timeoutMs, signal) {
7543
8206
  signal
7544
8207
  );
7545
8208
  if (result.exitCode !== 0) return [];
7546
- return physicalDestinations(JSON.parse(await readFile4(output, "utf8")));
8209
+ return physicalDestinations(JSON.parse(await readFile5(output, "utf8")));
7547
8210
  } finally {
7548
- await rm4(directory, { recursive: true, force: true });
8211
+ await rm5(directory, { recursive: true, force: true });
7549
8212
  }
7550
8213
  }
7551
8214
  var inspectBuildDestinations = async (payload, timeoutMs, signal) => {
@@ -7580,7 +8243,7 @@ var inspectBuildDestinations = async (payload, timeoutMs, signal) => {
7580
8243
  listPhysicalDevices(timeoutMs, signal)
7581
8244
  ]);
7582
8245
  return {
7583
- ...successfulProcess5,
8246
+ ...successfulProcess6,
7584
8247
  destinations: [
7585
8248
  ...genericBuildDestinations(input.action),
7586
8249
  ...simulators.exitCode === 0 ? simulatorDestinations(JSON.parse(simulators.stdout)) : [],
@@ -7601,12 +8264,12 @@ var inspectBuildRunDestinations = async (payload, timeoutMs, signal) => {
7601
8264
  );
7602
8265
  requireSuccess3(simulators, "Could not inspect available simulators");
7603
8266
  return {
7604
- ...successfulProcess5,
8267
+ ...successfulProcess6,
7605
8268
  destinations: simulatorDestinations(JSON.parse(simulators.stdout))
7606
8269
  };
7607
8270
  }
7608
8271
  return {
7609
- ...successfulProcess5,
8272
+ ...successfulProcess6,
7610
8273
  destinations: await listPhysicalDevices(timeoutMs, signal)
7611
8274
  };
7612
8275
  };
@@ -8025,16 +8688,16 @@ async function runHook(options) {
8025
8688
  const log = join7(directory, `${prefix}.log`);
8026
8689
  const started = Date.now();
8027
8690
  try {
8028
- await mkdir3(directory, { recursive: true, mode: 448 });
8029
- await writeFile3(file, `${options.source}
8691
+ await mkdir4(directory, { recursive: true, mode: 448 });
8692
+ await writeFile4(file, `${options.source}
8030
8693
  `, { mode: 384 });
8031
- await writeFile3(
8694
+ await writeFile4(
8032
8695
  options.contextPath,
8033
8696
  `${JSON.stringify(options.hookContext, null, 2)}
8034
8697
  `,
8035
8698
  { mode: 384 }
8036
8699
  );
8037
- await writeFile3(
8700
+ await writeFile4(
8038
8701
  runner,
8039
8702
  `import { readFile } from "node:fs/promises";
8040
8703
  const hookModule = await import(${JSON.stringify(`./${basename4(file)}`)});
@@ -8312,7 +8975,7 @@ async function writeJsonReport(input, kind, timeoutMs, signal) {
8312
8975
  const resultBundle = join7(input.artifactDirectory, "result.xcresult");
8313
8976
  const filename = kind === "TEST_RESULTS" ? "test-results.json" : "code-coverage.json";
8314
8977
  const destination = join7(input.artifactDirectory, filename);
8315
- const temporary = `${destination}.tmp-${randomUUID2()}`;
8978
+ const temporary = `${destination}.tmp-${randomUUID3()}`;
8316
8979
  try {
8317
8980
  if (!await pathExists(resultBundle)) {
8318
8981
  throw new Error("The build result bundle is unavailable");
@@ -8339,7 +9002,7 @@ async function writeJsonReport(input, kind, timeoutMs, signal) {
8339
9002
  ),
8340
9003
  `Could not generate ${filename}`
8341
9004
  );
8342
- const serialized = await readFile4(temporary, "utf8");
9005
+ const serialized = await readFile5(temporary, "utf8");
8343
9006
  const parsed = JSON.parse(serialized);
8344
9007
  const normalized = kind === "TEST_RESULTS" ? normalizeTestResults(parsed) : normalizeCoverage(parsed);
8345
9008
  await rename3(temporary, destination);
@@ -8355,7 +9018,7 @@ async function writeJsonReport(input, kind, timeoutMs, signal) {
8355
9018
  error: null
8356
9019
  };
8357
9020
  } catch (error) {
8358
- await rm4(temporary, { force: true });
9021
+ await rm5(temporary, { force: true });
8359
9022
  return {
8360
9023
  kind,
8361
9024
  status: "FAILED",
@@ -8446,7 +9109,7 @@ async function snapshotCoverageChanges(input, folder, timeoutMs, signal) {
8446
9109
  const types = changeTypesFromStatus(status2.stdout);
8447
9110
  for (const path of untracked.stdout.split("\0").filter(Boolean)) {
8448
9111
  try {
8449
- const contents = await readFile4(join7(folder, path));
9112
+ const contents = await readFile5(join7(folder, path));
8450
9113
  if (contents.includes(0)) continue;
8451
9114
  const lineCount = contents.length ? contents.toString("utf8").split("\n").length - (contents.toString("utf8").endsWith("\n") ? 1 : 0) : 0;
8452
9115
  lines.set(
@@ -8482,7 +9145,7 @@ async function addChangedCoverage(report, changes, input, folder, timeoutMs, sig
8482
9145
  if (coveragePath && change.lines.length) {
8483
9146
  const temporary2 = join7(
8484
9147
  input.artifactDirectory,
8485
- `.changed-coverage-${randomUUID2()}.json`
9148
+ `.changed-coverage-${randomUUID3()}.json`
8486
9149
  );
8487
9150
  try {
8488
9151
  const result = await commandToFile(
@@ -8504,7 +9167,7 @@ async function addChangedCoverage(report, changes, input, folder, timeoutMs, sig
8504
9167
  );
8505
9168
  if (result.exitCode === 0 && !result.cancelled && !result.timedOut) {
8506
9169
  const parsed = jsonObject(
8507
- JSON.parse(await readFile4(temporary2, "utf8"))
9170
+ JSON.parse(await readFile5(temporary2, "utf8"))
8508
9171
  );
8509
9172
  const lineData = parsed?.[coveragePath];
8510
9173
  if (Array.isArray(lineData)) {
@@ -8521,7 +9184,7 @@ async function addChangedCoverage(report, changes, input, folder, timeoutMs, sig
8521
9184
  }
8522
9185
  }
8523
9186
  } finally {
8524
- await rm4(temporary2, { force: true });
9187
+ await rm5(temporary2, { force: true });
8525
9188
  }
8526
9189
  }
8527
9190
  changedCoveredLines += covered;
@@ -8542,8 +9205,8 @@ async function addChangedCoverage(report, changes, input, folder, timeoutMs, sig
8542
9205
  };
8543
9206
  const data = { ...report.data, changedFiles };
8544
9207
  const destination = join7(input.artifactDirectory, "worktree-coverage.json");
8545
- const temporary = `${destination}.tmp-${randomUUID2()}`;
8546
- await writeFile3(temporary, JSON.stringify({ summary, data }, null, 2), {
9208
+ const temporary = `${destination}.tmp-${randomUUID3()}`;
9209
+ await writeFile4(temporary, JSON.stringify({ summary, data }, null, 2), {
8547
9210
  mode: 384
8548
9211
  });
8549
9212
  await rename3(temporary, destination);
@@ -8659,8 +9322,8 @@ async function captureArtifacts(input, folder, signal, includeProducts = true) {
8659
9322
  if (source && await pathExists(source)) {
8660
9323
  const productDirectory = join7(input.artifactDirectory, "products");
8661
9324
  const destination = join7(productDirectory, basename4(source));
8662
- await mkdir3(productDirectory, { recursive: true, mode: 448 });
8663
- await rm4(destination, { recursive: true, force: true });
9325
+ await mkdir4(productDirectory, { recursive: true, mode: 448 });
9326
+ await rm5(destination, { recursive: true, force: true });
8664
9327
  await cp(source, destination, {
8665
9328
  recursive: true,
8666
9329
  preserveTimestamps: true
@@ -8725,7 +9388,7 @@ var runIosBuild = async (payload, timeoutMs, signal, onLog, context) => {
8725
9388
  Math.min(timeoutMs, 6e4),
8726
9389
  signal
8727
9390
  );
8728
- await mkdir3(input.artifactDirectory, { recursive: true, mode: 448 });
9391
+ await mkdir4(input.artifactDirectory, { recursive: true, mode: 448 });
8729
9392
  const rawLog = join7(input.artifactDirectory, "build.log");
8730
9393
  const logger = new BuildLogger(input.buildId, context, rawLog, process.env);
8731
9394
  try {
@@ -8967,7 +9630,7 @@ var generateIosBuildReport = async (payload, timeoutMs, signal, onLog) => {
8967
9630
  if (!isAbsolute4(input.artifactDirectory) || basename4(input.artifactDirectory) !== input.buildId) {
8968
9631
  throw new Error("Build artifact directory is invalid");
8969
9632
  }
8970
- if (signal.aborted) return { ...successfulProcess5, cancelled: true };
9633
+ if (signal.aborted) return { ...successfulProcess6, cancelled: true };
8971
9634
  const report = await writeJsonReport(
8972
9635
  input,
8973
9636
  input.reportKind,
@@ -8981,22 +9644,22 @@ var generateIosBuildReport = async (payload, timeoutMs, signal, onLog) => {
8981
9644
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
8982
9645
  });
8983
9646
  return {
8984
- ...successfulProcess5,
9647
+ ...successfulProcess6,
8985
9648
  report,
8986
9649
  artifacts: report.artifact ? [report.artifact] : []
8987
9650
  };
8988
9651
  };
8989
9652
  var deleteIosBuild = async (payload, _timeoutMs, signal, onLog) => {
8990
9653
  const input = parseBuildDeletePayload(payload);
8991
- if (signal.aborted) return { ...successfulProcess5, cancelled: true };
8992
- await rm4(input.artifactDirectory, { recursive: true, force: true });
9654
+ if (signal.aborted) return { ...successfulProcess6, cancelled: true };
9655
+ await rm5(input.artifactDirectory, { recursive: true, force: true });
8993
9656
  await onLog({
8994
9657
  sequence: 0,
8995
9658
  stream: "SYSTEM",
8996
9659
  message: `Deleted build folder ${input.artifactDirectory}`,
8997
9660
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
8998
9661
  });
8999
- return successfulProcess5;
9662
+ return successfulProcess6;
9000
9663
  };
9001
9664
  var downloadIosBuildArtifact = async (payload, timeoutMs, signal, onLog, context) => {
9002
9665
  const input = parseBuildArtifactDownloadPayload(payload);
@@ -9019,8 +9682,8 @@ var downloadIosBuildArtifact = async (payload, timeoutMs, signal, onLog, context
9019
9682
  try {
9020
9683
  if (information.isDirectory()) {
9021
9684
  temporaryArchive = join7(
9022
- tmpdir2(),
9023
- `ade-build-artifact-${randomUUID2()}.tar.gz`
9685
+ tmpdir3(),
9686
+ `ade-build-artifact-${randomUUID3()}.tar.gz`
9024
9687
  );
9025
9688
  requireSuccess3(
9026
9689
  await command2(
@@ -9049,10 +9712,10 @@ var downloadIosBuildArtifact = async (payload, timeoutMs, signal, onLog, context
9049
9712
  filename,
9050
9713
  contentType
9051
9714
  });
9052
- return successfulProcess5;
9715
+ return successfulProcess6;
9053
9716
  } finally {
9054
9717
  if (temporaryArchive) {
9055
- await rm4(temporaryArchive, { force: true });
9718
+ await rm5(temporaryArchive, { force: true });
9056
9719
  }
9057
9720
  }
9058
9721
  };
@@ -9089,7 +9752,7 @@ var deployIosBuild = async (payload, timeoutMs, signal, _onLog, context) => {
9089
9752
  throw new Error("Runnable app artifact is missing");
9090
9753
  }
9091
9754
  const deploymentsDirectory = join7(input.artifactDirectory, "deployments");
9092
- await mkdir3(deploymentsDirectory, { recursive: true, mode: 448 });
9755
+ await mkdir4(deploymentsDirectory, { recursive: true, mode: 448 });
9093
9756
  const logger = new BuildLogger(
9094
9757
  input.buildId,
9095
9758
  context,
@@ -9104,7 +9767,7 @@ var deployIosBuild = async (payload, timeoutMs, signal, _onLog, context) => {
9104
9767
  "deployments",
9105
9768
  deployment.id
9106
9769
  );
9107
- await mkdir3(directory, { recursive: true, mode: 448 });
9770
+ await mkdir4(directory, { recursive: true, mode: 448 });
9108
9771
  const logPath = join7(directory, "deployment.log");
9109
9772
  const started = Date.now();
9110
9773
  let failure = null;
@@ -9288,8 +9951,16 @@ function exportPlist(settings) {
9288
9951
  signingStyle: settings.signingStyle.toLowerCase(),
9289
9952
  uploadSymbols: settings.uploadSymbols,
9290
9953
  manageAppVersionAndBuildNumber: settings.manageAppVersionAndBuildNumber,
9291
- testFlightInternalTestingOnly: settings.testFlightInternalTestingOnly
9954
+ testFlightInternalTestingOnly: settings.testFlightInternalTestingOnly,
9955
+ stripSwiftSymbols: settings.stripSwiftSymbols
9292
9956
  };
9957
+ if (settings.thinning) values.thinning = settings.thinning;
9958
+ if (settings.iCloudContainerEnvironment) {
9959
+ values.iCloudContainerEnvironment = settings.iCloudContainerEnvironment;
9960
+ }
9961
+ if (settings.distributionBundleIdentifier) {
9962
+ values.distributionBundleIdentifier = settings.distributionBundleIdentifier;
9963
+ }
9293
9964
  if (settings.teamId) values.teamID = settings.teamId;
9294
9965
  if (settings.signingCertificate)
9295
9966
  values.signingCertificate = settings.signingCertificate;
@@ -9317,10 +9988,10 @@ var exportIosArchive = async (payload, timeoutMs, signal, _onLog, context) => {
9317
9988
  "exports",
9318
9989
  input.exportId
9319
9990
  );
9320
- await mkdir3(exportDirectory, { recursive: true, mode: 448 });
9991
+ await mkdir4(exportDirectory, { recursive: true, mode: 448 });
9321
9992
  const plistPath = join7(exportDirectory, "ExportOptions.plist");
9322
9993
  const logPath = join7(exportDirectory, "export.log");
9323
- await writeFile3(plistPath, exportPlist(input.settings), { mode: 384 });
9994
+ await writeFile4(plistPath, exportPlist(input.settings), { mode: 384 });
9324
9995
  const logger = new BuildLogger(input.buildId, context, logPath, process.env);
9325
9996
  try {
9326
9997
  const result = await runLoggedCommand({
@@ -9412,7 +10083,13 @@ var handlers = {
9412
10083
  [IOS_EXPORT_JOB_KIND]: exportIosArchive,
9413
10084
  [IOS_TEST_RESULTS_JOB_KIND]: generateIosBuildReport,
9414
10085
  [IOS_COVERAGE_REPORT_JOB_KIND]: generateIosBuildReport,
9415
- [IOS_SIGNING_INSPECT_JOB_KIND]: inspectIosSigning
10086
+ [IOS_SIGNING_INSPECT_JOB_KIND]: inspectIosSigning,
10087
+ [SIGNING_ASSETS_SCAN_JOB_KIND]: scanSigningAssets,
10088
+ [SIGNING_PROFILE_READ_JOB_KIND]: readSigningProfile,
10089
+ [SIGNING_PROFILE_INSTALL_JOB_KIND]: installSigningProfile,
10090
+ [SIGNING_PROFILE_DELETE_JOB_KIND]: deleteSigningProfile,
10091
+ [SIGNING_IDENTITY_IMPORT_JOB_KIND]: importSigningIdentity,
10092
+ [SIGNING_IDENTITY_DELETE_JOB_KIND]: deleteSigningIdentity
9416
10093
  };
9417
10094
 
9418
10095
  // src/repository-coordinator.ts
@@ -9491,7 +10168,8 @@ var JobExecutor = class {
9491
10168
  reportWorktreeActivity: (input) => this.client.reportWorktreeActivity(input),
9492
10169
  reportBuildProgress: (input) => this.client.reportBuildProgress(input),
9493
10170
  appendBuildLogs: (buildId, events) => this.client.appendBuildLogs(buildId, events),
9494
- uploadBuildArtifact: (input) => this.client.uploadBuildArtifact(input)
10171
+ uploadBuildArtifact: (input) => this.client.uploadBuildArtifact(input),
10172
+ claimSigningSecretTransfer: (transferId) => this.client.claimSigningSecretTransfer(transferId)
9495
10173
  }
9496
10174
  );
9497
10175
  const codebaseId = claimed.payload && typeof claimed.payload === "object" && !Array.isArray(claimed.payload) && typeof claimed.payload.codebaseId === "string" ? String(claimed.payload.codebaseId) : null;