@capgo/cli 7.120.0 → 7.121.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 (29) hide show
  1. package/dist/index.js +580 -566
  2. package/dist/package.json +15 -3
  3. package/dist/src/ai/analyze.d.ts +8 -0
  4. package/dist/src/ai/telemetry.d.ts +2 -2
  5. package/dist/src/build/onboarding/ai-fit.d.ts +91 -0
  6. package/dist/src/build/onboarding/android/types.d.ts +1 -1
  7. package/dist/src/build/onboarding/android/ui/app.d.ts +5 -1
  8. package/dist/src/build/onboarding/build-log.d.ts +10 -0
  9. package/dist/src/build/onboarding/min-terminal-size.d.ts +16 -0
  10. package/dist/src/build/onboarding/progress.d.ts +1 -0
  11. package/dist/src/build/onboarding/types.d.ts +18 -1
  12. package/dist/src/build/onboarding/ui/app.d.ts +5 -2
  13. package/dist/src/build/onboarding/ui/completed-steps-log.d.ts +9 -0
  14. package/dist/src/build/onboarding/ui/components.d.ts +58 -1
  15. package/dist/src/build/onboarding/ui/frame-fit.d.ts +10 -0
  16. package/dist/src/build/onboarding/ui/min-size-gate.d.ts +20 -0
  17. package/dist/src/build/onboarding/ui/platform-picker.d.ts +19 -0
  18. package/dist/src/build/onboarding/ui/shell.d.ts +23 -0
  19. package/dist/src/build/onboarding/ui/steps/android-ci.d.ts +45 -0
  20. package/dist/src/build/onboarding/ui/steps/android-keystore.d.ts +75 -0
  21. package/dist/src/build/onboarding/ui/steps/android-sa-gcp.d.ts +85 -0
  22. package/dist/src/build/onboarding/ui/steps/android-shared.d.ts +63 -0
  23. package/dist/src/build/onboarding/ui/steps/ios-ci.d.ts +44 -0
  24. package/dist/src/build/onboarding/ui/steps/ios-credentials.d.ts +66 -0
  25. package/dist/src/build/onboarding/ui/steps/ios-import.d.ts +47 -0
  26. package/dist/src/build/onboarding/ui/steps/ios-shared.d.ts +89 -0
  27. package/dist/src/schemas/build.d.ts +10 -0
  28. package/dist/src/sdk.js +258 -258
  29. package/package.json +15 -3
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capgo/cli",
3
3
  "type": "module",
4
- "version": "7.120.0",
4
+ "version": "7.121.0",
5
5
  "description": "A CLI to upload to capgo servers",
6
6
  "author": "Martin martin@capgo.app",
7
7
  "license": "Apache 2.0",
@@ -105,11 +105,22 @@
105
105
  "test:macos-signing": "bun test/test-macos-signing.mjs",
106
106
  "test:apple-api-import-helpers": "bun test/test-apple-api-import-helpers.mjs",
107
107
  "test:manifest-path-encoding": "bun test/test-manifest-path-encoding.mjs",
108
- "test": "bun run build && 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: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:mcp-analytics && 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-app-conflict && bun run test:init-guardrails && bun run test:prompt-preferences && bun run test:esm-sdk && bun run test:mcp && bun run test:version-detection && bun run test:platform-paths && bun run test:payload-split && bun run test:manifest-path-encoding && bun run test:macos-signing && bun run test:apple-api-import-helpers && bun run test:ai-log-capture && bun run test:ai-analyze-flow && bun run test:ai-render-markdown",
108
+ "test": "bun run build && 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: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:mcp-analytics && 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-app-conflict && bun run test:init-guardrails && bun run test:prompt-preferences && bun run test:esm-sdk && bun run test:mcp && bun run test:version-detection && bun run test:platform-paths && bun run test:payload-split && bun run test:manifest-path-encoding && bun run test:macos-signing && bun run test:apple-api-import-helpers && bun run test:ai-log-capture && bun run test:ai-analyze-flow && bun run test:ai-render-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",
109
109
  "test:build-platform-selection": "bun test/test-build-platform-selection.mjs",
110
110
  "test:ai-log-capture": "bun test/test-ai-log-capture.mjs",
111
111
  "test:ai-analyze-flow": "bun test/test-ai-analyze-flow.mjs",
112
- "test:ai-render-markdown": "bun test/test-ai-render-markdown.mjs"
112
+ "test:ai-render-markdown": "bun test/test-ai-render-markdown.mjs",
113
+ "test:ai-onboarding-mode": "bun test/test-ai-onboarding-mode.mjs",
114
+ "test:ai-fit": "bun test/test-ai-fit.mjs",
115
+ "test:platform-layout": "bun test/test-platform-layout.mjs",
116
+ "test:frame-fit": "bun test/run-frame-fit.mjs",
117
+ "test:onboarding-min-size": "bun test/test-onboarding-min-size.mjs",
118
+ "test:min-size-gate": "bun test/test-min-size-gate.mjs",
119
+ "test:shell-size-gate": "bun test/test-shell-size-gate.mjs",
120
+ "test:build-log-sanitize": "bun test/test-build-log-sanitize.mjs",
121
+ "test:build-output-viewport": "bun test/test-build-output-viewport.mjs",
122
+ "test:diff-viewer-viewport": "bun test/test-diff-viewer-viewport.mjs",
123
+ "test:build-complete-exit": "bun test/test-build-complete-exit.mjs"
113
124
  },
114
125
  "dependencies": {
115
126
  "@inkjs/ui": "^2.0.0",
@@ -142,6 +153,7 @@
142
153
  "@types/ws": "^8.18.1",
143
154
  "@typescript/native-preview": "7.0.0-dev.20260526.1",
144
155
  "@vercel/ncc": "^0.38.4",
156
+ "@xterm/headless": "^6.0.0",
145
157
  "adm-zip": "^0.5.17",
146
158
  "ci-info": "^4.4.0",
147
159
  "commander": "^14.0.3",
@@ -27,3 +27,11 @@ export type PostAnalyzeResult = {
27
27
  export declare function postAnalyzeRequest(input: PostAnalyzeInput): Promise<PostAnalyzeResult>;
28
28
  export declare const HARD_LOG_SIZE_LIMIT: number;
29
29
  export declare function isLogTooBig(jobId: string): Promise<boolean>;
30
+ export interface RunCapgoAiAnalysisInput {
31
+ apiHost: string;
32
+ apikey: string;
33
+ jobId: string;
34
+ appId: string;
35
+ }
36
+ export declare function runCapgoAiAnalysis(input: RunCapgoAiAnalysisInput): Promise<PostAnalyzeResult>;
37
+ export declare function releaseCapturedLogs(jobId: string): Promise<void>;
@@ -1,5 +1,5 @@
1
- export type AiAnalysisChoice = 'capgo_ai' | 'local_ai' | 'skip' | 'auto_upload';
2
- export type AiAnalysisTriggeredBy = 'menu' | 'ci_flag';
1
+ export type AiAnalysisChoice = 'capgo_ai' | 'local_ai' | 'skip' | 'auto_upload' | 'retry';
2
+ export type AiAnalysisTriggeredBy = 'menu' | 'ci_flag' | 'onboarding';
3
3
  export type AiAnalysisResult = 'success' | 'already_analyzed' | 'too_big' | 'error';
4
4
  export interface TrackAiAnalysisChoiceInput {
5
5
  apikey: string;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Fit estimation for the AI analysis result step in the onboarding TUI.
3
+ *
4
+ * The on-failure AI flow can return a multi-screen markdown diagnosis. If
5
+ * that text doesn't fit in the user's current terminal viewport we MUST
6
+ * route it through the scrollable `FullscreenAiViewer` — otherwise the
7
+ * earlier lines scroll out of view and the onboarding wizard ends up in
8
+ * an unreadable state.
9
+ *
10
+ * The estimator deliberately errs on the side of "doesn't fit": a
11
+ * false-positive scroll is fine (just one more keystroke for the user),
12
+ * but a false-negative inline render is bad UX (text disappears off the
13
+ * top of the screen).
14
+ */
15
+ export declare const AI_RESULT_CHROME_ROWS = 10;
16
+ /** Strip ANSI SGR escape codes so length matches what the user actually sees. */
17
+ export declare function stripAnsi(text: string): string;
18
+ /**
19
+ * Estimate how many terminal rows a multi-line, possibly ANSI-styled string
20
+ * will occupy when rendered by Ink at the given column width.
21
+ *
22
+ * Each logical line (split on '\n') becomes `ceil(visibleLen / cols)` rows,
23
+ * with a floor of 1 to account for empty lines that still consume a row.
24
+ */
25
+ export declare function estimateRenderedRows(text: string, terminalCols: number): number;
26
+ /**
27
+ * Decide whether the AI analysis text should be routed through the
28
+ * scrollable fullscreen viewer. Conservative — prefers true (scroll) when
29
+ * the estimate is close to the available row budget.
30
+ *
31
+ * @param text The AI analysis markdown (already rendered to ANSI).
32
+ * @param terminalRows Total terminal rows from `useStdout().stdout?.rows`.
33
+ * @param terminalCols Total terminal cols from `useStdout().stdout?.columns`.
34
+ * @param chromeRows Reserved rows for the surrounding wizard chrome.
35
+ * Defaults to `AI_RESULT_CHROME_ROWS`.
36
+ */
37
+ export declare function isAiAnalysisTooTall(text: string, terminalRows: number, terminalCols: number, chromeRows?: number): boolean;
38
+ export type AiResultStep = 'ai-analysis-result' | 'ai-analysis-result-scroll';
39
+ /**
40
+ * Decide which AI-result step should be active for the CURRENT terminal size.
41
+ *
42
+ * Routing is BIDIRECTIONAL and driven by the single `isAiAnalysisTooTall`
43
+ * predicate, so it settles deterministically at any size — at a given size
44
+ * exactly one outcome is stable, so it can't oscillate:
45
+ * - inline + now too tall (terminal shrank) → scroll
46
+ * - scroll + now fits (terminal grew) → inline ← the missing case
47
+ *
48
+ * Before, only the inline→scroll direction existed: once the viewer opened
49
+ * (e.g. after shrinking), growing the terminal never returned to the inline
50
+ * render — the user was stuck in the scroll viewer showing "all N lines" with
51
+ * empty space.
52
+ *
53
+ * `viewedFull` (the user manually dismissed the viewer with Esc/Enter) pins the
54
+ * inline step so a later resize can't shove a dismissed analysis back into the
55
+ * viewer. It only gates the inline→scroll direction; leaving the viewer when it
56
+ * fits is always allowed.
57
+ *
58
+ * @returns the step to switch to, or `null` when the current step is already
59
+ * correct (so the caller can skip a no-op `setStep`).
60
+ */
61
+ export declare function resolveAiResultRoute(params: {
62
+ current: AiResultStep;
63
+ text: string | null;
64
+ viewedFull: boolean;
65
+ terminalRows: number;
66
+ terminalCols: number;
67
+ }): AiResultStep | null;
68
+ /**
69
+ * Pick the slice of `lines` starting at `scrollOffset` that PACKS the
70
+ * `viewportRows` rendered rows of a terminal `terminalCols` wide.
71
+ *
72
+ * Packs lines until the cumulative wrapped row count reaches or exceeds
73
+ * `viewportRows`, INCLUDING the line that crosses the boundary. That last line
74
+ * may render past the viewport; the viewer clips it with `overflow: hidden` so
75
+ * the visible area is always FULL of text when more lines remain. (Stopping
76
+ * before the boundary line — the old behaviour — left the unused rows as an
77
+ * empty gap when a long line couldn't fully fit.)
78
+ *
79
+ * Always returns at least one line if the input is non-empty and the
80
+ * `scrollOffset` is in-range — even if that line wraps to more rows than the
81
+ * viewport.
82
+ */
83
+ export declare function pickVisibleLines(lines: string[], scrollOffset: number, viewportRows: number, terminalCols: number): string[];
84
+ /**
85
+ * Compute the largest `scrollOffset` that still keeps content visible at the
86
+ * bottom of the viewport — i.e. the offset where the LAST line is rendered
87
+ * within the viewport. Walks backwards from the end, packing as many tail
88
+ * lines as fit (accounting for wrap), and returns the offset of the first
89
+ * fully-visible tail line.
90
+ */
91
+ export declare function computeMaxScrollOffset(lines: string[], viewportRows: number, terminalCols: number): number;
@@ -1,4 +1,4 @@
1
- export type AndroidOnboardingStep = 'welcome' | 'credentials-exist' | 'backing-up' | 'no-platform' | 'keystore-method-select' | 'keystore-explainer' | 'keystore-existing-path' | 'keystore-existing-picker' | 'keystore-existing-store-password' | 'keystore-existing-detecting-alias' | 'keystore-existing-alias-select' | 'keystore-existing-alias' | 'keystore-existing-key-password' | 'keystore-new-alias' | 'keystore-new-password-method' | 'keystore-new-store-password' | 'keystore-new-key-password' | 'keystore-new-cn' | 'keystore-generating' | 'service-account-method-select' | 'sa-json-existing-path' | 'sa-json-existing-picker' | 'sa-json-validating' | 'sa-json-validation-failed' | 'google-sign-in' | 'google-sign-in-running' | 'play-developer-id-input' | 'gcp-projects-loading' | 'gcp-projects-select' | 'gcp-project-create-name' | 'android-package-select' | 'gcp-setup-running' | 'saving-credentials' | 'detecting-ci-secrets' | 'ci-secrets-setup' | 'ci-secrets-target-select' | 'ask-ci-secrets' | 'checking-ci-secrets' | 'confirm-ci-secret-overwrite' | 'uploading-ci-secrets' | 'ci-secrets-failed' | 'ask-github-actions-setup' | 'confirm-secrets-push' | 'ask-export-env' | 'exporting-env' | 'confirm-env-export-overwrite' | 'overwrite-and-export-env' | 'pick-package-manager' | 'pick-build-script' | 'pick-build-script-custom' | 'preview-workflow-file' | 'view-workflow-diff' | 'writing-workflow-file' | 'ask-build' | 'requesting-build' | 'build-complete' | 'error';
1
+ export type AndroidOnboardingStep = 'welcome' | 'credentials-exist' | 'backing-up' | 'no-platform' | 'keystore-method-select' | 'keystore-explainer' | 'keystore-existing-path' | 'keystore-existing-picker' | 'keystore-existing-store-password' | 'keystore-existing-detecting-alias' | 'keystore-existing-alias-select' | 'keystore-existing-alias' | 'keystore-existing-key-password' | 'keystore-new-alias' | 'keystore-new-password-method' | 'keystore-new-store-password' | 'keystore-new-key-password' | 'keystore-new-cn' | 'keystore-generating' | 'service-account-method-select' | 'sa-json-existing-path' | 'sa-json-existing-picker' | 'sa-json-validating' | 'sa-json-validation-failed' | 'google-sign-in' | 'google-sign-in-running' | 'play-developer-id-input' | 'gcp-projects-loading' | 'gcp-projects-select' | 'gcp-project-create-name' | 'android-package-select' | 'gcp-setup-running' | 'saving-credentials' | 'detecting-ci-secrets' | 'ci-secrets-setup' | 'ci-secrets-target-select' | 'ask-ci-secrets' | 'checking-ci-secrets' | 'confirm-ci-secret-overwrite' | 'uploading-ci-secrets' | 'ci-secrets-failed' | 'ask-github-actions-setup' | 'confirm-secrets-push' | 'ask-export-env' | 'exporting-env' | 'confirm-env-export-overwrite' | 'overwrite-and-export-env' | 'pick-package-manager' | 'pick-build-script' | 'pick-build-script-custom' | 'preview-workflow-file' | 'view-workflow-diff' | 'writing-workflow-file' | 'ask-build' | 'requesting-build' | 'ai-analysis-prompt' | 'ai-analysis-running' | 'ai-analysis-result' | 'ai-analysis-result-scroll' | 'build-complete' | 'error';
2
2
  export type AndroidOnboardingErrorCategory = 'keystore_invalid' | 'google_oauth_failed' | 'play_account_id_invalid' | 'sa_json_shape_invalid' | 'sa_json_token_rejected' | 'sa_json_no_app_access' | 'sa_json_network_error' | 'unknown';
3
3
  export type KeystoreMethod = 'existing' | 'generate';
4
4
  export type ServiceAccountMethod = 'existing' | 'generate';
@@ -1,12 +1,16 @@
1
1
  import type { FC } from 'react';
2
2
  import type { AndroidOnboardingProgress } from '../types.js';
3
+ import type { OnboardingResult } from '../../types.js';
3
4
  interface AppProps {
4
5
  appId: string;
5
6
  initialProgress: AndroidOnboardingProgress | null;
6
7
  androidDir: string;
7
8
  /** Optional Capgo API key passed via -a/--apikey flag; takes precedence over saved key. */
8
9
  apikey?: string;
9
- terminalRows?: number;
10
+ /** Reports the wizard outcome to the shell when it reaches build-complete, so
11
+ * the caller prints an accurate post-exit message + durable summary instead of
12
+ * always claiming success. Never fires on cancel/missing-platform exits. */
13
+ onResult?: (result: OnboardingResult) => void;
10
14
  }
11
15
  declare const AndroidOnboardingApp: FC<AppProps>;
12
16
  export default AndroidOnboardingApp;
@@ -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,16 @@
1
+ export declare const MIN_COLS = 80;
2
+ export declare const IOS_MIN_ROWS = 38;
3
+ export declare const ANDROID_MIN_ROWS = 49;
4
+ export declare const MIN_ROWS: number;
5
+ /** The full-onboarding row floor for a given platform. */
6
+ export declare function onboardingMinRows(platform: 'ios' | 'android'): number;
7
+ /**
8
+ * True when the given terminal size can run a platform's onboarding without a
9
+ * mid-flow resize. `platform` defaults to the conservative 'android' (larger)
10
+ * floor for platform-agnostic callers.
11
+ */
12
+ export declare function terminalFitsOnboarding(cols: number, rows: number, platform?: 'ios' | 'android'): boolean;
13
+ export declare const PICKER_MIN_COLS = 44;
14
+ export declare const PICKER_MIN_ROWS = 11;
15
+ /** True when the terminal can render the platform picker (banner + picker). */
16
+ export declare function terminalFitsPicker(cols: number, rows: number): boolean;
@@ -48,3 +48,4 @@ export declare function getResumeStep(progress: OnboardingProgress | null): Onbo
48
48
  * Returns the step to land on after a successful Keychain scan.
49
49
  */
50
50
  export declare function getImportEntryStep(progress: OnboardingProgress | null): OnboardingStep;
51
+ export declare function extractKeyIdFromP8Path(filePath: string): string;
@@ -1,5 +1,22 @@
1
1
  export type Platform = 'ios' | 'android';
2
- export type OnboardingStep = 'welcome' | 'platform-select' | 'adding-platform' | 'credentials-exist' | 'backing-up' | 'setup-method-select' | 'import-scanning' | 'import-distribution-mode' | 'import-pick-identity' | 'import-pick-profile' | 'import-no-match-recovery' | 'import-fetching-profile' | 'import-create-profile-only' | 'import-export-warning' | 'import-compiling-helper' | 'import-exporting' | 'api-key-instructions' | 'p8-method-select' | 'input-p8-path' | 'input-key-id' | 'input-issuer-id' | 'verifying-key' | 'creating-certificate' | 'cert-limit-prompt' | 'revoking-certificate' | 'creating-profile' | 'duplicate-profile-prompt' | 'deleting-duplicate-profiles' | 'saving-credentials' | 'detecting-ci-secrets' | 'ci-secrets-setup' | 'ci-secrets-target-select' | 'ask-ci-secrets' | 'checking-ci-secrets' | 'confirm-ci-secret-overwrite' | 'uploading-ci-secrets' | 'ci-secrets-failed' | 'ask-github-actions-setup' | 'confirm-secrets-push' | 'ask-export-env' | 'exporting-env' | 'confirm-env-export-overwrite' | 'overwrite-and-export-env' | 'pick-package-manager' | 'pick-build-script' | 'pick-build-script-custom' | 'preview-workflow-file' | 'view-workflow-diff' | 'writing-workflow-file' | 'ask-build' | 'requesting-build' | 'build-complete' | 'no-platform' | 'error';
2
+ export interface OnboardingCompletionSummary {
3
+ /** The Capgo dashboard build URL, when a build was kicked off. */
4
+ buildUrl?: string;
5
+ /** One-line CI-secret upload summary, when secrets were pushed. */
6
+ ciSecretUploadSummary?: string | null;
7
+ /** Path to the generated GitHub Actions workflow file, when written. */
8
+ workflowFilePath?: string | null;
9
+ /** Path to the exported .env file, when the user chose the env-export fallback. */
10
+ envExportPath?: string | null;
11
+ /** The "run anytime" build-request command shown on the final screen. */
12
+ buildRequestCommand?: string;
13
+ }
14
+ export interface OnboardingResult {
15
+ outcome: 'completed' | 'cancelled';
16
+ /** Present only when outcome === 'completed'. */
17
+ summary?: OnboardingCompletionSummary;
18
+ }
19
+ export type OnboardingStep = 'welcome' | 'platform-select' | 'adding-platform' | 'credentials-exist' | 'backing-up' | 'setup-method-select' | 'import-scanning' | 'import-distribution-mode' | 'import-pick-identity' | 'import-pick-profile' | 'import-no-match-recovery' | 'import-fetching-profile' | 'import-create-profile-only' | 'import-export-warning' | 'import-compiling-helper' | 'import-exporting' | 'api-key-instructions' | 'p8-method-select' | 'input-p8-path' | 'input-key-id' | 'input-issuer-id' | 'verifying-key' | 'creating-certificate' | 'cert-limit-prompt' | 'revoking-certificate' | 'creating-profile' | 'duplicate-profile-prompt' | 'deleting-duplicate-profiles' | 'saving-credentials' | 'detecting-ci-secrets' | 'ci-secrets-setup' | 'ci-secrets-target-select' | 'ask-ci-secrets' | 'checking-ci-secrets' | 'confirm-ci-secret-overwrite' | 'uploading-ci-secrets' | 'ci-secrets-failed' | 'ask-github-actions-setup' | 'confirm-secrets-push' | 'ask-export-env' | 'exporting-env' | 'confirm-env-export-overwrite' | 'overwrite-and-export-env' | 'pick-package-manager' | 'pick-build-script' | 'pick-build-script-custom' | 'preview-workflow-file' | 'view-workflow-diff' | 'writing-workflow-file' | 'ask-build' | 'requesting-build' | 'ai-analysis-prompt' | 'ai-analysis-running' | 'ai-analysis-result' | 'ai-analysis-result-scroll' | 'build-complete' | 'no-platform' | 'error';
3
20
  export type OnboardingErrorCategory = 'apple_api_unauthorized' | 'apple_api_rate_limited' | 'cert_limit_reached' | 'profile_creation_failed' | 'p8_invalid' | 'keychain_no_identities' | 'keychain_export_failed' | 'keychain_helper_compile_failed' | 'profile_no_match' | 'profile_read_failed' | 'unknown';
4
21
  export interface ApiKeyData {
5
22
  keyId: string;
@@ -1,5 +1,5 @@
1
1
  import type { FC } from 'react';
2
- import type { OnboardingProgress } from '../types.js';
2
+ import type { OnboardingProgress, OnboardingResult } from '../types.js';
3
3
  interface AppProps {
4
4
  appId: string;
5
5
  initialProgress: OnboardingProgress | null;
@@ -7,7 +7,10 @@ interface AppProps {
7
7
  iosDir: string;
8
8
  /** Optional Capgo API key passed via -a/--apikey flag; takes precedence over saved key */
9
9
  apikey?: string;
10
- terminalRows?: number;
10
+ /** Reports the wizard outcome to the shell when it reaches build-complete, so
11
+ * the caller prints an accurate post-exit message + durable summary instead of
12
+ * always claiming success. Never fires on cancel/missing-platform exits. */
13
+ onResult?: (result: OnboardingResult) => void;
11
14
  }
12
15
  declare const OnboardingApp: FC<AppProps>;
13
16
  export default OnboardingApp;
@@ -0,0 +1,9 @@
1
+ import type { FC } from 'react';
2
+ export interface LogEntry {
3
+ text: string;
4
+ color?: string;
5
+ }
6
+ export declare const CompletedStepsLog: FC<{
7
+ entries: LogEntry[];
8
+ maxRows: number;
9
+ }>;
@@ -3,6 +3,9 @@ import type { DiffLine } from '../diff-utils.js';
3
3
  export declare const Divider: FC<{
4
4
  width?: number;
5
5
  }>;
6
+ export declare const BOX_HEADER_ROWS = 5;
7
+ export declare const COMPACT_HEADER_ROWS = 1;
8
+ export declare const WIZARD_PADDING_ROWS = 2;
6
9
  export declare const SpinnerLine: FC<{
7
10
  text: string;
8
11
  }>;
@@ -13,6 +16,12 @@ export declare const SuccessLine: FC<{
13
16
  export declare const ErrorLine: FC<{
14
17
  text: string;
15
18
  }>;
19
+ export type AiResultKind = 'already_analyzed' | 'too_big' | 'error';
20
+ export declare const AiResultBanner: FC<{
21
+ kind: AiResultKind;
22
+ message: string;
23
+ dense?: boolean;
24
+ }>;
16
25
  /**
17
26
  * Custom TextInput that filters out specific characters (e.g. '=').
18
27
  * @inkjs/ui's TextInput is uncontrolled and can't filter keystrokes,
@@ -24,7 +33,55 @@ export declare const FilteredTextInput: FC<{
24
33
  mask?: boolean;
25
34
  onSubmit: (value: string) => void;
26
35
  }>;
27
- export declare const Header: FC;
36
+ export declare const Header: FC<{
37
+ compact?: boolean;
38
+ }>;
39
+ /**
40
+ * Scrollable, fullscreen viewer for the AI build-analysis markdown when it
41
+ * is taller than the user's terminal viewport. Mirrors the shape of the
42
+ * workflow-file diff viewer on main, but for pre-rendered ANSI lines (no
43
+ * `add`/`del` colouring — the markdown renderer already styled them).
44
+ *
45
+ * Keybindings:
46
+ * ↑/k scroll one line up
47
+ * ↓/j scroll one line down
48
+ * PgUp/u jump up one viewport
49
+ * PgDn/d/␣ jump down one viewport
50
+ * Home/g jump to top
51
+ * End/G jump to bottom
52
+ * Esc/Enter dismiss the viewer (returns control to the parent step)
53
+ */
54
+ export declare const FullscreenAiViewer: FC<{
55
+ title: string;
56
+ subtitle?: string;
57
+ lines: string[];
58
+ terminalRows: number;
59
+ onExit: () => void;
60
+ }>;
61
+ export declare function isBuildCompleteDismissKey(input: string, key: {
62
+ return?: boolean;
63
+ escape?: boolean;
64
+ }): boolean;
65
+ export interface BuildScrollState {
66
+ scrollOffset: number;
67
+ follow: boolean;
68
+ }
69
+ export declare function buildScrollAction(input: string, key: {
70
+ upArrow?: boolean;
71
+ downArrow?: boolean;
72
+ pageUp?: boolean;
73
+ pageDown?: boolean;
74
+ }, state: {
75
+ scrollOffset: number;
76
+ maxScrollOffset: number;
77
+ viewportRows: number;
78
+ }): BuildScrollState | null;
79
+ export declare function formatElapsed(ms: number): string;
80
+ export declare const FullscreenBuildOutput: FC<{
81
+ title: string;
82
+ lines: string[];
83
+ terminalRows: number;
84
+ }>;
28
85
  /**
29
86
  * Minimal bordered table component for the confirm-secrets-push step.
30
87
  *
@@ -0,0 +1,10 @@
1
+ export type PlatformPickerLayout = 'cards' | 'list';
2
+ export declare const PLATFORM_CARDS_MIN_COLS = 44;
3
+ export declare const PLATFORM_CARDS_MIN_ROWS = 16;
4
+ export declare function pickPlatformLayout(cols: number, rows: number): PlatformPickerLayout;
5
+ export declare function logBudgetRows(terminalRows: number, headerRows: number, bodyHeight: number): number;
6
+ export interface CappedLog<T> {
7
+ hidden: number;
8
+ visible: T[];
9
+ }
10
+ export declare function capLogRows<T>(entries: T[], maxRows: number): CappedLog<T>;
@@ -0,0 +1,20 @@
1
+ import type { FC, ReactNode } from 'react';
2
+ export interface TerminalTooSmallPromptProps {
3
+ cols: number;
4
+ rows: number;
5
+ /** Minimum columns this screen needs. Defaults to the full onboarding floor;
6
+ * the platform picker passes its smaller PICKER_MIN_COLS. */
7
+ minCols?: number;
8
+ /** Minimum rows this screen needs. Defaults to the full onboarding floor; the
9
+ * platform picker passes its smaller PICKER_MIN_ROWS. So the prompt always
10
+ * states the floor of the screen that's actually too small (e.g. "11 rows" on
11
+ * the picker, not the wizard's 49). */
12
+ minRows?: number;
13
+ }
14
+ export declare const TerminalTooSmallPrompt: FC<TerminalTooSmallPromptProps>;
15
+ export interface MinSizeGateProps {
16
+ cols: number;
17
+ rows: number;
18
+ children: ReactNode;
19
+ }
20
+ export declare const MinSizeGate: FC<MinSizeGateProps>;
@@ -0,0 +1,19 @@
1
+ import type { FC } from 'react';
2
+ import type { Platform } from '../types.js';
3
+ import type { PlatformPickerLayout } from './frame-fit.js';
4
+ export type PlatformKeyAction = {
5
+ type: 'select';
6
+ platform: Platform;
7
+ } | {
8
+ type: 'confirm';
9
+ } | null;
10
+ export declare function platformKeyAction(input: string, key: {
11
+ leftArrow?: boolean;
12
+ rightArrow?: boolean;
13
+ return?: boolean;
14
+ }): PlatformKeyAction;
15
+ export interface PlatformPickerProps {
16
+ layout: PlatformPickerLayout;
17
+ onSelect: (platform: Platform) => void;
18
+ }
19
+ export declare const PlatformPicker: FC<PlatformPickerProps>;
@@ -0,0 +1,23 @@
1
+ import type { FC } from 'react';
2
+ import type { OnboardingResult, Platform } from '../types.js';
3
+ export declare function useTerminalSize(): {
4
+ cols: number;
5
+ rows: number;
6
+ };
7
+ export interface OnboardingShellProps {
8
+ appId: string;
9
+ iosDir: string;
10
+ androidDir: string;
11
+ apikey?: string;
12
+ /** Pre-resolved platform (--platform flag or the single existing native dir); skips the picker. */
13
+ initialPlatform?: Platform;
14
+ /** Called once a platform is chosen so the caller can print the completion breadcrumb. */
15
+ onResolvePlatform?: (platform: Platform) => void;
16
+ /** Called by the mounted app when it reaches the build-complete screen, so the
17
+ * caller prints the accurate post-exit message + durable summary. If the wizard
18
+ * exits any other way (cancel / missing platform), this never fires and the
19
+ * caller treats it as cancelled. */
20
+ onResult?: (result: OnboardingResult) => void;
21
+ }
22
+ declare const OnboardingShell: FC<OnboardingShellProps>;
23
+ export default OnboardingShell;
@@ -0,0 +1,45 @@
1
+ import type { FC } from 'react';
2
+ import type { CiSecretSetupAdvice } from '../../ci-secrets.js';
3
+ export interface SelectOption {
4
+ label: string;
5
+ value: string;
6
+ }
7
+ export declare const SavingCredentialsStep: FC;
8
+ export declare const DetectingCiSecretsStep: FC;
9
+ export interface CiSecretsSetupStepProps {
10
+ advice: CiSecretSetupAdvice[];
11
+ onChoose: (choice: 'retry' | 'skip') => void;
12
+ dense?: boolean;
13
+ }
14
+ export declare const CiSecretsSetupStep: FC<CiSecretsSetupStepProps>;
15
+ export interface CiSecretsTargetSelectStepProps {
16
+ options: SelectOption[];
17
+ onChange: (value: string) => void;
18
+ dense?: boolean;
19
+ }
20
+ export declare const CiSecretsTargetSelectStep: FC<CiSecretsTargetSelectStepProps>;
21
+ export interface AskCiSecretsStepProps {
22
+ entryCount: number;
23
+ targetLabel: string;
24
+ cli: string;
25
+ onChoose: (choice: 'yes' | 'no') => void;
26
+ dense?: boolean;
27
+ }
28
+ export declare const AskCiSecretsStep: FC<AskCiSecretsStepProps>;
29
+ export interface ConfirmCiSecretOverwriteStepProps {
30
+ existingKeys: string[];
31
+ onChoose: (choice: 'replace' | 'skip') => void;
32
+ dense?: boolean;
33
+ }
34
+ export declare const ConfirmCiSecretOverwriteStep: FC<ConfirmCiSecretOverwriteStepProps>;
35
+ export interface CiSecretsFailedStepProps {
36
+ error: string | null;
37
+ onChoose: (choice: 'retry' | 'continue') => void;
38
+ dense?: boolean;
39
+ }
40
+ export declare const CiSecretsFailedStep: FC<CiSecretsFailedStepProps>;
41
+ export interface AskBuildStepProps {
42
+ onChoose: (choice: 'yes' | 'no') => void;
43
+ dense?: boolean;
44
+ }
45
+ export declare const AskBuildStep: FC<AskBuildStepProps>;
@@ -0,0 +1,75 @@
1
+ import type { FC } from 'react';
2
+ export type KeystoreMethodChoice = 'existing' | 'generate' | 'learn';
3
+ export interface KeystoreMethodSelectStepProps {
4
+ onChoose: (choice: KeystoreMethodChoice) => void;
5
+ dense?: boolean;
6
+ }
7
+ export declare const KeystoreMethodSelectStep: FC<KeystoreMethodSelectStepProps>;
8
+ export interface KeystoreExplainerStepProps {
9
+ onBack: () => void;
10
+ dense?: boolean;
11
+ }
12
+ export declare const KeystoreExplainerStep: FC<KeystoreExplainerStepProps>;
13
+ export interface KeystoreExistingPathStepProps {
14
+ /** When true, render the picker-vs-manual chooser; else the path text input. */
15
+ showChooser: boolean;
16
+ onChoosePicker: () => void;
17
+ onChooseManual: () => void;
18
+ onSubmitPath: (value: string) => void;
19
+ dense?: boolean;
20
+ }
21
+ export declare const KeystoreExistingPathStep: FC<KeystoreExistingPathStepProps>;
22
+ export declare const KeystoreExistingPickerStep: FC;
23
+ export interface KeystoreExistingStorePasswordStepProps {
24
+ onSubmit: (value: string) => void;
25
+ dense?: boolean;
26
+ }
27
+ export declare const KeystoreExistingStorePasswordStep: FC<KeystoreExistingStorePasswordStepProps>;
28
+ export declare const KeystoreExistingDetectingAliasStep: FC;
29
+ export interface KeystoreExistingAliasSelectStepProps {
30
+ aliases: string[];
31
+ onSelect: (alias: string) => void;
32
+ dense?: boolean;
33
+ }
34
+ export declare const KeystoreExistingAliasSelectStep: FC<KeystoreExistingAliasSelectStepProps>;
35
+ export interface KeystoreExistingAliasStepProps {
36
+ onSubmit: (value: string) => void;
37
+ dense?: boolean;
38
+ }
39
+ export declare const KeystoreExistingAliasStep: FC<KeystoreExistingAliasStepProps>;
40
+ export interface KeystoreExistingKeyPasswordStepProps {
41
+ /** `probing` shows a spinner while we auto-detect; `prompt` asks the user. */
42
+ mode: 'probing' | 'prompt';
43
+ onSubmit: (value: string) => void;
44
+ dense?: boolean;
45
+ }
46
+ export declare const KeystoreExistingKeyPasswordStep: FC<KeystoreExistingKeyPasswordStepProps>;
47
+ export interface KeystoreNewAliasStepProps {
48
+ onSubmit: (value: string) => void;
49
+ dense?: boolean;
50
+ }
51
+ export declare const KeystoreNewAliasStep: FC<KeystoreNewAliasStepProps>;
52
+ export type KeystorePasswordMethodChoice = 'random' | 'manual';
53
+ export interface KeystoreNewPasswordMethodStepProps {
54
+ onChoose: (choice: KeystorePasswordMethodChoice) => void;
55
+ dense?: boolean;
56
+ }
57
+ export declare const KeystoreNewPasswordMethodStep: FC<KeystoreNewPasswordMethodStepProps>;
58
+ export interface KeystoreNewStorePasswordStepProps {
59
+ onSubmit: (value: string) => void;
60
+ dense?: boolean;
61
+ }
62
+ export declare const KeystoreNewStorePasswordStep: FC<KeystoreNewStorePasswordStepProps>;
63
+ export interface KeystoreNewKeyPasswordStepProps {
64
+ onSubmit: (value: string) => void;
65
+ dense?: boolean;
66
+ }
67
+ export declare const KeystoreNewKeyPasswordStep: FC<KeystoreNewKeyPasswordStepProps>;
68
+ export interface KeystoreNewCommonNameStepProps {
69
+ /** Placeholder shown for the default (the app id). */
70
+ appId: string;
71
+ onSubmit: (value: string) => void;
72
+ dense?: boolean;
73
+ }
74
+ export declare const KeystoreNewCommonNameStep: FC<KeystoreNewCommonNameStepProps>;
75
+ export declare const KeystoreGeneratingStep: FC;