@capgo/cli 8.31.3 → 8.31.5

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.
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capgo/cli",
3
3
  "type": "module",
4
- "version": "8.31.3",
4
+ "version": "8.31.5",
5
5
  "description": "A CLI to upload to capgo servers",
6
6
  "author": "Martin martin@capgo.app",
7
7
  "license": "Apache 2.0",
@@ -160,7 +160,7 @@
160
160
  "test:ios-marketing-version": "bun test/test-ios-marketing-version.mjs",
161
161
  "test:platform-flow-contract": "bun test/test-platform-flow-contract.mjs",
162
162
  "test:tail-engine-shared": "bun test/test-tail-engine-shared.mjs",
163
- "test": "bun run build && bun run test:helper-dce && bun run test:version-detection:setup && bun run test:bundle && bun run test:functional && bun run test:semver && bun run test:version-edge-cases && bun run test:regex && bun run test:upload && bun run test:fail-on-incompatible && bun run test:native-dependencies && bun run test:credentials && bun run test:credentials-validation && bun run test:android-service-account-validation && bun run test:build-zip-filter && bun run test:checksum && bun run test:build-needed && bun run test:ci-prompts && bun run test:ci-secrets && bun run test:android-onboarding-progress && bun run test:onboarding-telemetry && bun run test:v2-event-migration && bun run test:analytics && bun run test:analytics-error-category && bun run test:analytics-org-resolver && bun run test:supabase-perf && bun run test:preview-qr && bun run test:app-set-options && bun run test:mcp-analytics && bun run test:mcp-instructions && bun run test:mcp-live-update-onboarding && bun run test:mcp-stdout-guard && bun run test:mcp-platform-select && bun run test:mcp-explain-scopes && bun run test:mcp-oauth-reopen && bun run test:mcp-broker-oauth && bun run test:mcp-broker-session && bun run test:mcp-credentials-manage && bun run test:mcp-resume-prompt && bun run test:mcp-build-job && bun run test:mcp-build-tools && bun run test:app-created-source && bun run test:doctor-analytics && bun run test:posthog-exception && bun run test:build-platform-selection && bun run test:onboarding-recovery && bun run test:onboarding-progress && bun run test:onboarding-run-targets && bun run test:run-device-command && bun run test:init-monorepo-targeting && bun run test:init-app-conflict && bun run test:init-guardrails && bun run test:init-replay && bun run test:prompt-preferences && bun run test:esm-sdk && bun run test:mcp && bun run test:mcp-no-key-handshake && bun run test:auth-session && bun run test:version-detection && bun run test:platform-paths && bun run test:project-type-detection && bun run test:payload-split && bun run test:manifest-path-encoding && bun run test:macos-signing && bun run test:asc-key-protocol && bun run test:apple-api-import-helpers && bun run test:apple-api-verify-key && bun run test:bundle-id-detector && bun run test:apple-api-app-list && bun run test:app-verification && bun run test:pbxproj-parser && bun run test:ai-log-capture && bun run test:ai-analyze-flow && bun run test:cicd-failure-help && bun run test:ai-sse-parser && bun run test:ai-render-markdown && bun run test:ai-stream-markdown && bun run test:ai-onboarding-mode && bun run test:ai-fit && bun run test:platform-layout && bun run test:frame-fit && bun run test:onboarding-min-size && bun run test:min-size-gate && bun run test:shell-size-gate && bun run test:build-log-sanitize && bun run test:build-output-viewport && bun run test:diff-viewer-viewport && bun run test:build-complete-exit && bun run test:ai-analyze-stream && bun run test:support-mailto && bun run test:support-redact && bun run test:support-internal-log && bun run test:support-help-menu && bun run test:support-contact && bun run test:support-upload-prompt && bun run test:support-bundle-files && bun run test:self-update && bun run test:update-prompt && bun run test:apple-api-cert-create && bun run test:android-tail-engine && bun run test:android-tail-render && bun run test:android-tail-routing && bun run test:dev-gate-stripped && bun run test:frame-fit-ios-shared && bun run test:ios-confirm-app-id && bun run test:ios-create-new && bun run test:ios-e2e && bun run test:ios-flow-contract && bun run test:ios-import-discovery && bun run test:ios-import-export && bun run test:ios-import-pickers && bun run test:ios-import-recovery && bun run test:ios-recovery && bun run test:ios-resume && bun run test:ios-tail-handoff && bun run test:ios-tui-render && bun run test:p8-error && bun run test:ios-tui-routing && bun run test:ios-updater-sync-validation && bun run test:ios-verify-app && bun run test:ios-marketing-version && bun run test:platform-flow-contract && bun run test:tail-engine-shared && bun run test:prescan && bun run test:android-reporting-api && bun run test:android-app-verification && bun run test:android-rename && bun run test:appflow-auth && bun run test:appflow-api-map && bun run test:appflow-validate && bun run test:appflow-flow && bun run test:appflow-gapfill && bun run test:appflow-engine && bun run test:appflow-tail && bun run test:appflow-fetch && bun run test:appflow-sa-decode && bun run test:app-permission-helper && bun run test:organization-set-api-host && bun run test:trial-warning",
163
+ "test": "bun run build && bun run test:helper-dce && bun run test:version-detection:setup && bun run test:bundle && bun run test:functional && bun run test:semver && bun run test:version-edge-cases && bun run test:regex && bun run test:upload && bun run test:fail-on-incompatible && bun run test:native-dependencies && bun run test:credentials && bun run test:credentials-validation && bun run test:android-service-account-validation && bun run test:build-zip-filter && bun run test:checksum && bun run test:build-needed && bun run test:ci-prompts && bun run test:ci-secrets && bun run test:android-onboarding-progress && bun run test:onboarding-telemetry && bun run test:v2-event-migration && bun run test:analytics && bun run test:analytics-error-category && bun run test:analytics-org-resolver && bun run test:supabase-perf && bun run test:preview-qr && bun run test:app-set-options && bun run test:mcp-analytics && bun run test:mcp-instructions && bun run test:mcp-live-update-onboarding && bun run test:mcp-stdout-guard && bun run test:mcp-platform-select && bun run test:mcp-explain-scopes && bun run test:mcp-oauth-reopen && bun run test:mcp-broker-oauth && bun run test:mcp-broker-session && bun run test:mcp-credentials-manage && bun run test:mcp-resume-prompt && bun run test:mcp-build-job && bun run test:mcp-build-tools && bun run test:app-created-source && bun run test:doctor-analytics && bun run test:posthog-exception && bun run test:build-platform-selection && bun run test:onboarding-recovery && bun run test:onboarding-progress && bun run test:onboarding-run-targets && bun run test:run-device-command && bun run test:init-monorepo-targeting && bun run test:init-app-conflict && bun run test:init-guardrails && bun run test:init-replay && bun run test:prompt-preferences && bun run test:esm-sdk && bun run test:mcp && bun run test:mcp-no-key-handshake && bun run test:auth-session && bun run test:version-detection && bun run test:platform-paths && bun run test:project-type-detection && bun run test:payload-split && bun run test:manifest-path-encoding && bun run test:macos-signing && bun run test:asc-key-protocol && bun run test:apple-api-import-helpers && bun run test:apple-api-verify-key && bun run test:bundle-id-detector && bun run test:apple-api-app-list && bun run test:app-verification && bun run test:pbxproj-parser && bun run test:ai-log-capture && bun run test:ai-analyze-flow && bun run test:cicd-failure-help && bun run test:ai-sse-parser && bun run test:ai-render-markdown && bun run test:ai-stream-markdown && bun run test:ai-onboarding-mode && bun run test:ai-fit && bun run test:platform-layout && bun run test:frame-fit && bun run test:onboarding-min-size && bun run test:min-size-gate && bun run test:shell-size-gate && bun run test:build-log-sanitize && bun run test:build-output-viewport && bun run test:diff-viewer-viewport && bun run test:build-complete-exit && bun run test:ai-analyze-stream && bun run test:support-mailto && bun run test:support-redact && bun run test:support-internal-log && bun run test:support-help-menu && bun run test:support-contact && bun run test:support-upload-prompt && bun run test:support-bundle-files && bun run test:self-update && bun run test:update-prompt && bun run test:apple-api-cert-create && bun run test:android-tail-engine && bun run test:android-tail-render && bun run test:android-tail-routing && bun run test:dev-gate-stripped && bun run test:frame-fit-ios-shared && bun run test:ios-confirm-app-id && bun run test:ios-create-new && bun run test:ios-e2e && bun run test:ios-flow-contract && bun run test:ios-import-discovery && bun run test:ios-import-export && bun run test:ios-import-pickers && bun run test:ios-import-recovery && bun run test:ios-recovery && bun run test:ios-resume && bun run test:ios-tail-handoff && bun run test:ios-tui-render && bun run test:p8-error && bun run test:ios-tui-routing && bun run test:ios-updater-sync-validation && bun run test:ios-verify-app && bun run test:ios-marketing-version && bun run test:platform-flow-contract && bun run test:tail-engine-shared && bun run test:prescan && bun run test:android-reporting-api && bun run test:android-app-verification && bun run test:android-rename && bun run test:appflow-auth && bun run test:appflow-api-map && bun run test:appflow-validate && bun run test:appflow-flow && bun run test:appflow-gapfill && bun run test:appflow-engine && bun run test:appflow-tail && bun run test:appflow-fetch && bun run test:appflow-sa-decode && bun run test:app-permission-helper && bun run test:organization-set-api-host && bun run test:trial-warning && bun run test:plan-validation",
164
164
  "test:build-platform-selection": "bun test/test-build-platform-selection.mjs",
165
165
  "test:ai-log-capture": "bun test/test-ai-log-capture.mjs",
166
166
  "test:ai-analyze-flow": "bun test/test-ai-analyze-flow.mjs",
@@ -203,7 +203,8 @@
203
203
  "test:appflow-sa-decode": "bun test/test-appflow-sa-decode.mjs",
204
204
  "test:app-permission-helper": "bun test/test-app-permission-helper.mjs",
205
205
  "test:organization-set-api-host": "bun test/test-organization-set-api-host.mjs",
206
- "test:trial-warning": "bun test/test-trial-warning.mjs"
206
+ "test:trial-warning": "bun test/test-trial-warning.mjs",
207
+ "test:plan-validation": "bun test/test-plan-validation.mjs"
207
208
  },
208
209
  "dependencies": {
209
210
  "@inkjs/ui": "^2.0.0",
@@ -23,7 +23,20 @@ export interface MobileprovisionDetail extends MobileprovisionInfo {
23
23
  profileType: 'app_store' | 'ad_hoc' | 'development' | 'enterprise' | 'unknown';
24
24
  /** SHA1 (40-char lowercase hex) of each DeveloperCertificate embedded in the profile */
25
25
  certificateSha1s: string[];
26
+ /**
27
+ * The capability-bearing keys parsed from the profile's `<key>Entitlements</key>`
28
+ * dict, keyed by entitlement name. String/bool entitlements map to their value;
29
+ * array entitlements (application-groups, associated-domains, keychain-access-groups,
30
+ * iCloud container ids, etc.) map to the list of `<string>` members. Only keys
31
+ * actually present in the profile are included, so a caller can both test
32
+ * presence (`key in profileEntitlements`) and read the granted value/members.
33
+ * No credential material is included — these are capability KEY names + their
34
+ * declared identifiers, the same data the entitlement-coverage checks surface.
35
+ */
36
+ profileEntitlements: ProfileEntitlements;
26
37
  }
38
+ export type ProfileEntitlementValue = string | string[] | boolean;
39
+ export type ProfileEntitlements = Record<string, ProfileEntitlementValue>;
27
40
  export declare function parseMobileprovision(filePath: string): MobileprovisionInfo;
28
41
  export declare function parseMobileprovisionFromBase64(base64Content: string): MobileprovisionInfo;
29
42
  /**
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Major version of the Capacitor runtime declared in package.json, or null.
3
+ *
4
+ * Checks `@capacitor/core` first (the platform-agnostic runtime), then the
5
+ * platform packages `@capacitor/ios` and `@capacitor/android`, so both the iOS
6
+ * and Android prescan checks resolve the same major from one shared place.
7
+ * Reads dev+prod dependencies, returns null on a missing/malformed package.json
8
+ * (never throws).
9
+ */
10
+ export declare function capacitorMajor(projectDir: string): number | null;
@@ -0,0 +1,4 @@
1
+ import type { PrescanCheck } from '../types';
2
+ export declare const serverUrlShipped: PrescanCheck;
3
+ export declare const serverCleartext: PrescanCheck;
4
+ export declare const allowNavigationWildcard: PrescanCheck;
@@ -0,0 +1,5 @@
1
+ import type { PrescanCheck } from '../types';
2
+ export declare const entitlementsVsProfileCapability: PrescanCheck;
3
+ export declare const apsEnvironmentVsMode: PrescanCheck;
4
+ export declare const associatedDomainsFormat: PrescanCheck;
5
+ export declare const appGroupsFormat: PrescanCheck;
@@ -0,0 +1,11 @@
1
+ import type { PrescanCheck } from '../types';
2
+ export declare const plistBundleIdFormat: PrescanCheck;
3
+ export declare const plistVersionShortFormat: PrescanCheck;
4
+ export declare const plistVersionBuildFormat: PrescanCheck;
5
+ export declare const plistEncryptionCompliance: PrescanCheck;
6
+ export declare const plistAtsArbitraryLoads: PrescanCheck;
7
+ export declare const plistLaunchStoryboard: PrescanCheck;
8
+ export declare const plistOrientationsMultitasking: PrescanCheck;
9
+ export declare const plistOrientationsPresent: PrescanCheck;
10
+ export declare const plistDisplayName: PrescanCheck;
11
+ export declare const plistBackgroundModesSanity: PrescanCheck;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Top-level `<key>K</key><string>V</string>` value, or null when absent.
3
+ * V is returned verbatim, including an unresolved `$(VAR)` build-variable
4
+ * reference — callers run it through resolvePlistValue before validating.
5
+ */
6
+ export declare function plistString(raw: string, key: string): string | null;
7
+ /**
8
+ * Boolean for `<key>K</key>\s*<true/>|<false/>`. Returns null when the key is
9
+ * absent OR maps to a non-bool value — null is meaningfully distinct from false
10
+ * (e.g. UIRequiresFullScreen absent vs. explicitly false).
11
+ */
12
+ export declare function plistBool(raw: string, key: string): boolean | null;
13
+ /** Presence-only check for a `<key>K</key>` element. */
14
+ export declare function plistHasKey(raw: string, key: string): boolean;
15
+ /**
16
+ * The `<string>` children of `<key>K</key>\s*<array>...</array>`, or [] when the
17
+ * key is absent / not an array. Non-greedy so the first `</array>` wins. Note
18
+ * that the key match is anchored on `</key>`, so a suffixed key such as
19
+ * `K~ipad` is NOT matched by a request for the plain `K` (and vice-versa).
20
+ */
21
+ export declare function plistArrayStrings(raw: string, key: string): string[];
22
+ /**
23
+ * Inner text of `<key>K</key>\s*<dict>...</dict>`, or null when the key is
24
+ * absent. Returns the FULL balanced dict: it scans `<dict>` / `</dict>` depth
25
+ * from the opening dict to its matching close, so arbitrarily nested dicts are
26
+ * captured intact. This matters for keys like NSAppTransportSecurity, where a
27
+ * nested NSExceptionDomains dict appearing BEFORE a sibling such as
28
+ * NSAllowsArbitraryLoads would otherwise truncate the block at the first
29
+ * `</dict>` and hide the sibling. Used to scope reads such as
30
+ * NSAppTransportSecurity. Pure; returns null on a missing key or an unbalanced
31
+ * (malformed) dict.
32
+ */
33
+ export declare function plistDictBlock(raw: string, key: string): string | null;
@@ -0,0 +1,55 @@
1
+ import type { PrescanCheck } from '../types';
2
+ /**
3
+ * Podfile present but `Pods/` or `App.xcworkspace` missing. The cloud builder
4
+ * runs `pod install` (regenerating both), so this is a WARNING, not an error -
5
+ * it slows the first build and breaks local Xcode opens, but the server recovers.
6
+ */
7
+ export declare const podsNotInstalled: PrescanCheck;
8
+ /** Podfile present but Podfile.lock absent - non-reproducible pod resolution. */
9
+ export declare const podsLockMissing: PrescanCheck;
10
+ /**
11
+ * Podfile does not wire the Capacitor pod. `pod install` cannot inject a missing
12
+ * declaration, but the standard Capacitor Podfile uses the `capacitor_pods`
13
+ * helper / `require_relative` rather than a literal `pod 'Capacitor'`, so the
14
+ * literal-match heuristic is high false-positive. WARNING, not error.
15
+ */
16
+ export declare const podsCapacitorMissing: PrescanCheck;
17
+ /**
18
+ * SPM project with no Package.resolved in either known location. `build_app`
19
+ * (xcodebuild) resolves packages during the build, so this is a WARNING - a
20
+ * committed Package.resolved just makes resolution reproducible and faster.
21
+ */
22
+ export declare const spmPackageResolvedMissing: PrescanCheck;
23
+ /**
24
+ * Package.swift does not declare the capacitor-swift-pm dependency / the
25
+ * Capacitor product. The builder never runs `cap sync`, but Package.swift is
26
+ * CLI-managed ("DO NOT MODIFY") and the regex is high false-positive on valid
27
+ * variants, so this is a WARNING, not an error.
28
+ */
29
+ export declare const spmCapacitorDependencyMissing: PrescanCheck;
30
+ /**
31
+ * AppIcon.appiconset directory missing, Contents.json missing/malformed, or no
32
+ * icon images declared. The directory-missing and malformed-Contents cases are
33
+ * always errors (the asset catalog is structurally broken). The "no images"
34
+ * case is a WARNING by default (actool tolerates it for ad_hoc/dev) and
35
+ * ESCALATES to error when uploading to the App Store (ITMS-90704 blocks upload).
36
+ */
37
+ export declare const appiconEmptyOrPlaceholder: PrescanCheck;
38
+ /**
39
+ * A Contents.json image entry references a filename that is missing from disk.
40
+ * `actool` FAILS server-side in this case, so this KEEPS error severity.
41
+ */
42
+ export declare const appiconReferencedFileMissing: PrescanCheck;
43
+ /**
44
+ * App Store marketing icon (1024x1024 / role=marketing) missing. Upload-gated:
45
+ * ad_hoc/dev builds do not need it, but App Store upload requires it
46
+ * (ITMS-90704). KEEPS error severity.
47
+ */
48
+ export declare const appiconMarketingMissing: PrescanCheck;
49
+ /**
50
+ * SPM project where the pbxproj IPHONEOS_DEPLOYMENT_TARGET is LOWER than the
51
+ * Package.swift platform minimum (`.iOS(.vN)`) - the dangerous direction: the
52
+ * package requires a newer floor than the app builds against. Warning only;
53
+ * skipped entirely when IPHONEOS_DEPLOYMENT_TARGET is absent (inherited/unknown).
54
+ */
55
+ export declare const spmDeploymentTargetConsistency: PrescanCheck;
@@ -0,0 +1,8 @@
1
+ import type { PrescanCheck } from '../types';
2
+ export declare const deploymentTargetCapacitor: PrescanCheck;
3
+ export declare const signingTeam: PrescanCheck;
4
+ export declare const bundleIdMismatchAcrossConfigs: PrescanCheck;
5
+ export declare const enableBitcodeLeftover: PrescanCheck;
6
+ export declare const swiftVersionSanity: PrescanCheck;
7
+ export declare const noAppTarget: PrescanCheck;
8
+ export declare const multipleAppTargets: PrescanCheck;
@@ -11,6 +11,8 @@ export interface PrescanCommandOptions {
11
11
  verbose?: boolean;
12
12
  supaHost?: string;
13
13
  supaAnon?: string;
14
+ /** Test seam for hard-coded rollout deadlines; defaults to the current time. */
15
+ now?: Date;
14
16
  /**
15
17
  * pre-merged credentials (CLI flags + env + saved file) when invoked from
16
18
  * build request's gate — the scan must validate the exact set the build
@@ -19,7 +21,7 @@ export interface PrescanCommandOptions {
19
21
  credentials?: Record<string, string>;
20
22
  }
21
23
  export declare function validateFlags(opts: Pick<PrescanCommandOptions, 'failOnWarnings' | 'ignoreFatal'>): void;
22
- export declare function exitCodeFor(counts: Record<Severity, number>, opts: OutcomeOptions): number;
24
+ export declare function exitCodeFor(counts: Record<Severity, number>, opts: OutcomeOptions, findings?: PrescanReport['findings']): number;
23
25
  export interface PrescanExecution {
24
26
  report: PrescanReport;
25
27
  /** apikey actually used for the scan (flag or saved key); undefined when remote checks were skipped */
@@ -35,6 +37,8 @@ export interface PrescanGateOptions {
35
37
  /** test seam; defaults to canPromptInteractively() (via resolveWarningGate) at call time */
36
38
  interactive?: boolean;
37
39
  silent?: boolean;
40
+ /** Test seam for hard-coded rollout deadlines; defaults to the current time. */
41
+ now?: Date;
38
42
  /**
39
43
  * Output sink for the report / crash notice. Callers that own the terminal
40
44
  * (Ink onboarding, SDK, MCP stdio) pass their BuildLogger here; raw clack
@@ -49,6 +53,7 @@ export interface PrescanGateResult {
49
53
  /** null when the gate was disabled or the scan crashed (no scan ran) */
50
54
  report: PrescanReport | null;
51
55
  crashed: boolean;
56
+ informationOnlyFindings: number;
52
57
  }
53
58
  /**
54
59
  * Used by build request. Runs the scan via the provided thunk, prints the report,
@@ -0,0 +1,7 @@
1
+ import type { Finding, PrescanReport, Severity } from './types';
2
+ type EnforcementReport = Pick<PrescanReport, 'counts' | 'findings'>;
3
+ export declare function isFindingEnforced(finding: Finding, now?: Date): boolean;
4
+ export declare function informationOnlyFindings(report: EnforcementReport, now?: Date): Finding[];
5
+ export declare function enforcedCounts(report: EnforcementReport, now?: Date): Record<Severity, number>;
6
+ export declare function formatEnforcementDeadline(iso: string): string;
7
+ export {};
@@ -3,5 +3,5 @@ interface EngineOptions {
3
3
  checkTimeoutMs?: number;
4
4
  }
5
5
  export declare function runPrescan(ctx: ScanContext, checks: PrescanCheck[], options?: EngineOptions): Promise<PrescanReport>;
6
- export declare function decideOutcome(report: Pick<PrescanReport, 'counts'>, options: OutcomeOptions): PrescanOutcome;
6
+ export declare function decideOutcome(report: Pick<PrescanReport, 'counts' | 'findings'>, options: OutcomeOptions): PrescanOutcome;
7
7
  export {};
@@ -0,0 +1,33 @@
1
+ export interface AppIconImage {
2
+ idiom?: string;
3
+ size?: string;
4
+ scale?: string;
5
+ filename?: string;
6
+ platform?: string;
7
+ role?: string;
8
+ }
9
+ export interface AssetContents {
10
+ images?: AppIconImage[];
11
+ info?: {
12
+ version?: number;
13
+ author?: string;
14
+ };
15
+ }
16
+ /**
17
+ * Parse an asset-catalog Contents.json. Returns null on a missing file OR a
18
+ * parse error — the asset catalog is the one place an invalid hand-edit can
19
+ * crash a naive reader, so this is the shared safety net for the appicon checks.
20
+ * Never throws.
21
+ */
22
+ export declare function readContentsJson(path: string): AssetContents | null;
23
+ /**
24
+ * Absolute path to the project's `<IconName>.appiconset` directory. The icon
25
+ * name comes from the pbxproj ASSETCATALOG_COMPILER_APPICON_NAME build setting
26
+ * (Release-preferred) and defaults to `AppIcon` for standard Capacitor layouts.
27
+ */
28
+ export declare function appIconSetDir(projectDir: string, pbxContent?: string): string;
29
+ /**
30
+ * Whether the icon set declares the App Store marketing icon: a `1024x1024`
31
+ * size (whitespace-trimmed) or an image whose `role` is `marketing`.
32
+ */
33
+ export declare function hasMarketingIcon(c: AssetContents | null): boolean;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Read the app target's CODE_SIGN_ENTITLEMENTS file, falling back to the
3
+ * Capacitor-convention path only when that build setting is absent.
4
+ */
5
+ export declare function readAppEntitlements(projectDir: string, appId?: string): {
6
+ raw: string;
7
+ } | null;
8
+ /** String entitlement value (e.g. aps-environment), or null when absent. */
9
+ export declare function entString(raw: string, key: string): string | null;
10
+ /** Array entitlement members (e.g. application-groups), or [] when absent. */
11
+ export declare function entArray(raw: string, key: string): string[];
12
+ /** Boolean entitlement (e.g. get-task-allow), or null when absent. */
13
+ export declare function entBool(raw: string, key: string): boolean | null;
@@ -0,0 +1,40 @@
1
+ import type { PbxTarget } from '../pbxproj-parser';
2
+ export interface BuildConfig {
3
+ name: string;
4
+ settings: Record<string, string>;
5
+ isProjectLevel: boolean;
6
+ }
7
+ export interface TargetConfigs {
8
+ target: PbxTarget;
9
+ configs: {
10
+ name: string;
11
+ settings: Record<string, string>;
12
+ }[];
13
+ }
14
+ /**
15
+ * Per-config build settings (Debug/Release/...) plus an isProjectLevel flag for
16
+ * the configs referenced by the PBXProject configuration list.
17
+ */
18
+ export declare function readBuildConfigs(pbxContent: string): BuildConfig[];
19
+ /**
20
+ * Release-preferred scalar lookup across every build config. Returns the value
21
+ * from a config named Release if one carries the key, else the first config
22
+ * that carries it (fallback), else null. SCALAR keys only.
23
+ */
24
+ export declare function readBuildSetting(pbxContent: string, name: string): string | null;
25
+ /**
26
+ * If rawValue is EXACTLY one `$(VAR)` or `${VAR}` reference, substitute it via
27
+ * readBuildSetting(VAR); otherwise return rawValue unchanged. When the variable
28
+ * has no pbxproj match the raw `$()` string is returned so callers can treat a
29
+ * still-unresolved reference as "skip / cannot judge". A value that merely
30
+ * contains a `$()` among other text is left untouched (not a clean reference).
31
+ */
32
+ export declare function resolvePlistValue(rawValue: string, pbxContent: string): string;
33
+ /**
34
+ * Per signable target, the full scalar settings dict of each of its configs.
35
+ * Reuses findSignableTargets for the target identity and re-walks the native
36
+ * target blocks to associate each target name with its configuration list.
37
+ */
38
+ export declare function readTargetConfigs(pbxContent: string): TargetConfigs[];
39
+ /** Lowest explicit iOS deployment target across linked project and application configs. */
40
+ export declare function readMinimumIosDeploymentTarget(pbxContent: string): number | null;
@@ -1,2 +1,4 @@
1
1
  import type { PrescanCheck } from './types';
2
+ /** New iOS expansion checks become build-blocking at this UTC instant. */
3
+ export declare const IOS_PRESCAN_EXPANSION_ENFORCE_AFTER = "2026-08-14T00:00:00.000Z";
2
4
  export declare const ALL_CHECKS: PrescanCheck[];
@@ -2,5 +2,6 @@ import type { PrescanReport } from './types';
2
2
  export declare function renderTerminalReport(report: PrescanReport, opts?: {
3
3
  verbose?: boolean;
4
4
  color?: boolean;
5
+ now?: Date;
5
6
  }): string;
6
7
  export declare function renderJsonReport(report: PrescanReport): string;
@@ -6,6 +6,8 @@ export type Platform = 'ios' | 'android';
6
6
  export interface Finding {
7
7
  id: string;
8
8
  severity: Severity;
9
+ /** Finding stays visible but is information-only until this UTC instant. */
10
+ enforceAfter?: string;
9
11
  /**
10
12
  * detail/fix/title are printed to the terminal and serialized into --json reports
11
13
  * (routinely captured in CI logs): they must NEVER contain credential material
@@ -31,6 +33,8 @@ export interface ScanContext {
31
33
  export interface PrescanCheck {
32
34
  id: string;
33
35
  platforms: Platform[];
36
+ /** Findings from this check stay information-only until this UTC instant. */
37
+ enforceAfter?: string;
34
38
  /** requires ctx.supabase; skipped (with notice) when absent */
35
39
  remote?: boolean;
36
40
  appliesTo?: (ctx: ScanContext) => boolean;
@@ -47,4 +51,6 @@ export type PrescanOutcome = 'proceed' | 'ask' | 'block';
47
51
  export interface OutcomeOptions {
48
52
  failOnWarnings?: boolean;
49
53
  ignoreFatal?: boolean;
54
+ /** Test seam for hard-coded rollout deadlines; defaults to the current time. */
55
+ now?: Date;
50
56
  }