@capgo/cli 8.0.0-alpha.4 → 8.0.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 (221) hide show
  1. package/README.md +755 -75
  2. package/dist/index.js +1135 -311
  3. package/dist/keychain-export.swift +351 -0
  4. package/dist/package.json +120 -29
  5. package/dist/src/ai/analyze.d.ts +48 -0
  6. package/dist/src/ai/log-capture.d.ts +14 -0
  7. package/dist/src/ai/prompt.d.ts +1 -0
  8. package/dist/src/ai/render-markdown.d.ts +12 -0
  9. package/dist/src/ai/sse.d.ts +5 -0
  10. package/dist/src/ai/stream-markdown.d.ts +22 -0
  11. package/dist/src/ai/telemetry.d.ts +39 -0
  12. package/dist/src/analytics/error-category.d.ts +11 -0
  13. package/dist/src/analytics/org-resolver.d.ts +11 -0
  14. package/dist/src/analytics/supabase-perf.d.ts +48 -0
  15. package/dist/src/analytics/track.d.ts +70 -0
  16. package/dist/src/api/app.d.ts +17 -8
  17. package/dist/src/api/channels.d.ts +2442 -2729
  18. package/dist/src/api/crypto.d.ts +26 -0
  19. package/dist/src/api/update.d.ts +7 -1
  20. package/dist/src/api/versions.d.ts +9 -2
  21. package/dist/src/app/add.d.ts +6 -4
  22. package/dist/src/app/debug.d.ts +3 -7
  23. package/dist/src/app/delete.d.ts +1 -2
  24. package/dist/src/app/info.d.ts +5 -1
  25. package/dist/src/app/list.d.ts +23 -2
  26. package/dist/src/app/set.d.ts +0 -1
  27. package/dist/src/app/setting.d.ts +3 -9
  28. package/dist/src/app/updateProbe.d.ts +43 -0
  29. package/dist/src/build/credentials-command.d.ts +89 -0
  30. package/dist/src/build/credentials-manage.d.ts +7 -0
  31. package/dist/src/build/credentials.d.ts +78 -0
  32. package/dist/src/build/env-render.d.ts +8 -0
  33. package/dist/src/build/last-output-command.d.ts +6 -0
  34. package/dist/src/build/mobileprovision-parser.d.ts +35 -0
  35. package/dist/src/build/needed.d.ts +28 -0
  36. package/dist/src/build/onboarding/ai-fit.d.ts +110 -0
  37. package/dist/src/build/onboarding/analytics.d.ts +23 -0
  38. package/dist/src/build/onboarding/android/gcp-api.d.ts +128 -0
  39. package/dist/src/build/onboarding/android/gradle-parser.d.ts +19 -0
  40. package/dist/src/build/onboarding/android/keystore.d.ts +77 -0
  41. package/dist/src/build/onboarding/android/oauth-config.d.ts +24 -0
  42. package/dist/src/build/onboarding/android/oauth-google.d.ts +134 -0
  43. package/dist/src/build/onboarding/android/play-api.d.ts +91 -0
  44. package/dist/src/build/onboarding/android/progress.d.ts +22 -0
  45. package/dist/src/build/onboarding/android/service-account-validation.d.ts +58 -0
  46. package/dist/src/build/onboarding/android/types.d.ts +72 -0
  47. package/dist/src/build/onboarding/android/ui/app.d.ts +17 -0
  48. package/dist/src/build/onboarding/app-verification.d.ts +86 -0
  49. package/dist/src/build/onboarding/apple-api.d.ts +234 -0
  50. package/dist/src/build/onboarding/build-log.d.ts +10 -0
  51. package/dist/src/build/onboarding/bundle-id-detector.d.ts +117 -0
  52. package/dist/src/build/onboarding/ci-secrets.d.ts +87 -0
  53. package/dist/src/build/onboarding/command.d.ts +6 -0
  54. package/dist/src/build/onboarding/csr.d.ts +33 -0
  55. package/dist/src/build/onboarding/diff-utils.d.ts +24 -0
  56. package/dist/src/build/onboarding/env-export.d.ts +46 -0
  57. package/dist/src/build/onboarding/error-categories.d.ts +13 -0
  58. package/dist/src/build/onboarding/file-picker.d.ts +47 -0
  59. package/dist/src/build/onboarding/macos-signing.d.ts +190 -0
  60. package/dist/src/build/onboarding/min-terminal-size.d.ts +16 -0
  61. package/dist/src/build/onboarding/progress.d.ts +51 -0
  62. package/dist/src/build/onboarding/recovery.d.ts +7 -0
  63. package/dist/src/build/onboarding/telemetry.d.ts +28 -0
  64. package/dist/src/build/onboarding/types.d.ts +140 -0
  65. package/dist/src/build/onboarding/ui/app.d.ts +36 -0
  66. package/dist/src/build/onboarding/ui/completed-steps-log.d.ts +9 -0
  67. package/dist/src/build/onboarding/ui/components.d.ts +178 -0
  68. package/dist/src/build/onboarding/ui/frame-fit.d.ts +10 -0
  69. package/dist/src/build/onboarding/ui/min-size-gate.d.ts +20 -0
  70. package/dist/src/build/onboarding/ui/platform-picker.d.ts +19 -0
  71. package/dist/src/build/onboarding/ui/shell.d.ts +33 -0
  72. package/dist/src/build/onboarding/ui/steps/android-ci.d.ts +45 -0
  73. package/dist/src/build/onboarding/ui/steps/android-keystore.d.ts +75 -0
  74. package/dist/src/build/onboarding/ui/steps/android-sa-gcp.d.ts +85 -0
  75. package/dist/src/build/onboarding/ui/steps/android-shared.d.ts +67 -0
  76. package/dist/src/build/onboarding/ui/steps/ios-ci.d.ts +44 -0
  77. package/dist/src/build/onboarding/ui/steps/ios-credentials.d.ts +66 -0
  78. package/dist/src/build/onboarding/ui/steps/ios-import.d.ts +79 -0
  79. package/dist/src/build/onboarding/ui/steps/ios-shared.d.ts +93 -0
  80. package/dist/src/build/onboarding/workflow-generator.d.ts +48 -0
  81. package/dist/src/build/onboarding/workflow-ui-helpers.d.ts +18 -0
  82. package/dist/src/build/onboarding/workflow-writer.d.ts +36 -0
  83. package/dist/src/build/output-record.d.ts +30 -0
  84. package/dist/src/build/pbxproj-parser.d.ts +48 -0
  85. package/dist/src/build/platform-paths.d.ts +20 -0
  86. package/dist/src/build/qr.d.ts +5 -0
  87. package/dist/src/build/request.d.ts +107 -0
  88. package/dist/src/build/telemetry.d.ts +17 -0
  89. package/dist/src/bundle/builder-cta.d.ts +67 -0
  90. package/dist/src/bundle/check.d.ts +0 -1
  91. package/dist/src/bundle/cleanup.d.ts +3 -12
  92. package/dist/src/bundle/compatibility.d.ts +23 -12
  93. package/dist/src/bundle/decrypt.d.ts +4 -0
  94. package/dist/src/bundle/delete.d.ts +3 -8
  95. package/dist/src/bundle/encrypt.d.ts +4 -0
  96. package/dist/src/bundle/list.d.ts +5 -2
  97. package/dist/src/bundle/partial.d.ts +5 -3
  98. package/dist/src/bundle/releaseType.d.ts +15 -0
  99. package/dist/src/bundle/unlink.d.ts +6 -5
  100. package/dist/src/bundle/upload-command.d.ts +8 -0
  101. package/dist/src/bundle/upload.d.ts +21 -14
  102. package/dist/src/bundle/upload_interface.d.ts +2 -50
  103. package/dist/src/bundle/zip.d.ts +4 -19
  104. package/dist/src/capacitor-cli.d.ts +13 -0
  105. package/dist/src/channel/add.d.ts +8 -10
  106. package/dist/src/channel/currentBundle.d.ts +3 -9
  107. package/dist/src/channel/delete.d.ts +3 -9
  108. package/dist/src/channel/list.d.ts +31 -4
  109. package/dist/src/channel/set.d.ts +2 -17
  110. package/dist/src/checksum.d.ts +1 -2
  111. package/dist/src/config/index.d.ts +2 -13
  112. package/dist/src/docs.d.ts +0 -1
  113. package/dist/src/github-command.d.ts +9 -0
  114. package/dist/src/github.d.ts +40 -0
  115. package/dist/src/index.d.ts +0 -1
  116. package/dist/src/init/app-conflict.d.ts +2 -0
  117. package/dist/src/init/command.d.ts +57 -0
  118. package/dist/src/init/index.d.ts +1 -0
  119. package/dist/src/init/prompts.d.ts +41 -0
  120. package/dist/src/init/runtime.d.ts +111 -0
  121. package/dist/src/init/ui/app.d.ts +9 -0
  122. package/dist/src/init/ui/components.d.ts +31 -0
  123. package/dist/src/init/ui.d.ts +12 -0
  124. package/dist/src/init/updater.d.ts +13 -0
  125. package/dist/src/key.d.ts +16 -0
  126. package/dist/src/login.d.ts +0 -1
  127. package/dist/src/mcp/server.d.ts +5 -0
  128. package/dist/src/onboarding-support.d.ts +18 -0
  129. package/dist/src/organization/add.d.ts +26 -0
  130. package/dist/src/organization/delete.d.ts +3 -0
  131. package/dist/src/{organisation → organization}/index.d.ts +1 -1
  132. package/dist/src/{organisation → organization}/list.d.ts +14 -2
  133. package/dist/src/organization/members.d.ts +12 -0
  134. package/dist/src/organization/set.d.ts +21 -0
  135. package/dist/src/posthog.d.ts +13 -0
  136. package/dist/src/probe.d.ts +20 -0
  137. package/dist/src/promptPreferences.d.ts +13 -0
  138. package/dist/src/replicationProgress.d.ts +8 -0
  139. package/dist/src/run/device.d.ts +5 -0
  140. package/dist/src/runner-command.d.ts +5 -0
  141. package/dist/src/schemas/app.d.ts +26 -0
  142. package/dist/src/schemas/base.d.ts +7 -0
  143. package/dist/src/schemas/build.d.ts +196 -0
  144. package/dist/src/schemas/bundle.d.ts +157 -0
  145. package/dist/src/schemas/channel.d.ts +62 -0
  146. package/dist/src/schemas/common.d.ts +46 -0
  147. package/dist/src/schemas/config.d.ts +20 -0
  148. package/dist/src/schemas/index.d.ts +19 -0
  149. package/dist/src/schemas/organization.d.ts +41 -0
  150. package/dist/src/schemas/sdk.d.ts +335 -0
  151. package/dist/src/schemas/validate.d.ts +12 -0
  152. package/dist/src/sdk.d.ts +138 -317
  153. package/dist/src/sdk.js +542 -299
  154. package/dist/src/terminal-table.d.ts +7 -0
  155. package/dist/src/types/supabase.types.d.ts +2770 -296
  156. package/dist/src/updaterConfig.d.ts +8 -0
  157. package/dist/src/user/account.d.ts +0 -1
  158. package/dist/src/utils/latest-version.d.ts +0 -1
  159. package/dist/src/utils/safeWrites.d.ts +21 -0
  160. package/dist/src/utils/security_policy_errors.d.ts +47 -0
  161. package/dist/src/utils.d.ts +2869 -341
  162. package/dist/src/versionHelpers.d.ts +19 -0
  163. package/package.json +120 -29
  164. package/skills/native-builds/SKILL.md +255 -0
  165. package/skills/organization-management/SKILL.md +93 -0
  166. package/skills/release-management/SKILL.md +225 -0
  167. package/skills/usage/SKILL.md +92 -0
  168. package/dist/src/api/app.d.ts.map +0 -1
  169. package/dist/src/api/channels.d.ts.map +0 -1
  170. package/dist/src/api/cryptoV2.d.ts +0 -16
  171. package/dist/src/api/cryptoV2.d.ts.map +0 -1
  172. package/dist/src/api/update.d.ts.map +0 -1
  173. package/dist/src/api/versions.d.ts.map +0 -1
  174. package/dist/src/app/add.d.ts.map +0 -1
  175. package/dist/src/app/debug.d.ts.map +0 -1
  176. package/dist/src/app/delete.d.ts.map +0 -1
  177. package/dist/src/app/info.d.ts.map +0 -1
  178. package/dist/src/app/list.d.ts.map +0 -1
  179. package/dist/src/app/set.d.ts.map +0 -1
  180. package/dist/src/app/setting.d.ts.map +0 -1
  181. package/dist/src/bundle/check.d.ts.map +0 -1
  182. package/dist/src/bundle/cleanup.d.ts.map +0 -1
  183. package/dist/src/bundle/compatibility.d.ts.map +0 -1
  184. package/dist/src/bundle/decryptV2.d.ts +0 -13
  185. package/dist/src/bundle/decryptV2.d.ts.map +0 -1
  186. package/dist/src/bundle/delete.d.ts.map +0 -1
  187. package/dist/src/bundle/encryptV2.d.ts +0 -14
  188. package/dist/src/bundle/encryptV2.d.ts.map +0 -1
  189. package/dist/src/bundle/list.d.ts.map +0 -1
  190. package/dist/src/bundle/partial.d.ts.map +0 -1
  191. package/dist/src/bundle/unlink.d.ts.map +0 -1
  192. package/dist/src/bundle/upload.d.ts.map +0 -1
  193. package/dist/src/bundle/upload_interface.d.ts.map +0 -1
  194. package/dist/src/bundle/zip.d.ts.map +0 -1
  195. package/dist/src/channel/add.d.ts.map +0 -1
  196. package/dist/src/channel/currentBundle.d.ts.map +0 -1
  197. package/dist/src/channel/delete.d.ts.map +0 -1
  198. package/dist/src/channel/list.d.ts.map +0 -1
  199. package/dist/src/channel/set.d.ts.map +0 -1
  200. package/dist/src/checksum.d.ts.map +0 -1
  201. package/dist/src/config/index.d.ts.map +0 -1
  202. package/dist/src/docs.d.ts.map +0 -1
  203. package/dist/src/index.d.ts.map +0 -1
  204. package/dist/src/init.d.ts +0 -7
  205. package/dist/src/init.d.ts.map +0 -1
  206. package/dist/src/keyV2.d.ts +0 -19
  207. package/dist/src/keyV2.d.ts.map +0 -1
  208. package/dist/src/login.d.ts.map +0 -1
  209. package/dist/src/organisation/add.d.ts +0 -19
  210. package/dist/src/organisation/add.d.ts.map +0 -1
  211. package/dist/src/organisation/delete.d.ts +0 -8
  212. package/dist/src/organisation/delete.d.ts.map +0 -1
  213. package/dist/src/organisation/index.d.ts.map +0 -1
  214. package/dist/src/organisation/list.d.ts.map +0 -1
  215. package/dist/src/organisation/set.d.ts +0 -13
  216. package/dist/src/organisation/set.d.ts.map +0 -1
  217. package/dist/src/sdk.d.ts.map +0 -1
  218. package/dist/src/types/supabase.types.d.ts.map +0 -1
  219. package/dist/src/user/account.d.ts.map +0 -1
  220. package/dist/src/utils/latest-version.d.ts.map +0 -1
  221. package/dist/src/utils.d.ts.map +0 -1
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Pure decision logic for the iOS "verify App Store app" onboarding step.
3
+ *
4
+ * No filesystem, network, or React access — every input (the local Release
5
+ * build ID, the remote App Store Connect apps, and the registered bundle IDs)
6
+ * is passed in so the module stays synchronous and unit-testable, mirroring
7
+ * `decideBuilderCtaSurface` / `shouldBlockIncompatibleUpload` in
8
+ * `cli/src/bundle/builder-cta.ts`.
9
+ *
10
+ * The single invariant the step enforces (always `app_store` mode): an App
11
+ * Store Connect app must exist whose `bundleId` equals the Release build ID.
12
+ */
13
+ /**
14
+ * Classification of why (and whether) the verification invariant is met.
15
+ *
16
+ * - `exact-match` — an ASC app's bundle ID == the Release build ID. Pass.
17
+ * - `wrong-build-id` — apps exist but none match → likely a wrong build ID (Path A).
18
+ * - `no-app-identifier-exists` — no apps at all, but the identifier is already
19
+ * registered in the Developer portal (Path B; the
20
+ * ASC new-app form can select the existing id).
21
+ * - `no-app-unregistered` — no apps at all and the identifier is not yet
22
+ * registered (Path B; register first, then create).
23
+ *
24
+ * `no-apps-in-account` is the umbrella for the `apps.length === 0` cases. We
25
+ * keep it in the union because the analytics/step layer surfaces it as a
26
+ * coarse result, but `classifyAppVerification` deliberately returns the finer
27
+ * registered/unregistered split because that distinction is what changes the
28
+ * actionable Path B wording ("identifier already exists" vs "will be
29
+ * registered"). The umbrella value is therefore never returned by the
30
+ * classifier itself.
31
+ */
32
+ export type AppVerifyResult = 'exact-match' | 'wrong-build-id' | 'no-app-identifier-exists' | 'no-app-unregistered' | 'no-apps-in-account';
33
+ /** Minimal shape of an App Store Connect app needed for verification. */
34
+ export interface AscAppLike {
35
+ bundleId: string;
36
+ name: string;
37
+ }
38
+ export interface ClassifyAppVerificationInput {
39
+ /** The authoritative Release `PRODUCT_BUNDLE_IDENTIFIER` from the project. */
40
+ releaseBundleId: string;
41
+ /** Apps that actually exist in the user's App Store Connect account. */
42
+ apps: AscAppLike[];
43
+ /** Bundle IDs registered in the Apple Developer portal (diagnostic only). */
44
+ registeredBundleIds: string[];
45
+ }
46
+ export interface ClassifyAppVerificationResult {
47
+ result: AppVerifyResult;
48
+ /** The matched ASC app when `result === 'exact-match'`, else `null`. */
49
+ matchedApp: AscAppLike | null;
50
+ }
51
+ /**
52
+ * Pure classification of the verification invariant.
53
+ *
54
+ * 1. An app whose `bundleId === releaseBundleId` → `exact-match` (+ that app).
55
+ * 2. Otherwise, if any apps exist → `wrong-build-id` (the build signs an id that
56
+ * matches none of the account's apps).
57
+ * 3. Otherwise (no apps), if `releaseBundleId` is already registered →
58
+ * `no-app-identifier-exists`.
59
+ * 4. Otherwise (no apps, not registered) → `no-app-unregistered`.
60
+ */
61
+ export declare function classifyAppVerification(input: ClassifyAppVerificationInput): ClassifyAppVerificationResult;
62
+ /** Which resolution path the verification gate is enforcing. */
63
+ export type GatePath = 'fix-build-id' | 'create-app';
64
+ export interface EvaluateGateInput {
65
+ /** Whether the invariant now holds (re-checked live on each Continue). */
66
+ satisfied: boolean;
67
+ /** 1-based count of blocked Continue attempts so far. */
68
+ attempt: number;
69
+ }
70
+ export interface EvaluateGateResult {
71
+ /** Whether the user may proceed past the step. */
72
+ proceed: boolean;
73
+ /**
74
+ * How loud the (still-blocked) warning box should be. `0` when satisfied;
75
+ * otherwise the attempt count clamped to `3` so the escalation tops out
76
+ * instead of growing unbounded.
77
+ */
78
+ escalationLevel: number;
79
+ }
80
+ /**
81
+ * Pure gate decision. When the invariant is satisfied the user proceeds with no
82
+ * escalation; otherwise they are blocked and the escalation level is the attempt
83
+ * count capped at {@link MAX_ESCALATION_LEVEL} so the warning box can ramp its
84
+ * treatment without overflowing.
85
+ */
86
+ export declare function evaluateGate(input: EvaluateGateInput): EvaluateGateResult;
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Generate a JWT for App Store Connect API authentication.
3
+ * Uses ES256 algorithm with the .p8 private key.
4
+ */
5
+ export declare function generateJwt(keyId: string, issuerId: string, p8Content: string): string;
6
+ export declare class AppleApiHttpError extends Error {
7
+ readonly status: number;
8
+ constructor(status: number, message: string);
9
+ }
10
+ /**
11
+ * Verify the API key works and try to detect the team ID from existing certificates.
12
+ * Throws on 401/403 with a user-friendly message.
13
+ */
14
+ export declare function verifyApiKey(token: string): Promise<{
15
+ valid: true;
16
+ teamId: string;
17
+ }>;
18
+ export interface AscDistributionCert {
19
+ id: string;
20
+ name: string;
21
+ serialNumber: string;
22
+ expirationDate: string;
23
+ /**
24
+ * Base64-encoded DER of the certificate. Populated when {@link listDistributionCerts}
25
+ * is called with `includeContent: true` — kept optional so existing callers don't pay
26
+ * the larger payload when they don't need it.
27
+ */
28
+ certificateContent?: string;
29
+ }
30
+ /**
31
+ * Why a local Keychain cert can't be used to ship builds.
32
+ *
33
+ * Concrete enumeration so the import-pick-identity UI can render a stable
34
+ * Reason column and so we can add specific guidance per reason (e.g.
35
+ * "managed" certs get a "can't sign locally" note, "not-visible" certs get
36
+ * a "Open Developer Portal to verify" note).
37
+ */
38
+ export type CertAvailabilityReason = 'expired' | 'managed' | 'not-visible' | 'check-failed' | 'no-private-key';
39
+ export interface CertAvailability {
40
+ available: boolean;
41
+ reason?: CertAvailabilityReason;
42
+ /** Short human-readable reason for display in the picker. */
43
+ reasonText?: string;
44
+ /** When available — Apple-side cert resource id for downstream API calls. */
45
+ appleCertId?: string;
46
+ }
47
+ /**
48
+ * Pure classifier: given a local cert + the result of an Apple-side lookup,
49
+ * decide whether it's usable for shipping builds and surface a short
50
+ * reasonText for the picker UI.
51
+ *
52
+ * Exported separately from the lookup function so we can unit-test the
53
+ * decision logic without mocking network calls. Callers compose:
54
+ *
55
+ * const certId = await findCertIdBySha1(token, identity.sha1)
56
+ * .catch(err => { lookupError = err; return null })
57
+ * const availability = classifyCertAvailability({
58
+ * localExpirationDate: identity.expirationDate,
59
+ * appleCertId: certId,
60
+ * lookupError,
61
+ * })
62
+ *
63
+ * The `expired` and `managed` branches don't need a lookup — they're checked
64
+ * up-front from local metadata. Callers can pass null `appleCertId` without
65
+ * having run the lookup at all when those local-side conditions already
66
+ * disqualify the identity.
67
+ */
68
+ export declare function classifyCertAvailability(args: {
69
+ localExpirationDate?: string;
70
+ isManaged?: boolean;
71
+ appleCertId: string | null;
72
+ lookupError?: unknown;
73
+ }): CertAvailability;
74
+ /**
75
+ * List all iOS distribution certificates.
76
+ *
77
+ * Set `includeContent: true` when you need to compute the cert's SHA1 for
78
+ * matching against a local Keychain identity ({@link findCertIdBySha1}).
79
+ */
80
+ export declare function listDistributionCerts(token: string, options?: {
81
+ includeContent?: boolean;
82
+ }): Promise<AscDistributionCert[]>;
83
+ /**
84
+ * Compute the SHA1 hash of an ASC certificate's base64-DER content. Returns
85
+ * the lowercase 40-char hex string used elsewhere as the canonical identity
86
+ * key — matches the SHA1 reported by `security find-identity` on macOS.
87
+ *
88
+ * SECURITY NOTE on SHA1: this is NOT a security primitive. macOS itself
89
+ * reports code-signing identities as cert-DER SHA1 (via `security
90
+ * find-identity`), and we have to use the same hash to look up an Apple-side
91
+ * cert by its on-Mac counterpart. SHA1 here is a non-secret identifier, not
92
+ * a message digest protecting any data. CodeQL's "weak cryptographic
93
+ * algorithm" rule is suppressed for this reason.
94
+ */
95
+ export declare function computeCertSha1(certificateContentBase64: string): string;
96
+ /**
97
+ * Match a local Keychain identity (by its SHA1) against an Apple-side
98
+ * certificate and return the Apple certificate ID needed for profile
99
+ * creation. Returns null if no Apple-side cert matches the SHA1.
100
+ */
101
+ export declare function findCertIdBySha1(token: string, sha1: string): Promise<string | null>;
102
+ /**
103
+ * Like {@link findCertIdBySha1} but returns the full Apple-side cert
104
+ * record (id + name + expirationDate + serialNumber) when matched. Used
105
+ * by the eager batch validation so the picker / manual-portal-walkthrough
106
+ * step can surface concrete disambiguators (expiration date, last few
107
+ * chars of serial number — both visible in the Apple Developer Portal
108
+ * when the user clicks into a cert) that help the user pick the right
109
+ * row when multiple distribution certs are listed for the same team.
110
+ *
111
+ * Apple's API does NOT expose a "created by" field on certs (the portal
112
+ * UI shows it, but `/v1/certificates` doesn't return that column). The
113
+ * disambiguators we can give are expirationDate + serialNumber.
114
+ */
115
+ export declare function findCertBySha1(token: string, sha1: string): Promise<AscDistributionCert | null>;
116
+ /**
117
+ * List all provisioning profiles linked to a specific Apple-side certificate.
118
+ * Used by the import-flow no-match-recovery menu to surface profiles that
119
+ * exist on Apple but haven't been downloaded to the user's Mac.
120
+ */
121
+ export interface AscProfileSummary {
122
+ id: string;
123
+ name: string;
124
+ profileType: string;
125
+ profileContent: string;
126
+ expirationDate: string;
127
+ bundleIdentifier: string;
128
+ }
129
+ export declare function listProfilesForCert(token: string, certificateId: string): Promise<AscProfileSummary[]>;
130
+ /**
131
+ * Revoke (delete) a certificate by ID.
132
+ */
133
+ export declare function revokeCertificate(token: string, certId: string): Promise<void>;
134
+ /**
135
+ * Error thrown when certificate limit is reached.
136
+ * Contains the existing certificates so the UI can ask the user which to revoke.
137
+ */
138
+ export declare class CertificateLimitError extends Error {
139
+ readonly certificates: AscDistributionCert[];
140
+ constructor(certificates: AscDistributionCert[]);
141
+ }
142
+ /**
143
+ * Create a distribution certificate using a CSR.
144
+ * Returns the certificate ID, base64 DER content, expiration date, and team ID.
145
+ *
146
+ * Throws CertificateLimitError if the limit is reached, so the UI can ask
147
+ * the user which certificate to revoke.
148
+ */
149
+ export declare function createCertificate(token: string, csrPem: string): Promise<{
150
+ certificateId: string;
151
+ certificateContent: string;
152
+ expirationDate: string;
153
+ teamId: string;
154
+ }>;
155
+ /**
156
+ * Find an existing bundle ID or register a new one.
157
+ * Returns the Apple resource ID needed for profile creation.
158
+ */
159
+ export declare function ensureBundleId(token: string, identifier: string): Promise<{
160
+ bundleIdResourceId: string;
161
+ }>;
162
+ /**
163
+ * An App Store Connect app record. Used by the iOS app-verification step to
164
+ * check whether an app exists whose `bundleId` matches the project's Release
165
+ * `PRODUCT_BUNDLE_IDENTIFIER`.
166
+ */
167
+ export interface AscApp {
168
+ id: string;
169
+ bundleId: string;
170
+ name: string;
171
+ }
172
+ /**
173
+ * Parse a `GET /v1/apps` response into {@link AscApp} records. Tolerant of
174
+ * missing `data`, missing `attributes`, and missing individual fields — Apple
175
+ * omits attributes the API key isn't entitled to see rather than nulling them.
176
+ */
177
+ export declare function parseAppsResponse(json: any): AscApp[];
178
+ /**
179
+ * Parse a `GET /v1/bundleIds` response into the list of registered identifier
180
+ * strings, dropping any falsy entries (missing `attributes`/`identifier`).
181
+ */
182
+ export declare function parseBundleIdsResponse(json: any): string[];
183
+ /**
184
+ * List every App Store Connect app visible to the API key, following
185
+ * pagination. Uses the existing {@link ascFetch} — no separate fetch path.
186
+ */
187
+ export declare function listApps(token: string): Promise<AscApp[]>;
188
+ /**
189
+ * List every registered bundle ID identifier visible to the API key, following
190
+ * pagination. Uses the existing {@link ascFetch} — no separate fetch path.
191
+ */
192
+ export declare function listBundleIds(token: string): Promise<string[]>;
193
+ /**
194
+ * Get the profile name we use for a given appId.
195
+ */
196
+ export declare function getCapgoProfileName(appId: string): string;
197
+ /**
198
+ * Find existing provisioning profiles matching our naming convention.
199
+ * Only returns profiles we created (named "Capgo <appId> AppStore").
200
+ */
201
+ export declare function findCapgoProfiles(token: string, appId: string): Promise<Array<{
202
+ id: string;
203
+ name: string;
204
+ profileType: string;
205
+ }>>;
206
+ /**
207
+ * Delete a provisioning profile by ID.
208
+ */
209
+ export declare function deleteProfile(token: string, profileId: string): Promise<void>;
210
+ /**
211
+ * Create an App Store provisioning profile linking a certificate and bundle ID.
212
+ * Returns the base64 mobileprovision content.
213
+ *
214
+ * Throws a DuplicateProfileError if duplicate profiles exist, so the caller
215
+ * can ask the user whether to delete them and retry.
216
+ */
217
+ export declare class DuplicateProfileError extends Error {
218
+ readonly profiles: Array<{
219
+ id: string;
220
+ name: string;
221
+ profileType: string;
222
+ }>;
223
+ constructor(profiles: Array<{
224
+ id: string;
225
+ name: string;
226
+ profileType: string;
227
+ }>);
228
+ }
229
+ export declare function createProfile(token: string, bundleIdResourceId: string, certificateId: string, appId: string): Promise<{
230
+ profileId: string;
231
+ profileName: string;
232
+ profileContent: string;
233
+ expirationDate: string;
234
+ }>;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Turn a raw streamed build-log chunk into clean display lines.
3
+ *
4
+ * Splits on `\n` AND bare `\r` (an in-place redraw becomes its own line rather
5
+ * than fusing with another), strips ANSI/escape/control bytes, trims trailing
6
+ * whitespace, and drops the empty element a trailing newline would add (interior
7
+ * blank lines — e.g. the intentional spacer before the first log line — are
8
+ * kept). A chunk may be a single line or several; callers spread the result.
9
+ */
10
+ export declare function sanitizeBuildLogLines(chunk: string): string[];
@@ -0,0 +1,117 @@
1
+ export type BundleIdSource = 'pbxproj-release' | 'pbxproj-debug' | 'pbxproj-fallback' | 'plist' | 'capacitor-config';
2
+ export interface BundleIdCandidate {
3
+ value: string;
4
+ source: BundleIdSource;
5
+ /** Short human-readable label for the picker, e.g. "project.pbxproj (Release)". */
6
+ label: string;
7
+ }
8
+ export interface DetectedBundleIds {
9
+ /** PRODUCT_BUNDLE_IDENTIFIER from project.pbxproj, preferring Release config. */
10
+ pbxproj: BundleIdCandidate | null;
11
+ /**
12
+ * The Debug-config PRODUCT_BUNDLE_IDENTIFIER from project.pbxproj, when a
13
+ * literal value exists. Exposed for the awareness note only — never used to
14
+ * gate. Null when no Debug-config literal value is present.
15
+ */
16
+ debug: BundleIdCandidate | null;
17
+ /**
18
+ * Info.plist CFBundleIdentifier when it's a literal value (not the common
19
+ * `$(PRODUCT_BUNDLE_IDENTIFIER)` placeholder, which we drop because it
20
+ * adds nothing the pbxproj source doesn't already cover).
21
+ */
22
+ plist: BundleIdCandidate | null;
23
+ /** capacitor.config.ts/json's appId — always present (it's a required arg). */
24
+ capacitor: BundleIdCandidate;
25
+ /**
26
+ * The best-guess Apple-side bundle ID, picked in priority order:
27
+ * pbxproj-release > pbxproj-fallback > plist > capacitor. Returned for
28
+ * convenience so callers don't have to re-implement the precedence.
29
+ */
30
+ recommended: BundleIdCandidate;
31
+ /**
32
+ * True when the recommended value differs from capacitor.config.appId.
33
+ * Used by redirectIfMismatch to decide whether to adopt the Release id —
34
+ * when they match, capacitor.config.appId is already the build id.
35
+ */
36
+ mismatch: boolean;
37
+ /**
38
+ * True only when BOTH a Release-config and a Debug-config literal bundle id
39
+ * were found AND they differ. Drives the "Debug ≠ Release" awareness note;
40
+ * never gates. False when either value is missing or they match.
41
+ */
42
+ debugReleaseDiffer: boolean;
43
+ /**
44
+ * True when a Release-config PRODUCT_BUNDLE_IDENTIFIER was resolved from
45
+ * pbxproj. When false, the authoritative build ID could not be determined
46
+ * from Release and callers should warn/skip gating rather than gate on a
47
+ * Debug or plist fallback.
48
+ */
49
+ releaseResolved: boolean;
50
+ /**
51
+ * Deduplicated, ordered list of candidates ready to render as Select
52
+ * options. Empty list is impossible (capacitor is always included).
53
+ */
54
+ candidates: BundleIdCandidate[];
55
+ }
56
+ /**
57
+ * Parse `PRODUCT_BUNDLE_IDENTIFIER = "..."` lines from pbxproj content,
58
+ * returning the Release and Debug candidates separately.
59
+ *
60
+ * Release is authoritative: when ANY Release-config value exists, `release`
61
+ * is populated and `releaseResolved` is true. The Debug value (when present)
62
+ * is returned alongside via `debug` for the awareness note — it is never
63
+ * promoted to `release`.
64
+ *
65
+ * When no Release config exists, `release` is null and `releaseResolved` is
66
+ * false so callers can detect the no-Release case.
67
+ */
68
+ export declare function parsePbxprojBundleIds(pbxprojContent: string): {
69
+ release: BundleIdCandidate | null;
70
+ debug: BundleIdCandidate | null;
71
+ releaseResolved: boolean;
72
+ };
73
+ /**
74
+ * Parse `PRODUCT_BUNDLE_IDENTIFIER = "..."` lines from pbxproj content.
75
+ * Returns the Release-config value if present, else the shortest non-Release
76
+ * value as a `pbxproj-fallback`. Returns null when no bundle id can be
77
+ * extracted.
78
+ *
79
+ * Release stays authoritative here: a Release value is never overridden by a
80
+ * Debug value. The no-Release fallback is preserved for backward
81
+ * compatibility — callers that need to distinguish "Release resolved" from
82
+ * "fell back to Debug" should use `parsePbxprojBundleIds` (or the
83
+ * `releaseResolved` flag on `detectIosBundleIds`).
84
+ *
85
+ * Looks like a re-implementation of pbxproj-parser.ts's resolveBundleId, but
86
+ * that one needs an XCConfigurationList id (it walks from a target). This
87
+ * one needs to work standalone given only the file contents — so it
88
+ * collects all PRODUCT_BUNDLE_IDENTIFIER values, groups by adjacent
89
+ * `name = Release`/`name = Debug` markers, and prefers Release. Less
90
+ * accurate for multi-target projects but good enough for the "what should
91
+ * we pre-fill" use case here.
92
+ */
93
+ export declare function parsePbxprojBundleId(pbxprojContent: string): BundleIdCandidate | null;
94
+ /**
95
+ * Parse Info.plist's CFBundleIdentifier from raw XML.
96
+ * Returns null when the file is empty, when CFBundleIdentifier is absent,
97
+ * or when it's a `$(PRODUCT_BUNDLE_IDENTIFIER)` variable reference (we drop
98
+ * the placeholder so the picker doesn't list a non-actionable option).
99
+ */
100
+ export declare function parseInfoPlistBundleId(plistContent: string): BundleIdCandidate | null;
101
+ /**
102
+ * Read project.pbxproj and Info.plist from the iOS dir and return all
103
+ * available bundle id candidates, plus the recommended one and a
104
+ * mismatch flag.
105
+ *
106
+ * Filesystem reads are best-effort — when either file is missing or
107
+ * unreadable, we silently skip that source. The capacitor candidate is
108
+ * always present.
109
+ */
110
+ export declare function detectIosBundleIds(opts: {
111
+ /** Project root (typically `process.cwd()`). */
112
+ cwd: string;
113
+ /** Subdirectory under cwd holding the iOS project (typically "ios"). */
114
+ iosDir: string;
115
+ /** Bundle id read from capacitor.config.ts/json — always known. */
116
+ capacitorAppId: string;
117
+ }): DetectedBundleIds;
@@ -0,0 +1,87 @@
1
+ import type { BuildCredentials } from '../../schemas/build.js';
2
+ export type CiSecretProvider = 'github' | 'gitlab';
3
+ export interface CiSecretEntry {
4
+ key: string;
5
+ value: string;
6
+ masked: boolean;
7
+ }
8
+ export interface CiSecretTarget {
9
+ provider: CiSecretProvider;
10
+ label: string;
11
+ cli: 'gh' | 'glab';
12
+ }
13
+ export interface CiSecretDiscovery {
14
+ targets: CiSecretTarget[];
15
+ setup: CiSecretSetupAdvice[];
16
+ notes: string[];
17
+ }
18
+ export interface CiSecretSetupAdvice {
19
+ target: CiSecretTarget;
20
+ reason: 'not-installed' | 'not-authenticated';
21
+ message: string;
22
+ commands: string[];
23
+ }
24
+ interface CommandRunOptions {
25
+ input?: string;
26
+ }
27
+ export interface CommandRunResult {
28
+ status: number | null;
29
+ stdout: string;
30
+ stderr: string;
31
+ error?: Error;
32
+ }
33
+ export type CommandRunner = (command: string, args: string[], options?: CommandRunOptions) => CommandRunResult;
34
+ /**
35
+ * Async runner. Used by the wizard so spawned `gh` / `glab` calls don't block
36
+ * the Node event loop — without this, `ink-spinner`'s animation freezes for
37
+ * the entire duration of every shell-out, which feels like the wizard has hung.
38
+ *
39
+ * Tests can pass either a sync (CommandRunner) or async runner — every helper
40
+ * that calls runner.* does so via `await` so a sync runner returning a plain
41
+ * result still works (Promise.resolve coerces it).
42
+ */
43
+ export type AsyncCommandRunner = (command: string, args: string[], options?: CommandRunOptions) => CommandRunResult | Promise<CommandRunResult>;
44
+ export declare function runCommand(command: string, args: string[], options?: CommandRunOptions): CommandRunResult;
45
+ /**
46
+ * Non-blocking shell-out. Mirrors `runCommand`'s shape but uses `spawn` so
47
+ * the Node event loop is free to tick spinners and process input while gh /
48
+ * glab work. Default for any wizard-side helper that needs to render UI
49
+ * during the call.
50
+ */
51
+ export declare function runCommandAsync(command: string, args: string[], options?: CommandRunOptions): Promise<CommandRunResult>;
52
+ export declare function createCiSecretEntries(credentials: Partial<BuildCredentials>, apiKey?: string): CiSecretEntry[];
53
+ export declare function detectCiSecretTargets(runner?: CommandRunner): CiSecretDiscovery;
54
+ export declare function getCiSecretTargetLabel(target: CiSecretTarget | null | undefined): string;
55
+ /**
56
+ * Resolve the concrete `owner/repo` (GitHub) or `group/project` (GitLab) the
57
+ * `gh` / `glab` CLI will target from the current working directory.
58
+ *
59
+ * Returns null when the CLI can't determine the repo (e.g. cwd is not a git
60
+ * repo, multiple remotes with no `gh-resolved` config, auth scopes missing).
61
+ *
62
+ * The wizard MUST show this string to the user and require explicit
63
+ * confirmation before any `gh secret set` / `glab variable set` runs — those
64
+ * commands silently overwrite without backup, so the user has to know which
65
+ * repo they're about to mutate.
66
+ */
67
+ export declare function getCiSecretRepoLabel(target: CiSecretTarget, runner?: CommandRunner): string | null;
68
+ /**
69
+ * Non-blocking variant of `getCiSecretRepoLabel`. Identical logic, but
70
+ * `await`s the runner so the event loop can tick during the gh/glab call —
71
+ * lets Ink spinners actually animate during the resolution.
72
+ */
73
+ export declare function getCiSecretRepoLabelAsync(target: CiSecretTarget, runner?: AsyncCommandRunner): Promise<string | null>;
74
+ export declare function listExistingCiSecretKeys(target: CiSecretTarget, keys: string[], runner?: CommandRunner): string[];
75
+ /** Non-blocking variant of `listExistingCiSecretKeys`. */
76
+ export declare function listExistingCiSecretKeysAsync(target: CiSecretTarget, keys: string[], runner?: AsyncCommandRunner): Promise<string[]>;
77
+ export declare function uploadCiSecrets(target: CiSecretTarget, entries: CiSecretEntry[], existingKeys?: string[], runner?: CommandRunner): void;
78
+ /**
79
+ * Non-blocking variant of `uploadCiSecrets`. Calls `onProgress(current, total,
80
+ * keyName)` before every `gh secret set` / `glab variable set` so the wizard
81
+ * can render "Pushing N of M: <KEY>…" instead of a frozen spinner.
82
+ *
83
+ * Pushes are still sequential — gh/glab don't have a bulk-set API, and
84
+ * parallelising would risk rate limits + makes failure semantics ambiguous.
85
+ */
86
+ export declare function uploadCiSecretsAsync(target: CiSecretTarget, entries: CiSecretEntry[], existingKeys?: string[], runner?: AsyncCommandRunner, onProgress?: (current: number, total: number, keyName: string) => void): Promise<void>;
87
+ export {};
@@ -0,0 +1,6 @@
1
+ export interface OnboardingBuilderOptions {
2
+ apikey?: string;
3
+ platform?: string;
4
+ supaHost?: string;
5
+ }
6
+ export declare function onboardingBuilderCommand(options?: OnboardingBuilderOptions): Promise<void>;
@@ -0,0 +1,33 @@
1
+ export interface CsrResult {
2
+ csrPem: string;
3
+ privateKeyPem: string;
4
+ }
5
+ export interface P12Result {
6
+ p12Base64: string;
7
+ }
8
+ /**
9
+ * Generate a 2048-bit RSA key pair and a Certificate Signing Request.
10
+ * The CSR is what Apple needs to create a distribution certificate.
11
+ * The private key must be kept to later create the .p12 file.
12
+ */
13
+ export declare function generateCsr(): CsrResult;
14
+ /**
15
+ * Create a PKCS#12 (.p12) file from Apple's certificate response and the private key.
16
+ *
17
+ * @param certificateContentBase64 - The `certificateContent` field from Apple's
18
+ * POST /v1/certificates response (base64-encoded DER certificate)
19
+ * @param privateKeyPem - The PEM-encoded private key from generateCsr()
20
+ * @param password - Optional password for the .p12 file (defaults to DEFAULT_P12_PASSWORD)
21
+ */
22
+ /**
23
+ * Extract the Apple team ID from a certificate's subject OU field.
24
+ * More reliable than parsing the certificate name string.
25
+ */
26
+ export declare function extractTeamIdFromCert(certificateContentBase64: string): string;
27
+ /**
28
+ * Default P12 password. node-forge P12 with empty password is incompatible
29
+ * with macOS `security import` (MAC verification fails). Using a known
30
+ * non-empty password avoids this issue.
31
+ */
32
+ export declare const DEFAULT_P12_PASSWORD = "capgo";
33
+ export declare function createP12(certificateContentBase64: string, privateKeyPem: string, password?: string): P12Result;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Line-by-line diff utilities for the workflow-file preview viewer.
3
+ *
4
+ * Uses a textbook longest-common-subsequence algorithm. O(m·n) time/space
5
+ * which is fine for the workflow-file scale we expect (≤200 lines either
6
+ * side); no dep needed.
7
+ */
8
+ export type DiffKind = 'add' | 'del' | 'eq';
9
+ export interface DiffLine {
10
+ kind: DiffKind;
11
+ text: string;
12
+ }
13
+ /**
14
+ * Compute a line-level diff between `before` and `after`.
15
+ *
16
+ * Returns an ordered list of lines where:
17
+ * - `kind: 'eq'` → present in both, unchanged
18
+ * - `kind: 'add'` → present only in `after` (will be added by the write)
19
+ * - `kind: 'del'` → present only in `before` (will be removed by the write)
20
+ *
21
+ * When `before` is the empty string, every line in `after` is returned as
22
+ * `add` — the natural "new file" rendering.
23
+ */
24
+ export declare function diffLines(before: string, after: string): DiffLine[];
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Build-onboarding helper to write a single-platform .env file with the build
3
+ * credentials the user just saved. Used on the "No to GitHub Actions setup, but
4
+ * yes to .env export" branch of the wizard.
5
+ *
6
+ * Reuses the renderer from `build credentials manage` so the file format
7
+ * (section comments, .gitignore reminder, provisioning-map base64 fallback)
8
+ * stays identical between the two paths.
9
+ */
10
+ import type { BuildCredentials } from '../../schemas/build.js';
11
+ export interface EnvExportOpts {
12
+ appId: string;
13
+ platform: 'ios' | 'android';
14
+ credentials: Partial<BuildCredentials>;
15
+ /** Default false — onboarding writes into the global store, not local. */
16
+ local?: boolean;
17
+ /** If absent, defaults to `<cwd>/.env.capgo.<appId>.<platform>`. */
18
+ targetPath?: string;
19
+ /** When true, write even if the file already exists. */
20
+ overwrite?: boolean;
21
+ }
22
+ export type EnvExportResult = {
23
+ kind: 'written';
24
+ path: string;
25
+ fieldCount: number;
26
+ } | {
27
+ kind: 'exists';
28
+ path: string;
29
+ } | {
30
+ kind: 'empty';
31
+ };
32
+ /**
33
+ * Resolve where the .env file should land for the given app + platform. Pure —
34
+ * callable before deciding to actually write, so the wizard can show the path
35
+ * in a confirm prompt without committing to write yet.
36
+ */
37
+ export declare function defaultExportPath(appId: string, platform: 'ios' | 'android'): string;
38
+ /**
39
+ * Write the credentials to a .env file. Caller is responsible for deciding
40
+ * whether the user has consented (no prompts in here — pure file I/O so the
41
+ * Ink wizard owns the UX).
42
+ *
43
+ * Returns `kind: 'exists'` if the target file is already present and
44
+ * `overwrite` was not set — caller can prompt the user and retry.
45
+ */
46
+ export declare function exportCredentialsToEnv(opts: EnvExportOpts): EnvExportResult;
@@ -0,0 +1,13 @@
1
+ import type { AndroidOnboardingErrorCategory } from './android/types.js';
2
+ import type { OnboardingErrorCategory, OnboardingStep } from './types.js';
3
+ export declare function mapIosOnboardingError(error: unknown, failedStep?: OnboardingStep): OnboardingErrorCategory;
4
+ export declare function mapAndroidOnboardingError(error: unknown): AndroidOnboardingErrorCategory;
5
+ /**
6
+ * Map a `ValidationResult.kind` from the SA-import validation module onto an
7
+ * AndroidOnboardingErrorCategory so PostHog `Builder Onboarding Step` events
8
+ * for `sa-json-validation-failed` carry an actionable failure dimension.
9
+ *
10
+ * Kept here (alongside `mapAndroidOnboardingError`) so the full SA-error
11
+ * taxonomy lives in one place.
12
+ */
13
+ export declare function mapSaValidationKindToCategory(kind: 'shape-error' | 'token-error' | 'no-app-access' | 'network-error'): AndroidOnboardingErrorCategory;