@capgo/cli 7.110.0 → 7.111.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.
- package/dist/index.js +469 -463
- package/dist/package.json +4 -2
- package/dist/src/build/env-render.d.ts +8 -0
- package/dist/src/build/onboarding/analytics.d.ts +23 -0
- package/dist/src/build/onboarding/android/progress.d.ts +1 -0
- package/dist/src/build/onboarding/android/types.d.ts +2 -1
- package/dist/src/build/onboarding/android/ui/app.d.ts +1 -0
- package/dist/src/build/onboarding/ci-secrets.d.ts +48 -1
- package/dist/src/build/onboarding/diff-utils.d.ts +24 -0
- package/dist/src/build/onboarding/env-export.d.ts +46 -0
- package/dist/src/build/onboarding/telemetry.d.ts +11 -0
- package/dist/src/build/onboarding/types.d.ts +1 -1
- package/dist/src/build/onboarding/ui/app.d.ts +1 -0
- package/dist/src/build/onboarding/ui/components.d.ts +33 -0
- package/dist/src/build/onboarding/workflow-generator.d.ts +48 -0
- package/dist/src/build/onboarding/workflow-ui-helpers.d.ts +18 -0
- package/dist/src/build/onboarding/workflow-writer.d.ts +36 -0
- package/dist/src/sdk.js +1 -1
- package/package.json +4 -2
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.111.0",
|
|
5
5
|
"description": "A CLI to upload to capgo servers",
|
|
6
6
|
"author": "Martin martin@capgo.app",
|
|
7
7
|
"license": "Apache 2.0",
|
|
@@ -77,6 +77,8 @@
|
|
|
77
77
|
"test:build-needed": "bun test/test-build-needed.mjs",
|
|
78
78
|
"test:ci-prompts": "bun test/test-ci-prompts.mjs",
|
|
79
79
|
"test:ci-secrets": "bun test/test-ci-secrets.mjs",
|
|
80
|
+
"test:android-onboarding-progress": "bun test/test-android-onboarding-progress.mjs",
|
|
81
|
+
"test:onboarding-telemetry": "bun test/test-onboarding-telemetry.mjs",
|
|
80
82
|
"test:posthog-exception": "bun test/test-posthog-exception.mjs",
|
|
81
83
|
"test:onboarding-recovery": "bun test/test-onboarding-recovery.mjs",
|
|
82
84
|
"test:onboarding-progress": "bun test/test-onboarding-progress.mjs",
|
|
@@ -94,7 +96,7 @@
|
|
|
94
96
|
"test:macos-signing": "bun test/test-macos-signing.mjs",
|
|
95
97
|
"test:apple-api-import-helpers": "bun test/test-apple-api-import-helpers.mjs",
|
|
96
98
|
"test:manifest-path-encoding": "bun test/test-manifest-path-encoding.mjs",
|
|
97
|
-
"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: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",
|
|
99
|
+
"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: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",
|
|
98
100
|
"test:build-platform-selection": "bun test/test-build-platform-selection.mjs",
|
|
99
101
|
"test:ai-log-capture": "bun test/test-ai-log-capture.mjs",
|
|
100
102
|
"test:ai-analyze-flow": "bun test/test-ai-analyze-flow.mjs",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BuildCredentials } from '../schemas/build';
|
|
2
|
+
export declare function renderEnvFile(args: {
|
|
3
|
+
appId: string;
|
|
4
|
+
local: boolean;
|
|
5
|
+
platform: 'ios' | 'android';
|
|
6
|
+
creds: Partial<BuildCredentials>;
|
|
7
|
+
}): string;
|
|
8
|
+
export declare function escapeDotenvValue(value: string): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DiffLine } from './diff-utils.js';
|
|
2
|
+
import type { BuildScriptChoice, PackageManager } from './workflow-generator.js';
|
|
3
|
+
export type BuildOnboardingWorkflowEvent = 'workflow-preview-prepared' | 'workflow-preview-action' | 'workflow-diff-opened' | 'workflow-diff-closed' | 'workflow-file-written';
|
|
4
|
+
export type BuildOnboardingWorkflowDecision = 'write' | 'view' | 'cancel' | 'escape' | 'close';
|
|
5
|
+
export type BuildOnboardingWorkflowState = 'new' | 'replace' | 'identical';
|
|
6
|
+
export interface WorkflowDiffTelemetry {
|
|
7
|
+
workflowState: BuildOnboardingWorkflowState;
|
|
8
|
+
diffLines: number;
|
|
9
|
+
diffAdded: number;
|
|
10
|
+
diffRemoved: number;
|
|
11
|
+
}
|
|
12
|
+
interface TrackBuildOnboardingWorkflowOptions extends WorkflowDiffTelemetry {
|
|
13
|
+
event: BuildOnboardingWorkflowEvent;
|
|
14
|
+
appId: string;
|
|
15
|
+
platform: 'ios' | 'android';
|
|
16
|
+
apikey?: string;
|
|
17
|
+
decision?: BuildOnboardingWorkflowDecision;
|
|
18
|
+
packageManager?: PackageManager;
|
|
19
|
+
buildScriptType?: BuildScriptChoice['type'];
|
|
20
|
+
}
|
|
21
|
+
export declare function getWorkflowDiffTelemetry(lines: DiffLine[], isNew: boolean): WorkflowDiffTelemetry;
|
|
22
|
+
export declare function trackBuildOnboardingWorkflowEvent(options: TrackBuildOnboardingWorkflowOptions): void;
|
|
23
|
+
export {};
|
|
@@ -2,6 +2,7 @@ import type { AndroidOnboardingProgress, AndroidOnboardingStep } from './types.j
|
|
|
2
2
|
export declare function loadAndroidProgress(appId: string, baseDir?: string): Promise<AndroidOnboardingProgress | null>;
|
|
3
3
|
export declare function saveAndroidProgress(appId: string, progress: AndroidOnboardingProgress, baseDir?: string): Promise<void>;
|
|
4
4
|
export declare function deleteAndroidProgress(appId: string, baseDir?: string): Promise<void>;
|
|
5
|
+
export declare function hasAnyOAuthProgress(progress: AndroidOnboardingProgress): boolean;
|
|
5
6
|
/**
|
|
6
7
|
* Determine the first incomplete step for the Android flow.
|
|
7
8
|
*
|
|
@@ -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-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' | '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';
|
|
@@ -48,6 +48,7 @@ export interface AndroidOnboardingProgress {
|
|
|
48
48
|
keystoreStorePassword?: string;
|
|
49
49
|
keystoreKeyPassword?: string;
|
|
50
50
|
keystoreCommonName?: string;
|
|
51
|
+
serviceAccountForkSeen?: true;
|
|
51
52
|
serviceAccountMethod?: ServiceAccountMethod;
|
|
52
53
|
serviceAccountJsonPath?: string;
|
|
53
54
|
serviceAccountValidationSkipped?: boolean;
|
|
@@ -6,6 +6,7 @@ interface AppProps {
|
|
|
6
6
|
androidDir: string;
|
|
7
7
|
/** Optional Capgo API key passed via -a/--apikey flag; takes precedence over saved key. */
|
|
8
8
|
apikey?: string;
|
|
9
|
+
terminalRows?: number;
|
|
9
10
|
}
|
|
10
11
|
declare const AndroidOnboardingApp: FC<AppProps>;
|
|
11
12
|
export default AndroidOnboardingApp;
|
|
@@ -31,10 +31,57 @@ export interface CommandRunResult {
|
|
|
31
31
|
error?: Error;
|
|
32
32
|
}
|
|
33
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>;
|
|
34
44
|
export declare function runCommand(command: string, args: string[], options?: CommandRunOptions): CommandRunResult;
|
|
35
|
-
|
|
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[];
|
|
36
53
|
export declare function detectCiSecretTargets(runner?: CommandRunner): CiSecretDiscovery;
|
|
37
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>;
|
|
38
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[]>;
|
|
39
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>;
|
|
40
87
|
export {};
|
|
@@ -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;
|
|
@@ -12,4 +12,15 @@ export interface TrackBuilderOnboardingStepInput {
|
|
|
12
12
|
/** Pre-computed category. Takes precedence over `error` if both are present. */
|
|
13
13
|
errorCategory?: OnboardingErrorCategory | AndroidOnboardingErrorCategory;
|
|
14
14
|
}
|
|
15
|
+
export type BuilderOnboardingAction = 'android_sa_method_selected' | 'android_sa_validation_recovery_selected' | 'android_sa_validation_result';
|
|
16
|
+
export interface TrackBuilderOnboardingActionInput {
|
|
17
|
+
apikey: string;
|
|
18
|
+
appId: string;
|
|
19
|
+
orgId: string;
|
|
20
|
+
platform: Platform;
|
|
21
|
+
step: OnboardingStep | AndroidOnboardingStep;
|
|
22
|
+
action: BuilderOnboardingAction;
|
|
23
|
+
tags?: Record<string, boolean | number | string>;
|
|
24
|
+
}
|
|
15
25
|
export declare function trackBuilderOnboardingStep(input: TrackBuilderOnboardingStepInput): Promise<void>;
|
|
26
|
+
export declare function trackBuilderOnboardingAction(input: TrackBuilderOnboardingActionInput): Promise<void>;
|
|
@@ -1,5 +1,5 @@
|
|
|
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-build' | 'requesting-build' | 'build-complete' | 'no-platform' | 'error';
|
|
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';
|
|
3
3
|
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
4
|
export interface ApiKeyData {
|
|
5
5
|
keyId: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FC } from 'react';
|
|
2
|
+
import type { DiffLine } from '../diff-utils.js';
|
|
2
3
|
export declare const Divider: FC<{
|
|
3
4
|
width?: number;
|
|
4
5
|
}>;
|
|
@@ -24,3 +25,35 @@ export declare const FilteredTextInput: FC<{
|
|
|
24
25
|
onSubmit: (value: string) => void;
|
|
25
26
|
}>;
|
|
26
27
|
export declare const Header: FC;
|
|
28
|
+
/**
|
|
29
|
+
* Minimal bordered table component for the confirm-secrets-push step.
|
|
30
|
+
*
|
|
31
|
+
* Rolled in-house instead of pulling `ink-table` because that package is
|
|
32
|
+
* CommonJS-only and Ink 5 uses top-level await — bun can't bundle the combo.
|
|
33
|
+
* Replicates the visual style (box-drawing borders, aligned columns) with
|
|
34
|
+
* ~50 lines of Ink primitives, lets us color the Status column per-row, and
|
|
35
|
+
* leaves nothing to maintain outside this repo.
|
|
36
|
+
*/
|
|
37
|
+
export interface SecretRow {
|
|
38
|
+
name: string;
|
|
39
|
+
status: 'NEW' | 'REPLACE';
|
|
40
|
+
}
|
|
41
|
+
export declare const DiffSummary: FC<{
|
|
42
|
+
title: string;
|
|
43
|
+
subtitle?: string;
|
|
44
|
+
lines: DiffLine[];
|
|
45
|
+
}>;
|
|
46
|
+
export declare const FullscreenDiffViewer: FC<{
|
|
47
|
+
title: string;
|
|
48
|
+
subtitle?: string;
|
|
49
|
+
lines: DiffLine[];
|
|
50
|
+
terminalRows: number;
|
|
51
|
+
onExit: () => void;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Render the secrets table inline. Keep this dynamic so the onboarding header
|
|
55
|
+
* and prompt stay in one live Ink frame.
|
|
56
|
+
*/
|
|
57
|
+
export declare const SecretsTable: FC<{
|
|
58
|
+
rows: SecretRow[];
|
|
59
|
+
}>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure generator for a GitHub Actions workflow file that runs `capgo build
|
|
3
|
+
* request` against credentials uploaded as repository secrets.
|
|
4
|
+
*
|
|
5
|
+
* No I/O — caller decides where to write the resulting file. This keeps the
|
|
6
|
+
* generator trivially testable: feed it opts, get a `{ path, content }` back.
|
|
7
|
+
*
|
|
8
|
+
* v1 deliberately limited: GitHub-only (no GitLab YAML), single `workflow_dispatch`
|
|
9
|
+
* trigger (no push/pr triggers), one platform per dispatch (no matrix), no
|
|
10
|
+
* monorepo subdirectory handling. Each of these is a follow-up.
|
|
11
|
+
*/
|
|
12
|
+
export type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn';
|
|
13
|
+
export type BuildScriptChoice = {
|
|
14
|
+
type: 'npm-script';
|
|
15
|
+
name: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: 'custom';
|
|
18
|
+
command: string;
|
|
19
|
+
} | {
|
|
20
|
+
type: 'skip';
|
|
21
|
+
};
|
|
22
|
+
export interface WorkflowGeneratorOpts {
|
|
23
|
+
/** The app's bundle ID, e.g. com.example.app */
|
|
24
|
+
appId: string;
|
|
25
|
+
/** Default platform when the user dispatches the workflow without overriding the input. */
|
|
26
|
+
defaultPlatform: 'ios' | 'android';
|
|
27
|
+
/** Detected via getPMAndCommand(). Drives setup actions and the `npx`/`bunx`/etc runner. */
|
|
28
|
+
packageManager: PackageManager;
|
|
29
|
+
/** What runs to produce the web bundle before `capgo build request` fires. */
|
|
30
|
+
buildScript: BuildScriptChoice;
|
|
31
|
+
/** Exact secret names that were pushed to GitHub (drives the env: block). */
|
|
32
|
+
secretKeys: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface GeneratedWorkflow {
|
|
35
|
+
/** Relative path inside the repo where the file should live. */
|
|
36
|
+
path: string;
|
|
37
|
+
/** Full file content, ready to write. */
|
|
38
|
+
content: string;
|
|
39
|
+
}
|
|
40
|
+
/** Default path inside the repo. */
|
|
41
|
+
export declare const WORKFLOW_PATH = ".github/workflows/capgo-build.yml";
|
|
42
|
+
/**
|
|
43
|
+
* Build the GitHub Actions workflow YAML.
|
|
44
|
+
*
|
|
45
|
+
* The shape is intentionally simple: one job, one platform per dispatch,
|
|
46
|
+
* `workflow_dispatch` trigger only. Power users can fork it after the fact.
|
|
47
|
+
*/
|
|
48
|
+
export declare function generateWorkflow(opts: WorkflowGeneratorOpts): GeneratedWorkflow;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PackageManager } from './workflow-generator.js';
|
|
2
|
+
export interface BuildScriptOption {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* `getPMAndCommand()` returns the literal string 'unknown' when no recognizable
|
|
8
|
+
* lockfile is present. The workflow generator only knows the four real ones —
|
|
9
|
+
* fall back to 'npm' for the generator template.
|
|
10
|
+
*/
|
|
11
|
+
export declare function normalizePackageManager(pm: string): PackageManager;
|
|
12
|
+
/**
|
|
13
|
+
* Build the picker options for `pick-build-script`. Shows ALL scripts from
|
|
14
|
+
* package.json (the user picks; we don't auto-guess), with the project-type
|
|
15
|
+
* recommendation surfaced at the top, plus escape hatches for custom commands
|
|
16
|
+
* and "skip build entirely" (raw HTML Capacitor apps).
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildScriptPickerOptions(scripts: Record<string, string>, recommended: string | null): BuildScriptOption[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper that turns the pure `generateWorkflow` output into actual files
|
|
3
|
+
* on disk. Kept separate from `workflow-generator.ts` so the generator stays
|
|
4
|
+
* trivially unit-testable without mocking fs.
|
|
5
|
+
*
|
|
6
|
+
* The wizard's Ink layer owns all prompts (overwrite confirmation, etc.); this
|
|
7
|
+
* module only handles "does it exist?" and "write it".
|
|
8
|
+
*/
|
|
9
|
+
import type { WorkflowGeneratorOpts } from './workflow-generator.js';
|
|
10
|
+
import { WORKFLOW_PATH } from './workflow-generator.js';
|
|
11
|
+
export { WORKFLOW_PATH };
|
|
12
|
+
export interface WorkflowWriteOptions {
|
|
13
|
+
/** When true, overwrite an existing file. Default: false. */
|
|
14
|
+
overwrite?: boolean;
|
|
15
|
+
/** Optional base dir override. Defaults to cwd(). */
|
|
16
|
+
baseDir?: string;
|
|
17
|
+
}
|
|
18
|
+
export type WorkflowWriteResult = {
|
|
19
|
+
kind: 'written';
|
|
20
|
+
absolutePath: string;
|
|
21
|
+
content: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'exists';
|
|
24
|
+
absolutePath: string;
|
|
25
|
+
existingContent: string;
|
|
26
|
+
newContent: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Generate the workflow YAML and write it to `.github/workflows/capgo-build.yml`.
|
|
30
|
+
* Creates the `.github/workflows/` directory if it doesn't exist.
|
|
31
|
+
*
|
|
32
|
+
* If the file already exists and `overwrite` is false, returns `kind: 'exists'`
|
|
33
|
+
* with both the existing and proposed content so the caller can render a diff
|
|
34
|
+
* and ask for explicit confirmation before clobbering.
|
|
35
|
+
*/
|
|
36
|
+
export declare function writeWorkflowFile(opts: WorkflowGeneratorOpts, writeOptions?: WorkflowWriteOptions): WorkflowWriteResult;
|