@capgo/cli 7.110.0 → 7.111.1

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": "7.110.0",
4
+ "version": "7.111.1",
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
- export declare function createCiSecretEntries(credentials: Partial<BuildCredentials>): CiSecretEntry[];
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;
@@ -7,6 +7,7 @@ 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
11
  }
11
12
  declare const OnboardingApp: FC<AppProps>;
12
13
  export default OnboardingApp;
@@ -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;
@@ -20,11 +20,10 @@ interface InitAutoTestChange {
20
20
  }
21
21
  export declare function getGitRepoStatus(startDir?: string): GitRepoStatus;
22
22
  export declare function getInitUpdaterPluginConfig(appId: string, directInstall: boolean): {
23
- directUpdate?: string | undefined;
24
23
  autoSplashscreen?: boolean | undefined;
25
24
  version: string;
26
25
  appId: string;
27
- autoUpdate: boolean;
26
+ autoUpdate: string;
28
27
  };
29
28
  export declare function getInitOtaVersionBase(pkgVersion: string): string;
30
29
  export declare function getInitSuggestedOtaVersion(pkgVersion: string): string;