@htgabriel/release-kit 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/exec/run.ts","../src/ui/log.ts","../src/context.ts","../src/config/schema.ts","../src/config/load.ts","../src/git/policy.ts","../src/git/commits.ts","../src/project/version.ts","../src/doctor/checks.ts","../src/project/detect.ts","../src/eas/cli.ts","../src/doctor/toolchain.ts","../src/doctor/run.ts","../src/release/build.ts","../src/eas/profiles.ts","../src/release/gate.ts","../src/release/metadata.ts","../src/release/submit.ts","../src/release/ship.ts","../src/release/version.ts","../src/release/notes.ts","../src/notes/draft.ts","../src/notes/editor.ts","../src/notes/limits.ts","../src/notes/paths.ts","../src/stores/credentials.ts","../src/env/store.ts","../src/stores/apple/auth.ts","../src/stores/apple/client.ts","../src/stores/google/auth.ts","../src/stores/google/client.ts","../src/stores/google/tracks.ts","../src/stores/apple/apps.ts","../src/stores/apple/review.ts","../src/release/promote.ts","../src/release/rollout.ts","../src/release/status.ts","../src/release/update.ts"],"sourcesContent":["import crossSpawn from 'cross-spawn'\n\nexport class ReleaseKitError extends Error {\n\tcode: number\n\n\tconstructor(message: string, { code = 1 }: { code?: number } = {}) {\n\t\tsuper(message)\n\t\tthis.name = 'ReleaseKitError'\n\t\tthis.code = code\n\t}\n}\n\nexport function fail(message: string, code = 1): never {\n\tthrow new ReleaseKitError(message, { code })\n}\n\nexport interface RunResult {\n\tstatus: number\n\tsignal: NodeJS.Signals | null\n\tstdout: string\n\tstderr: string\n\terror?: Error\n\tdryRun?: boolean\n\tprinted?: string\n}\n\nexport interface RunOptions {\n\tcwd?: string\n\tenv?: NodeJS.ProcessEnv\n\tinherit?: boolean\n\tdryRun?: boolean\n}\n\n/**\n * Só as env vars relevantes (APP_VARIANT, EAS_*) aparecem no comando\n * impresso — nunca segredos herdados do processo.\n */\nexport function formatCommand(\n\tcommand: string,\n\targs: string[],\n\tenv: Record<string, string | undefined> = {}\n): string {\n\tconst exported = Object.entries(env)\n\t\t.filter(([key, value]) => value !== undefined && (key === 'APP_VARIANT' || key.startsWith('EAS_')))\n\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t.join(' ')\n\tconst body = [command, ...args].join(' ')\n\treturn exported ? `${exported} ${body}` : body\n}\n\nexport type Runner = (command: string, args: string[], options?: RunOptions) => RunResult\n\n/**\n * spawnSync via cross-spawn: no Windows resolve .cmd/.bat (eas -> eas.cmd,\n * yarn -> yarn.cmd) e escapa argumentos corretamente. Sem isso `eas build`\n * falha silenciosamente fora do macOS/Linux.\n */\nexport const defaultRun: Runner = (command, args, { cwd, env, inherit = false, dryRun = false } = {}) => {\n\tconst extraEnv = env ?? {}\n\tif (dryRun) {\n\t\treturn {\n\t\t\tstatus: 0,\n\t\t\tsignal: null,\n\t\t\tstdout: '',\n\t\t\tstderr: '',\n\t\t\tdryRun: true,\n\t\t\tprinted: formatCommand(command, args, extraEnv),\n\t\t}\n\t}\n\tconst result = crossSpawn.sync(command, args, {\n\t\tcwd,\n\t\tenv: { ...process.env, ...extraEnv },\n\t\tencoding: 'utf8',\n\t\tstdio: inherit ? 'inherit' : 'pipe',\n\t\tmaxBuffer: 32 * 1024 * 1024,\n\t})\n\treturn {\n\t\tstatus: result.status ?? 1,\n\t\tsignal: result.signal ?? null,\n\t\tstdout: result.stdout ?? '',\n\t\tstderr: result.stderr ?? '',\n\t\terror: result.error,\n\t}\n}\n\nexport function requireSuccess(result: RunResult, label: string): RunResult {\n\tif (result.dryRun) return result\n\tif (result.status === 0) return result\n\tconst how = result.signal ? `sinal ${result.signal}` : `exit ${result.status}`\n\tconst detail = (result.stderr || result.stdout || result.error?.message || '').trim()\n\tfail(`${label} falhou (${how}).${detail ? `\\n${detail}` : ''}`)\n}\n","import pc from 'picocolors'\n\nexport type LogFn = (message: string) => void\n\nexport interface Logger {\n\tinfo: LogFn\n\twarn: LogFn\n\terror: LogFn\n\tsuccess: LogFn\n\tstep: LogFn\n\tdebug: LogFn\n}\n\nexport interface CreateLoggerOptions {\n\tjson?: boolean\n\tverbose?: boolean\n\twrite?: (line: string) => void\n}\n\n/**\n * Todo output de log vai para stderr (console.error) — stdout fica livre\n * para `--json`, que imprime só o resultado estruturado do comando.\n */\nexport function createLogger(options: CreateLoggerOptions = {}): Logger {\n\tconst write = options.write ?? ((line: string) => console.error(line))\n\tconst silent = Boolean(options.json)\n\n\tconst emit = (line: string) => {\n\t\tif (silent) return\n\t\twrite(line)\n\t}\n\n\treturn {\n\t\tinfo: (message) => emit(message),\n\t\twarn: (message) => emit(pc.yellow(`! ${message}`)),\n\t\terror: (message) => emit(pc.red(`✗ ${message}`)),\n\t\tsuccess: (message) => emit(pc.green(`✓ ${message}`)),\n\t\tstep: (message) => emit(pc.cyan(`→ ${message}`)),\n\t\tdebug: (message) => {\n\t\t\tif (!options.verbose) return\n\t\t\temit(pc.dim(message))\n\t\t},\n\t}\n}\n","import { defaultRun, type Runner } from './exec/run.js'\nimport { createLogger, type Logger } from './ui/log.js'\n\nexport interface ReleaseKitContext {\n\t/** Raiz do repositório git do projeto consumidor. */\n\trepoRoot: string\n\t/** Diretório do app Expo (\".\", \"packages/app\", etc). */\n\tappDir: string\n\t/** Onde ficam os artefatos e metadata de build (gitignored). */\n\treleaseDir: string\n\tenv: NodeJS.ProcessEnv\n\tdryRun: boolean\n\tjson: boolean\n\tverbose: boolean\n\t/** Sem TTY / --non-interactive: nunca pergunta, nunca publica sem flags explícitas. */\n\tnonInteractive: boolean\n\trun: Runner\n\tlog: Logger\n\t/** Usado no gate de canal protegido: pede para digitar a versão exata. */\n\tconfirm?: (question: string) => Promise<string> | string\n}\n\nexport interface CreateContextOverrides {\n\trepoRoot: string\n\tappDir?: string\n\treleaseDir?: string\n\tenv?: NodeJS.ProcessEnv\n\tdryRun?: boolean\n\tjson?: boolean\n\tverbose?: boolean\n\tnonInteractive?: boolean\n\trun?: Runner\n\tlog?: Logger\n\tconfirm?: (question: string) => Promise<string> | string\n}\n\nexport function createContext(overrides: CreateContextOverrides): ReleaseKitContext {\n\tconst env = overrides.env ?? process.env\n\tconst json = Boolean(overrides.json)\n\treturn {\n\t\trepoRoot: overrides.repoRoot,\n\t\tappDir: overrides.appDir ?? overrides.repoRoot,\n\t\treleaseDir: overrides.releaseDir ?? `${overrides.repoRoot}/.release`,\n\t\tenv,\n\t\tdryRun: Boolean(overrides.dryRun),\n\t\tjson,\n\t\tverbose: Boolean(overrides.verbose),\n\t\tnonInteractive: overrides.nonInteractive ?? !process.stdin.isTTY,\n\t\trun: overrides.run ?? defaultRun,\n\t\tlog: overrides.log ?? createLogger({ json, verbose: overrides.verbose }),\n\t\tconfirm: overrides.confirm,\n\t}\n}\n\nexport type { Runner } from './exec/run.js'\nexport type { Logger } from './ui/log.js'\n","import { z } from 'zod'\n\nexport const platformSchema = z.enum(['android', 'ios'])\nexport type Platform = z.infer<typeof platformSchema>\n\nexport const versionSourceSchema = z.enum(['app.json', 'package.json'])\n\nexport const gitPolicySchema = z.object({\n\treleaseBranch: z.string().default('main'),\n\ttagFormat: z.string().default('v{version}'),\n\trequireClean: z.boolean().default(true),\n\trequireSyncedWithRemote: z.boolean().default(true),\n\tremote: z.string().default('origin'),\n})\nexport type GitPolicy = z.infer<typeof gitPolicySchema>\n\nconst iosChannelSchema = z.object({\n\tbundleId: z.string(),\n\tascAppId: z.string().optional(),\n\tappleTeamId: z.string().optional(),\n\tphasedRelease: z.boolean().default(false),\n\tautomaticRelease: z.boolean().default(false),\n\tcopyright: z.string().optional(),\n})\n\nconst androidChannelSchema = z.object({\n\tpackage: z.string(),\n\ttestTrack: z.string().default('internal'),\n\tproductionTrack: z.string().default('production'),\n\tinitialRollout: z.number().min(0).max(1).default(1),\n})\n\nconst otaSchema = z.object({\n\tchannel: z.string(),\n})\n\nexport const channelSchema = z.object({\n\t/** Canal protegido (produção): exige --i-know-this-is-production ou confirmação digitando a versão. */\n\tprotected: z.boolean().default(false),\n\t/** Se false, o canal nunca envia à loja (ex: build local de sideload). */\n\tstore: z.boolean().default(true),\n\tbuildProfile: z.string(),\n\tsubmitProfile: z.string().optional(),\n\t/** Nome do \"environment\" do EAS (eas.json build.<profile>.environment) — usado nos checks de fingerprint/Sentry. */\n\teasEnvironment: z.string().optional(),\n\t/** Se o build profile já reusa o build number/versionCode (eas.json autoIncrement). */\n\tautoIncrement: z.boolean().default(true),\n\t/** Profiles com upload de sourcemap desligado (ex: SENTRY_DISABLE_AUTO_UPLOAD) não exigem token no doctor. */\n\tsentryUploadDisabled: z.boolean().default(false),\n\tenv: z.record(z.string(), z.string()).default({}),\n\tios: iosChannelSchema.optional(),\n\tandroid: androidChannelSchema.optional(),\n\tota: otaSchema.optional(),\n})\nexport type ChannelConfig = z.infer<typeof channelSchema>\n\nexport const toolchainBaselineSchema = z.object({\n\teasCli: z.object({ min: z.string(), tested: z.string() }).optional(),\n\tnode: z.object({ min: z.string(), tested: z.string() }).optional(),\n\tjdk: z.object({ min: z.string(), tested: z.string() }).optional(),\n\txcode: z.object({ min: z.string(), tested: z.string() }).optional(),\n\tcocoapods: z.object({ min: z.string(), tested: z.string() }).optional(),\n})\nexport type ToolchainBaseline = z.infer<typeof toolchainBaselineSchema>\n\nexport const doctorConfigSchema = z.object({\n\tsentry: z.boolean().default(false),\n\texpoDoctor: z.boolean().default(true),\n})\n\nexport const releaseKitConfigSchema = z.object({\n\t$schema: z.string().optional(),\n\tappDir: z.string().default('.'),\n\t/** Conta/organização esperada no `eas whoami` (opcional; reforça o doctor). */\n\teasOwner: z.string().optional(),\n\tplatforms: z.array(platformSchema).min(1),\n\tlocales: z.array(z.string()).min(1).default(['pt-BR']),\n\tnotesDir: z.string().default('release-notes'),\n\tversion: z.object({ source: versionSourceSchema.default('app.json') }).default({ source: 'app.json' }),\n\tgit: gitPolicySchema.default({}),\n\tchannels: z.record(z.string(), channelSchema).refine((channels) => Object.keys(channels).length > 0, {\n\t\tmessage: 'defina ao menos um canal em \"channels\"',\n\t}),\n\ttoolchain: toolchainBaselineSchema.default({}),\n\tdoctor: doctorConfigSchema.default({}),\n})\nexport type ReleaseKitConfig = z.infer<typeof releaseKitConfigSchema>\n\nexport function parseConfig(input: unknown): ReleaseKitConfig {\n\treturn releaseKitConfigSchema.parse(input)\n}\n\nexport function defaultLocale(config: ReleaseKitConfig): string {\n\tconst [first] = config.locales\n\tif (!first) throw new Error('config.locales está vazio')\n\treturn first\n}\n\nexport function channelOf(config: ReleaseKitConfig, name: string): ChannelConfig {\n\tconst channel = config.channels[name]\n\tif (!channel) {\n\t\tconst available = Object.keys(config.channels).join(', ')\n\t\tthrow new Error(`canal desconhecido: \"${name}\". Canais disponíveis: ${available}`)\n\t}\n\treturn channel\n}\n\nexport function protectedChannelNames(config: ReleaseKitConfig): string[] {\n\treturn Object.entries(config.channels)\n\t\t.filter(([, channel]) => channel.protected)\n\t\t.map(([name]) => name)\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { z } from 'zod'\nimport { fail } from '../exec/run.js'\nimport { parseConfig, type ReleaseKitConfig } from './schema.js'\n\nexport const CONFIG_FILENAME = 'release-kit.config.json'\n\nexport function configPath(repoRoot: string): string {\n\treturn join(repoRoot, CONFIG_FILENAME)\n}\n\nexport function configExists(repoRoot: string): boolean {\n\treturn existsSync(configPath(repoRoot))\n}\n\nexport function loadConfig(repoRoot: string): ReleaseKitConfig {\n\tconst path = configPath(repoRoot)\n\tif (!existsSync(path)) {\n\t\tfail(\n\t\t\t`${CONFIG_FILENAME} não encontrado em ${repoRoot}. Rode \\`release-kit init\\` para criar a configuração.`\n\t\t)\n\t}\n\tlet raw: unknown\n\ttry {\n\t\traw = JSON.parse(readFileSync(path, 'utf8'))\n\t} catch (error) {\n\t\tfail(`${CONFIG_FILENAME} não é um JSON válido: ${(error as Error).message}`)\n\t}\n\ttry {\n\t\treturn parseConfig(raw)\n\t} catch (error) {\n\t\tif (error instanceof z.ZodError) {\n\t\t\tconst issues = error.issues.map((issue) => ` - ${issue.path.join('.') || '(raiz)'}: ${issue.message}`)\n\t\t\tfail(`${CONFIG_FILENAME} inválido:\\n${issues.join('\\n')}`)\n\t\t}\n\t\tthrow error\n\t}\n}\n\nexport function writeConfig(repoRoot: string, config: ReleaseKitConfig): string {\n\tconst path = configPath(repoRoot)\n\tconst withSchema = { $schema: './node_modules/@htgabriel/release-kit/schema.json', ...config }\n\twriteFileSync(path, `${JSON.stringify(withSchema, null, 2)}\\n`)\n\treturn path\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport { requireSuccess, type RunResult } from '../exec/run.js'\nimport type { GitPolicy } from '../config/schema.js'\n\nexport function git(ctx: ReleaseKitContext, args: string[], { allowFail = false }: { allowFail?: boolean } = {}): RunResult {\n\tconst result = ctx.run('git', args, { cwd: ctx.repoRoot, inherit: false })\n\tif (!allowFail) requireSuccess(result, `git ${args.join(' ')}`)\n\treturn result\n}\n\nexport function gitPorcelain(ctx: ReleaseKitContext): string {\n\treturn git(ctx, ['status', '--porcelain']).stdout\n}\n\nexport function isWorkingTreeClean(ctx: ReleaseKitContext, ignoreDirs: string[] = ['.release/']): boolean {\n\tconst dirty = gitPorcelain(ctx)\n\t\t.split('\\n')\n\t\t.map((line) => line.trimEnd())\n\t\t.filter((line) => line.length > 0)\n\t\t.filter((line) => !ignoreDirs.some((dir) => line.endsWith(` ${dir}`) || line.includes(` ${dir}`)))\n\treturn dirty.length === 0\n}\n\nexport function dirtyFiles(ctx: ReleaseKitContext, ignoreDirs: string[] = ['.release/']): string[] {\n\treturn gitPorcelain(ctx)\n\t\t.split('\\n')\n\t\t.map((line) => line.trimEnd())\n\t\t.filter((line) => line.length > 0)\n\t\t.filter((line) => !ignoreDirs.some((dir) => line.endsWith(` ${dir}`) || line.includes(` ${dir}`)))\n}\n\nexport function currentBranch(ctx: ReleaseKitContext): string {\n\treturn git(ctx, ['rev-parse', '--abbrev-ref', 'HEAD']).stdout.trim()\n}\n\nexport function headSha(ctx: ReleaseKitContext): string {\n\treturn git(ctx, ['rev-parse', 'HEAD']).stdout.trim()\n}\n\nexport function remoteSha(ctx: ReleaseKitContext, remote: string, branch: string): string | null {\n\tconst result = git(ctx, ['rev-parse', `${remote}/${branch}`], { allowFail: true })\n\tif (result.status !== 0) return null\n\treturn result.stdout.trim()\n}\n\nexport function tagShaFormatted(ctx: ReleaseKitContext, tagFormat: string, version: string): string | null {\n\tconst tag = renderTag(tagFormat, version)\n\tconst result = git(ctx, ['rev-parse', `${tag}^{commit}`], { allowFail: true })\n\tif (result.status !== 0) return null\n\treturn result.stdout.trim()\n}\n\nexport function tagsPointingAtHead(ctx: ReleaseKitContext): string[] {\n\tconst result = git(ctx, ['tag', '--points-at', 'HEAD'], { allowFail: true })\n\treturn (result.stdout || '')\n\t\t.split('\\n')\n\t\t.map((line) => line.trim())\n\t\t.filter(Boolean)\n}\n\nexport function lastTagMatching(ctx: ReleaseKitContext, tagFormat: string): string | null {\n\tconst pattern = tagGlob(tagFormat)\n\tconst result = git(ctx, ['tag', '--list', pattern, '--sort=-creatordate'], { allowFail: true })\n\tconst [first] = (result.stdout || '').split('\\n').map((line) => line.trim()).filter(Boolean)\n\treturn first ?? null\n}\n\nexport function aheadBehind(\n\tctx: ReleaseKitContext,\n\tremote: string,\n\tbranch: string\n): { ahead: number; behind: number } | null {\n\tconst upstream = git(ctx, ['rev-parse', '--abbrev-ref', `${branch}@{upstream}`], { allowFail: true })\n\tif (upstream.status !== 0) return null\n\tconst counts = git(ctx, ['rev-list', '--left-right', '--count', `HEAD...${remote}/${branch}`], {\n\t\tallowFail: true,\n\t})\n\tif (counts.status !== 0) return null\n\tconst [ahead = '0', behind = '0'] = counts.stdout.trim().split(/\\s+/)\n\treturn { ahead: Number(ahead), behind: Number(behind) }\n}\n\nexport function renderTag(tagFormat: string, version: string): string {\n\treturn tagFormat.replace('{version}', version)\n}\n\n/** Converte \"v{version}\" em um glob de `git tag --list` (ex: \"v*\"). */\nfunction tagGlob(tagFormat: string): string {\n\treturn tagFormat.replace('{version}', '*')\n}\n\nexport interface GitCheckResult {\n\tname: string\n\tstatus: 'pass' | 'fail' | 'skip' | 'warn'\n\tmessage: string\n}\n\n/**\n * Assertivas de política de git usadas pelo doctor e pelo gate de build.\n * Reflete a regra do release kit original: production exige branch de\n * release, tag == HEAD, e HEAD == remoto.\n */\nexport function checkGitPolicy(\n\tctx: ReleaseKitContext,\n\tpolicy: GitPolicy,\n\t{ version, isProtectedChannel }: { version: string; isProtectedChannel: boolean }\n): GitCheckResult[] {\n\tconst checks: GitCheckResult[] = []\n\tconst branch = currentBranch(ctx)\n\n\tif (policy.requireClean) {\n\t\tconst dirty = dirtyFiles(ctx)\n\t\tif (dirty.length) {\n\t\t\tchecks.push({ name: 'git-clean', status: 'fail', message: `working tree suja:\\n${dirty.join('\\n')}` })\n\t\t} else {\n\t\t\tchecks.push({ name: 'git-clean', status: 'pass', message: 'working tree limpa' })\n\t\t}\n\t}\n\n\tif (isProtectedChannel) {\n\t\tif (branch !== policy.releaseBranch) {\n\t\t\tchecks.push({\n\t\t\t\tname: 'git-branch',\n\t\t\t\tstatus: 'fail',\n\t\t\t\tmessage: `canal protegido exige branch ${policy.releaseBranch} (atual: ${branch}).`,\n\t\t\t})\n\t\t} else {\n\t\t\tchecks.push({ name: 'git-branch', status: 'pass', message: `branch ${branch}` })\n\t\t}\n\n\t\tconst head = headSha(ctx)\n\t\tconst expectedTag = renderTag(policy.tagFormat, version)\n\t\tconst tagSha = tagShaFormatted(ctx, policy.tagFormat, version)\n\t\tif (!tagSha) {\n\t\t\tchecks.push({ name: 'git-tag', status: 'fail', message: `tag ${expectedTag} não existe (versão atual: ${version}).` })\n\t\t} else if (tagSha !== head) {\n\t\t\tchecks.push({\n\t\t\t\tname: 'git-tag',\n\t\t\t\tstatus: 'fail',\n\t\t\t\tmessage: `tag ${expectedTag} (${tagSha.slice(0, 8)}) não aponta para HEAD (${head.slice(0, 8)}).`,\n\t\t\t})\n\t\t} else {\n\t\t\tchecks.push({ name: 'git-tag', status: 'pass', message: `${expectedTag} == HEAD` })\n\t\t}\n\n\t\tif (policy.requireSyncedWithRemote) {\n\t\t\tconst remote = remoteSha(ctx, policy.remote, policy.releaseBranch)\n\t\t\tif (!remote) {\n\t\t\t\tchecks.push({\n\t\t\t\t\tname: 'git-sync',\n\t\t\t\t\tstatus: 'fail',\n\t\t\t\t\tmessage: `${policy.remote}/${policy.releaseBranch} ausente. Rode git fetch ${policy.remote} ${policy.releaseBranch}.`,\n\t\t\t\t})\n\t\t\t} else if (remote !== head) {\n\t\t\t\tchecks.push({\n\t\t\t\t\tname: 'git-sync',\n\t\t\t\t\tstatus: 'fail',\n\t\t\t\t\tmessage: `HEAD (${head.slice(0, 8)}) ≠ ${policy.remote}/${policy.releaseBranch} (${remote.slice(0, 8)}).`,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tchecks.push({ name: 'git-sync', status: 'pass', message: `HEAD == ${policy.remote}/${policy.releaseBranch}` })\n\t\t\t}\n\t\t}\n\t\treturn checks\n\t}\n\n\tif (policy.requireSyncedWithRemote) {\n\t\tconst status = aheadBehind(ctx, policy.remote, branch)\n\t\tif (!status) {\n\t\t\tchecks.push({ name: 'git-sync', status: 'fail', message: `branch ${branch} sem upstream. Rode git push -u.` })\n\t\t} else if (status.behind > 0) {\n\t\t\tchecks.push({ name: 'git-sync', status: 'fail', message: `branch atrasada ${status.behind} commit(s) em relação ao upstream.` })\n\t\t} else if (status.ahead > 0) {\n\t\t\tchecks.push({ name: 'git-sync', status: 'fail', message: `branch adiantada ${status.ahead} commit(s) — faça push antes de buildar.` })\n\t\t} else {\n\t\t\tchecks.push({ name: 'git-sync', status: 'pass', message: 'sincronizada com o upstream' })\n\t\t}\n\t}\n\n\treturn checks\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport { git, lastTagMatching } from './policy.js'\n\nexport interface CommitEntry {\n\tsha: string\n\tsubject: string\n\ttype: string | null\n\tscope: string | null\n\tdescription: string\n}\n\nconst CONVENTIONAL_RE = /^(\\w+)(?:\\(([^)]+)\\))?!?:\\s*(.+)$/\n\nfunction parseSubject(subject: string): { type: string | null; scope: string | null; description: string } {\n\tconst match = subject.match(CONVENTIONAL_RE)\n\tif (!match) return { type: null, scope: null, description: subject }\n\tconst [, type, scope, description] = match\n\treturn { type: type ?? null, scope: scope ?? null, description: description ?? subject }\n}\n\n/**\n * Lista os commits desde a última tag que casa com `tagFormat` (ou desde o\n * início do histórico, se nenhuma tag existir ainda). Usado para rascunhar\n * as notas de versão.\n */\nexport function commitsSinceLastTag(ctx: ReleaseKitContext, tagFormat: string): CommitEntry[] {\n\tconst lastTag = lastTagMatching(ctx, tagFormat)\n\tconst range = lastTag ? `${lastTag}..HEAD` : 'HEAD'\n\tconst result = git(ctx, ['log', range, '--pretty=format:%h %s'], { allowFail: true })\n\tif (result.status !== 0) return []\n\treturn result.stdout\n\t\t.split('\\n')\n\t\t.map((line) => line.trim())\n\t\t.filter(Boolean)\n\t\t.map((line) => {\n\t\t\tconst [sha, ...rest] = line.split(' ')\n\t\t\tconst subject = rest.join(' ')\n\t\t\tconst parsed = parseSubject(subject)\n\t\t\treturn { sha: sha ?? '', subject, ...parsed }\n\t\t})\n}\n\nconst USER_FACING_TYPES = new Set(['feat', 'fix'])\n\n/** Filtra só o que interessa ao usuário final (feat/fix), descarta o resto. */\nexport function userFacingCommits(commits: CommitEntry[]): CommitEntry[] {\n\treturn commits.filter((commit) => commit.type && USER_FACING_TYPES.has(commit.type))\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport semver from 'semver'\nimport { fail } from '../exec/run.js'\nimport type { ReleaseKitConfig } from '../config/schema.js'\n\ninterface VersionFile {\n\tpath: string\n\tjson: Record<string, unknown>\n\tget(): string\n\tset(next: string): void\n}\n\nfunction loadVersionFile(appDir: string, source: 'app.json' | 'package.json'): VersionFile {\n\tconst path = join(appDir, source)\n\tif (!existsSync(path)) fail(`${source} não encontrado em ${appDir}.`)\n\tconst raw = readFileSync(path, 'utf8')\n\tconst json = JSON.parse(raw) as Record<string, unknown>\n\n\tif (source === 'app.json') {\n\t\treturn {\n\t\t\tpath,\n\t\t\tjson,\n\t\t\tget: () => {\n\t\t\t\tconst expo = json.expo as Record<string, unknown> | undefined\n\t\t\t\tconst version = expo?.version\n\t\t\t\tif (typeof version !== 'string') fail(`app.json não tem expo.version.`)\n\t\t\t\treturn version\n\t\t\t},\n\t\t\tset: (next) => {\n\t\t\t\tconst expo = (json.expo as Record<string, unknown>) ?? {}\n\t\t\t\texpo.version = next\n\t\t\t\tjson.expo = expo\n\t\t\t},\n\t\t}\n\t}\n\n\treturn {\n\t\tpath,\n\t\tjson,\n\t\tget: () => {\n\t\t\tconst version = json.version\n\t\t\tif (typeof version !== 'string') fail(`package.json não tem \"version\".`)\n\t\t\treturn version\n\t\t},\n\t\tset: (next) => {\n\t\t\tjson.version = next\n\t\t},\n\t}\n}\n\nexport function readAppVersion(appDir: string, config: ReleaseKitConfig): string {\n\treturn loadVersionFile(appDir, config.version.source).get()\n}\n\nexport type VersionBump = 'patch' | 'minor' | 'major' | string\n\nexport function nextVersion(current: string, bump: VersionBump): string {\n\tif (bump === 'patch' || bump === 'minor' || bump === 'major') {\n\t\tconst next = semver.inc(current, bump)\n\t\tif (!next) fail(`não foi possível incrementar \"${bump}\" a partir de ${current}.`)\n\t\treturn next\n\t}\n\tif (!semver.valid(bump)) fail(`versão inválida: \"${bump}\". Use patch | minor | major | x.y.z.`)\n\tif (semver.lte(bump, current)) {\n\t\tfail(`${bump} não é maior que a versão atual (${current}).`)\n\t}\n\treturn bump\n}\n\n/**\n * Grava a nova versão preservando o resto do arquivo. Retorna o path\n * escrito, para o caller decidir o `git add`/commit.\n */\nexport function writeAppVersion(appDir: string, config: ReleaseKitConfig, next: string): string {\n\tconst file = loadVersionFile(appDir, config.version.source)\n\tfile.set(next)\n\twriteFileSync(file.path, `${JSON.stringify(file.json, null, '\\t')}\\n`)\n\treturn file.path\n}\n","import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { ReleaseKitContext } from '../context.js'\nimport type { ChannelConfig, Platform, ReleaseKitConfig } from '../config/schema.js'\nimport { checkGitPolicy, type GitCheckResult } from '../git/policy.js'\nimport { readAppVersion } from '../project/version.js'\nimport { detectPackageManager } from '../project/detect.js'\nimport {\n\teasEnvListHasKey,\n\teasFingerprintCompare,\n\teasFingerprintGenerate,\n\teasWhoami,\n\texpectedBuildNumber,\n\tprojectRemoteVersion,\n} from '../eas/cli.js'\nimport { collectToolchain, cmpVersion, type ToolchainInfo } from './toolchain.js'\n\nexport type CheckStatus = 'pass' | 'fail' | 'skip' | 'warn'\nexport interface Check {\n\tname: string\n\tstatus: CheckStatus\n\tmessage: string\n}\n\nconst EXPO_PUBLIC_PREFIX = 'EXPO_PUBLIC_'\n\nfunction check(name: string, status: CheckStatus, message: string): Check {\n\treturn { name, status, message }\n}\n\nexport function assertShellClean(ctx: ReleaseKitContext, checks: Check[]): void {\n\tconst leaked = Object.keys(ctx.env).filter((key) => key.startsWith(EXPO_PUBLIC_PREFIX) && ctx.env[key])\n\tif (leaked.length) {\n\t\tchecks.push(\n\t\t\tcheck(\n\t\t\t\t'shell-env',\n\t\t\t\t'fail',\n\t\t\t\t`shell tem ${leaked.join(', ')} exportado. Em build local isso vence as env vars do EAS. Unset antes de continuar.`\n\t\t\t)\n\t\t)\n\t\treturn\n\t}\n\tchecks.push(check('shell-env', 'pass', 'nenhum EXPO_PUBLIC_* no shell'))\n}\n\nexport function assertSentry(ctx: ReleaseKitContext, checks: Check[], channel: ChannelConfig | null): void {\n\tif (channel?.sentryUploadDisabled) {\n\t\tchecks.push(check('sentry', 'pass', 'canal desliga o upload de sourcemap; token não é exigido.'))\n\t\treturn\n\t}\n\tconst inShell = Boolean(ctx.env.SENTRY_AUTH_TOKEN)\n\tif (!channel && !inShell) {\n\t\tchecks.push(check('sentry', 'skip', 'passe --channel para verificar SENTRY_AUTH_TOKEN no environment EAS.'))\n\t\treturn\n\t}\n\tif (inShell) {\n\t\tchecks.push(\n\t\t\tcheck(\n\t\t\t\t'sentry',\n\t\t\t\t'warn',\n\t\t\t\t'SENTRY_AUTH_TOKEN está no shell e, em build local, vence o token do EAS. Prefira unset e deixe o environment EAS (Sensitive) injetar.'\n\t\t\t)\n\t\t)\n\t\treturn\n\t}\n\tconst environment = channel?.easEnvironment\n\tif (environment && easEnvListHasKey(ctx, environment, 'SENTRY_AUTH_TOKEN')) {\n\t\tchecks.push(check('sentry', 'pass', `SENTRY_AUTH_TOKEN no environment EAS ${environment}.`))\n\t\treturn\n\t}\n\tchecks.push(\n\t\tcheck(\n\t\t\t'sentry',\n\t\t\t'fail',\n\t\t\t`SENTRY_AUTH_TOKEN ausente no shell e no environment EAS ${environment || '(defina easEnvironment no canal)'}.`\n\t\t)\n\t)\n}\n\nexport function assertEasAuth(ctx: ReleaseKitContext, checks: Check[], easOwner?: string): void {\n\tconst result = easWhoami(ctx)\n\tif (ctx.dryRun) {\n\t\tchecks.push(check('eas-auth', 'pass', '[dry-run] eas whoami'))\n\t\treturn\n\t}\n\tif (!result.ok) {\n\t\tchecks.push(check('eas-auth', 'fail', `eas whoami falhou. Rode \\`eas login\\` ou defina EXPO_TOKEN.\\n${result.raw}`))\n\t\treturn\n\t}\n\tif (easOwner && !result.raw.includes(easOwner)) {\n\t\tchecks.push(check('eas-auth', 'fail', `eas whoami não listou a conta ${easOwner}.`))\n\t\treturn\n\t}\n\tchecks.push(check('eas-auth', 'pass', `autenticado${result.account ? ` como ${result.account}` : ''}`))\n}\n\nexport interface ToolchainCheckResult {\n\tactual: ToolchainInfo\n\tdrift: string[]\n\ttoolchainDrift: boolean\n}\n\nexport function assertToolchain(\n\tctx: ReleaseKitContext,\n\tchecks: Check[],\n\tconfig: ReleaseKitConfig,\n\t{ platform, allowToolchainDrift }: { platform?: Platform; allowToolchainDrift?: boolean }\n): ToolchainCheckResult {\n\tconst baseline = config.toolchain\n\tconst actual = collectToolchain(ctx)\n\tconst drift: string[] = []\n\n\tconst compare = (\n\t\tname: string,\n\t\tspec: { min?: string; tested?: string } | undefined,\n\t\tvalue: string | null,\n\t\t{ platformOnly }: { platformOnly?: Platform } = {}\n\t) => {\n\t\tif (!spec) {\n\t\t\tchecks.push(check(`toolchain-${name}`, 'skip', 'sem baseline configurado'))\n\t\t\treturn\n\t\t}\n\t\tif (platformOnly && platform && platform !== platformOnly) {\n\t\t\tchecks.push(check(`toolchain-${name}`, 'skip', `não exigido para --platform ${platform}`))\n\t\t\treturn\n\t\t}\n\t\tif (!value) {\n\t\t\tchecks.push(check(`toolchain-${name}`, 'fail', `${name} não encontrado no PATH.`))\n\t\t\treturn\n\t\t}\n\t\tif (spec.min && cmpVersion(value, spec.min) < 0) {\n\t\t\tchecks.push(check(`toolchain-${name}`, 'fail', `${name} ${value} < mínimo ${spec.min}.`))\n\t\t\treturn\n\t\t}\n\t\tif (spec.tested && cmpVersion(value, spec.tested) > 0) {\n\t\t\tdrift.push(`${name} ${value} > testado ${spec.tested}`)\n\t\t\tchecks.push(\n\t\t\t\tcheck(\n\t\t\t\t\t`toolchain-${name}`,\n\t\t\t\t\tallowToolchainDrift ? 'warn' : 'fail',\n\t\t\t\t\t`${name} ${value} está acima do testado (${spec.tested}). Passe --allow-toolchain-drift para continuar.`\n\t\t\t\t)\n\t\t\t)\n\t\t\treturn\n\t\t}\n\t\tchecks.push(check(`toolchain-${name}`, 'pass', `${name} ${value}`))\n\t}\n\n\tcompare('eas-cli', baseline.easCli, actual.easCli)\n\tcompare('node', baseline.node, actual.node)\n\tcompare('jdk', baseline.jdk, actual.jdk, { platformOnly: 'android' })\n\tcompare('xcode', baseline.xcode, actual.xcode, { platformOnly: 'ios' })\n\tcompare('cocoapods', baseline.cocoapods, actual.cocoapods, { platformOnly: 'ios' })\n\n\tif (!platform || platform === 'android') {\n\t\tif (!ctx.env.JAVA_HOME) {\n\t\t\tchecks.push(check('java-home', 'fail', 'JAVA_HOME não está definido.'))\n\t\t} else {\n\t\t\tchecks.push(check('java-home', 'pass', ctx.env.JAVA_HOME))\n\t\t}\n\t\tif (!ctx.env.ANDROID_HOME && !ctx.env.ANDROID_SDK_ROOT) {\n\t\t\tchecks.push(check('android-sdk', 'fail', 'ANDROID_HOME / ANDROID_SDK_ROOT ausente.'))\n\t\t} else {\n\t\t\tchecks.push(check('android-sdk', 'pass', ctx.env.ANDROID_HOME || ctx.env.ANDROID_SDK_ROOT || ''))\n\t\t}\n\t}\n\n\tif (platform === 'ios' && process.platform !== 'darwin') {\n\t\tchecks.push(check('platform-ios', 'fail', 'build local de iOS só funciona no macOS. Use --cloud ou remova --platform ios.'))\n\t} else if (platform === 'android' && process.platform === 'win32') {\n\t\tchecks.push(\n\t\t\tcheck(\n\t\t\t\t'platform-android',\n\t\t\t\t'warn',\n\t\t\t\t'build local de Android no Windows não é suportado pelo EAS fora do WSL2. Use --cloud ou rode dentro do WSL2.'\n\t\t\t)\n\t\t)\n\t}\n\n\treturn { actual, drift, toolchainDrift: drift.length > 0 }\n}\n\nexport function assertLockfileClean(ctx: ReleaseKitContext, checks: Check[]): void {\n\tconst pm = detectPackageManager(ctx.repoRoot)\n\tconst lockfile = { yarn: 'yarn.lock', pnpm: 'pnpm-lock.yaml', npm: 'package-lock.json' }[pm]\n\tconst diff = ctx.run('git', ['diff', '--quiet', 'HEAD', '--', lockfile], { cwd: ctx.repoRoot, inherit: false })\n\tif (diff.status !== 0) {\n\t\tchecks.push(check('lockfile', 'fail', `${lockfile} diverge do HEAD. Commit ou restaure antes do build (lockfile congelado).`))\n\t\treturn\n\t}\n\tchecks.push(check('lockfile', 'pass', `${lockfile} igual ao HEAD`))\n}\n\nexport function assertRemoteVersion(\n\tctx: ReleaseKitContext,\n\tchecks: Check[],\n\t{ platform, channel }: { platform: Platform; channel: ChannelConfig }\n): void {\n\tconst remote = projectRemoteVersion(ctx, { platform, buildProfile: channel.buildProfile })\n\tif (remote.dryRun) {\n\t\tchecks.push(check('remote-version', 'pass', '[dry-run] eas build:version:get'))\n\t\treturn\n\t}\n\tconst projection = expectedBuildNumber(remote, { autoIncrement: channel.autoIncrement, platform })\n\tif (!channel.autoIncrement) {\n\t\tchecks.push(\n\t\t\tcheck(\n\t\t\t\t'remote-version',\n\t\t\t\t'pass',\n\t\t\t\t`${projection.key} remoto atual: ${projection.current} (autoIncrement desligado; este build reutiliza o número).`\n\t\t\t)\n\t\t)\n\t\treturn\n\t}\n\tchecks.push(\n\t\tcheck(\n\t\t\t'remote-version',\n\t\t\t'pass',\n\t\t\t`${projection.key} remoto atual: ${projection.current} → esperado neste build: ${projection.expected} (só é reservado quando o EAS iniciar o build).`\n\t\t)\n\t)\n}\n\nexport function assertFingerprint(\n\tctx: ReleaseKitContext,\n\tchecks: Check[],\n\t{ channel, deep, buildId }: { channel: ChannelConfig; deep?: boolean; buildId?: string }\n): void {\n\tconst environment = channel.easEnvironment\n\tif (!environment) {\n\t\tchecks.push(check('fingerprint', 'skip', 'canal sem easEnvironment configurado.'))\n\t\treturn\n\t}\n\tif (!deep) {\n\t\tchecks.push(check('fingerprint', 'pass', `comparação contra build da nuvem só em --deep (environment ${environment}).`))\n\t\treturn\n\t}\n\tif (ctx.dryRun) {\n\t\tchecks.push(check('fingerprint', 'pass', `[dry-run] eas fingerprint:generate --environment ${environment}`))\n\t\treturn\n\t}\n\tconst generated = easFingerprintGenerate(ctx, environment)\n\tif (generated.status !== 0) {\n\t\tchecks.push(check('fingerprint', 'fail', `eas fingerprint:generate falhou.\\n${generated.stderr || generated.stdout}`))\n\t\treturn\n\t}\n\tif (!buildId) {\n\t\tchecks.push(\n\t\t\tcheck(\n\t\t\t\t'fingerprint',\n\t\t\t\t'pass',\n\t\t\t\t`fingerprint local gerado. Para comparar com a nuvem: eas fingerprint:compare --build-id <id> --environment ${environment}`\n\t\t\t)\n\t\t)\n\t\treturn\n\t}\n\tconst compared = easFingerprintCompare(ctx, environment, buildId)\n\tif (compared.status !== 0) {\n\t\tchecks.push(check('fingerprint', 'fail', `eas fingerprint:compare falhou.\\n${compared.stderr || compared.stdout}`))\n\t\treturn\n\t}\n\tchecks.push(check('fingerprint', 'pass', `fingerprint local vs build ${buildId}`))\n}\n\nexport function assertExpoDoctor(ctx: ReleaseKitContext, checks: Check[], config: ReleaseKitConfig): void {\n\tif (!config.doctor.expoDoctor) {\n\t\tchecks.push(check('expo-doctor', 'skip', 'desligado em doctor.expoDoctor'))\n\t\treturn\n\t}\n\tif (ctx.dryRun) {\n\t\tchecks.push(check('expo-doctor', 'pass', '[dry-run] npx expo-doctor'))\n\t\treturn\n\t}\n\tconst result = ctx.run('npx', ['expo-doctor'], { cwd: ctx.appDir, inherit: false })\n\tif (result.status !== 0) {\n\t\tconst detail = (result.stdout || result.stderr || '').trim()\n\t\tchecks.push(\n\t\t\tcheck('expo-doctor', 'fail', `expo-doctor saiu com código ${result.status}. Atualize as dependências com \\`npx expo install\\`.${detail ? `\\n${detail}` : ''}`)\n\t\t)\n\t\treturn\n\t}\n\tchecks.push(check('expo-doctor', 'pass', 'expo-doctor ok'))\n}\n\nexport function assertEasJsonExists(ctx: ReleaseKitContext): void {\n\tif (!existsSync(join(ctx.appDir, 'eas.json'))) {\n\t\tthrow new Error(`eas.json não encontrado em ${ctx.appDir}. Rode \\`eas init\\` ou \\`release-kit init\\`.`)\n\t}\n}\n\nexport { checkGitPolicy, type GitCheckResult }\nexport { readAppVersion }\n","import { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport type PackageManager = 'yarn' | 'npm' | 'pnpm'\n\nconst LOCKFILES: Record<PackageManager, string> = {\n\tyarn: 'yarn.lock',\n\tpnpm: 'pnpm-lock.yaml',\n\tnpm: 'package-lock.json',\n}\n\n/** Detecta o package manager pelo lockfile presente na raiz do repo. */\nexport function detectPackageManager(repoRoot: string): PackageManager {\n\tfor (const [pm, lockfile] of Object.entries(LOCKFILES) as [PackageManager, string][]) {\n\t\tif (existsSync(join(repoRoot, lockfile))) return pm\n\t}\n\treturn 'npm'\n}\n\n/**\n * Detecta o diretório do app Expo: primeiro tenta a raiz do repo, depois\n * `apps/*` e `packages/*` (padrão de monorepo) em busca de um app.json com\n * `expo`.\n */\nexport function detectAppDir(repoRoot: string): string | null {\n\tif (hasExpoAppJson(repoRoot)) return '.'\n\tconst candidateDirs = ['apps', 'packages']\n\tfor (const dir of candidateDirs) {\n\t\tconst base = join(repoRoot, dir)\n\t\tif (!existsSync(base)) continue\n\t\tconst entries = safeReadDir(base)\n\t\tfor (const entry of entries) {\n\t\t\tconst candidate = join(dir, entry)\n\t\t\tif (hasExpoAppJson(join(repoRoot, candidate))) return candidate\n\t\t}\n\t}\n\treturn null\n}\n\nfunction hasExpoAppJson(dir: string): boolean {\n\tconst path = join(dir, 'app.json')\n\tif (!existsSync(path)) return false\n\ttry {\n\t\tconst json = JSON.parse(readFileSync(path, 'utf8')) as Record<string, unknown>\n\t\treturn typeof json.expo === 'object' && json.expo !== null\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction safeReadDir(dir: string): string[] {\n\ttry {\n\t\treturn readdirSync(dir)\n\t} catch {\n\t\treturn []\n\t}\n}\n\nexport function detectEasJson(appDir: string): boolean {\n\treturn existsSync(join(appDir, 'eas.json'))\n}\n\nexport function readEasJson(appDir: string): Record<string, unknown> | null {\n\tconst path = join(appDir, 'eas.json')\n\tif (!existsSync(path)) return null\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, 'utf8')) as Record<string, unknown>\n\t} catch {\n\t\treturn null\n\t}\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport { fail, requireSuccess, type RunResult } from '../exec/run.js'\nimport type { Platform } from '../config/schema.js'\n\nexport function eas(\n\tctx: ReleaseKitContext,\n\targs: string[],\n\t{ inherit = false, env = {}, cwd }: { inherit?: boolean; env?: Record<string, string>; cwd?: string } = {}\n): RunResult {\n\treturn ctx.run('eas', args, {\n\t\tcwd: cwd ?? ctx.appDir,\n\t\tenv,\n\t\tinherit,\n\t\tdryRun: ctx.dryRun,\n\t})\n}\n\nexport interface RemoteVersion {\n\tversionCode: string | null\n\tbuildNumber: string | null\n\traw: unknown\n\tdryRun?: boolean\n}\n\nexport function parseRemoteVersion(stdout: string): RemoteVersion {\n\tconst text = String(stdout || '').trim()\n\tconst jsonStart = text.indexOf('{')\n\tif (jsonStart === -1) return { versionCode: null, buildNumber: null, raw: text }\n\ttry {\n\t\tconst parsed = JSON.parse(text.slice(jsonStart)) as { versionCode?: unknown; buildNumber?: unknown }\n\t\treturn {\n\t\t\tversionCode: parsed.versionCode != null ? String(parsed.versionCode) : null,\n\t\t\tbuildNumber: parsed.buildNumber != null ? String(parsed.buildNumber) : null,\n\t\t\traw: parsed,\n\t\t}\n\t} catch {\n\t\treturn { versionCode: null, buildNumber: null, raw: text }\n\t}\n}\n\nexport function projectRemoteVersion(\n\tctx: ReleaseKitContext,\n\t{ platform, buildProfile }: { platform: Platform | 'all'; buildProfile: string }\n): RemoteVersion {\n\tconst args = ['build:version:get', '--non-interactive', '--json', '-e', buildProfile, '-p', platform]\n\tconst result = eas(ctx, args)\n\tif (ctx.dryRun) return { versionCode: null, buildNumber: null, raw: null, dryRun: true }\n\trequireSuccess(result, 'eas build:version:get')\n\treturn parseRemoteVersion(result.stdout)\n}\n\nexport interface BuildNumberProjection {\n\tkey: 'buildNumber' | 'versionCode'\n\tcurrent: string | null\n\texpected: string | null\n}\n\nexport function expectedBuildNumber(\n\tcurrent: RemoteVersion,\n\t{ autoIncrement, platform }: { autoIncrement: boolean; platform: Platform }\n): BuildNumberProjection {\n\tconst key: BuildNumberProjection['key'] = platform === 'ios' ? 'buildNumber' : 'versionCode'\n\tconst currentValue = current[key]\n\tif (!currentValue) return { key, current: null, expected: null }\n\tif (!autoIncrement) return { key, current: currentValue, expected: currentValue }\n\tconst numeric = Number(currentValue)\n\tif (!Number.isFinite(numeric)) return { key, current: currentValue, expected: null }\n\treturn { key, current: currentValue, expected: String(numeric + 1) }\n}\n\nexport function easWhoami(ctx: ReleaseKitContext): { ok: boolean; account: string | null; raw: string } {\n\tconst result = eas(ctx, ['whoami'])\n\tif (ctx.dryRun) return { ok: true, account: null, raw: '[dry-run]' }\n\tif (result.status !== 0) return { ok: false, account: null, raw: result.stderr || result.stdout }\n\tconst account = result.stdout.trim().split('\\n').pop() ?? null\n\treturn { ok: true, account, raw: result.stdout }\n}\n\nexport function easEnvList(ctx: ReleaseKitContext, environment: string): RunResult {\n\treturn eas(ctx, ['env:list', environment, '--format', 'short'])\n}\n\nexport function easEnvListHasKey(ctx: ReleaseKitContext, environment: string, key: string): boolean {\n\tconst result = easEnvList(ctx, environment)\n\tif (ctx.dryRun) return true\n\tif (result.status !== 0) return false\n\tconst pattern = new RegExp(`(^|\\\\n)${key}(\\\\n|$)`)\n\treturn pattern.test(`${result.stdout}\\n${result.stderr}`)\n}\n\nexport function easFingerprintGenerate(ctx: ReleaseKitContext, environment: string): RunResult {\n\treturn eas(ctx, ['fingerprint:generate', '--non-interactive', '--json', '--environment', environment])\n}\n\nexport function easFingerprintCompare(ctx: ReleaseKitContext, environment: string, buildId: string): RunResult {\n\treturn eas(ctx, [\n\t\t'fingerprint:compare',\n\t\t'--non-interactive',\n\t\t'--json',\n\t\t'--build-id',\n\t\tbuildId,\n\t\t'--environment',\n\t\tenvironment,\n\t])\n}\n\nexport function easInit(ctx: ReleaseKitContext): RunResult {\n\treturn eas(ctx, ['init', '--non-interactive'])\n}\n\nexport interface EasBuildArgs {\n\tplatform: Platform\n\tbuildProfile: string\n\tlocal: boolean\n\toutput?: string\n\tenv: Record<string, string>\n}\n\nexport function easBuild(ctx: ReleaseKitContext, opts: EasBuildArgs): RunResult {\n\tconst args = ['build', '-p', opts.platform, '--profile', opts.buildProfile, '--non-interactive']\n\tif (opts.local) args.push('--local')\n\tif (opts.output) args.push('--output', opts.output)\n\treturn eas(ctx, args, { inherit: true, env: opts.env })\n}\n\nexport interface EasSubmitArgs {\n\tplatform: Platform\n\tsubmitProfile: string\n\tpath: string\n\tenv: Record<string, string>\n}\n\nexport function easSubmit(ctx: ReleaseKitContext, opts: EasSubmitArgs): RunResult {\n\tconst args = ['submit', '-p', opts.platform, '--profile', opts.submitProfile, '--path', opts.path, '--non-interactive']\n\treturn eas(ctx, args, { inherit: true, env: opts.env })\n}\n\nexport interface EasUpdateArgs {\n\tchannel: string\n\tmessage?: string\n\tplatform?: Platform | 'all'\n\tenv: Record<string, string>\n}\n\nexport function easUpdate(ctx: ReleaseKitContext, opts: EasUpdateArgs): RunResult {\n\tconst args = ['update', '--channel', opts.channel, '--non-interactive']\n\tif (opts.message) args.push('--message', opts.message)\n\tif (opts.platform) args.push('--platform', opts.platform)\n\treturn eas(ctx, args, { inherit: true, env: opts.env })\n}\n\nexport function assertEasCliAvailable(ctx: ReleaseKitContext): void {\n\tconst result = ctx.run('eas', ['--version'], { cwd: ctx.appDir })\n\tif (result.status !== 0) {\n\t\tfail('eas-cli não encontrado no PATH. Instale com `npm install -g eas-cli` e rode `eas login`.')\n\t}\n}\n","import type { ReleaseKitContext } from '../context.js'\n\nexport interface ToolchainInfo {\n\teasCli: string | null\n\tnode: string | null\n\tyarn: string | null\n\tjdk: string | null\n\txcode: string | null\n\txcodeBuild: string | null\n\tcocoapods: string | null\n\tndkHome: string | null\n\thost: string\n}\n\n/**\n * cmpVersion próprio (não `semver`) porque versões de toolchain como Java\n * \"17\", NDK \"27.1.12297006\" ou Xcode \"26.6\" não são semver válido.\n */\nexport function parseVersion(input: string | null | undefined): { major: number; minor: number; patch: number } | null {\n\tconst match = String(input ?? '')\n\t\t.replace(/^v/i, '')\n\t\t.match(/(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?/)\n\tif (!match) return null\n\treturn { major: Number(match[1]), minor: Number(match[2] || 0), patch: Number(match[3] || 0) }\n}\n\nexport function cmpVersion(a: string, b: string): number {\n\tconst pa = parseVersion(a)\n\tconst pb = parseVersion(b)\n\tif (!pa || !pb) return 0\n\tif (pa.major !== pb.major) return pa.major - pb.major\n\tif (pa.minor !== pb.minor) return pa.minor - pb.minor\n\treturn pa.patch - pb.patch\n}\n\nexport function collectToolchain(ctx: ReleaseKitContext): ToolchainInfo {\n\tconst capture = (command: string, args: string[], pick: (text: string) => string | null): string | null => {\n\t\tconst result = ctx.run(command, args, { inherit: false })\n\t\tif (result.status !== 0) return null\n\t\treturn pick(`${result.stdout}\\n${result.stderr}`)\n\t}\n\tconst firstMatch = (text: string, re: RegExp): string | null => text.match(re)?.[1] ?? null\n\n\treturn {\n\t\teasCli: capture('eas', ['--version'], (t) => firstMatch(t, /eas-cli\\/(\\d+\\.\\d+\\.\\d+)/)),\n\t\tnode: capture('node', ['-v'], (t) => firstMatch(t, /v?(\\d+\\.\\d+\\.\\d+)/)),\n\t\tyarn: capture('yarn', ['-v'], (t) => firstMatch(t, /(\\d+\\.\\d+\\.\\d+)/)),\n\t\tjdk: capture('java', ['-version'], (t) => firstMatch(t, /version \"(\\d+(?:\\.\\d+\\.\\d+)?)/)),\n\t\txcode: capture('xcodebuild', ['-version'], (t) => firstMatch(t, /Xcode (\\d+\\.\\d+)/)),\n\t\txcodeBuild: capture('xcodebuild', ['-version'], (t) => firstMatch(t, /Build version (\\S+)/)),\n\t\tcocoapods: capture('pod', ['--version'], (t) => firstMatch(t, /(\\d+\\.\\d+\\.\\d+)/)),\n\t\tndkHome: ctx.env.ANDROID_NDK_HOME || null,\n\t\thost: `${process.platform}-${process.arch}`,\n\t}\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport type { Platform, ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { fail } from '../exec/run.js'\nimport { checkGitPolicy } from '../git/policy.js'\nimport { readAppVersion } from '../project/version.js'\nimport {\n\tassertEasAuth,\n\tassertEasJsonExists,\n\tassertExpoDoctor,\n\tassertFingerprint,\n\tassertLockfileClean,\n\tassertRemoteVersion,\n\tassertSentry,\n\tassertShellClean,\n\tassertToolchain,\n\ttype Check,\n} from './checks.js'\n\nexport interface DoctorOptions {\n\tchannel?: string\n\tplatform?: Platform\n\tdeep?: boolean\n\tbuildId?: string\n\tallowToolchainDrift?: boolean\n}\n\nexport interface DoctorReport {\n\tok: boolean\n\tchecks: Check[]\n\ttoolchainDrift: boolean\n}\n\nexport function runDoctor(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: DoctorOptions): DoctorReport {\n\tassertEasJsonExists(ctx)\n\n\tconst channel = opts.channel ? channelOf(config, opts.channel) : null\n\tif (opts.platform && !config.platforms.includes(opts.platform)) {\n\t\tfail(`--platform ${opts.platform} não está em config.platforms (${config.platforms.join(', ')}).`)\n\t}\n\n\tconst checks: Check[] = []\n\tconst version = readAppVersion(ctx.appDir, config)\n\n\tchecks.push(...checkGitPolicy(ctx, config.git, { version, isProtectedChannel: Boolean(channel?.protected) }))\n\tassertShellClean(ctx, checks)\n\n\tif (config.doctor.sentry) {\n\t\tassertSentry(ctx, checks, channel)\n\t} else {\n\t\tchecks.push({ name: 'sentry', status: 'skip', message: 'desligado em doctor.sentry' })\n\t}\n\n\tassertEasAuth(ctx, checks, config.easOwner)\n\tconst toolchain = assertToolchain(ctx, checks, config, {\n\t\tplatform: opts.platform,\n\t\tallowToolchainDrift: opts.allowToolchainDrift,\n\t})\n\tassertLockfileClean(ctx, checks)\n\n\tif (channel && opts.platform) {\n\t\tassertRemoteVersion(ctx, checks, { platform: opts.platform, channel })\n\t\tassertFingerprint(ctx, checks, { channel, deep: opts.deep, buildId: opts.buildId })\n\t} else {\n\t\tchecks.push({ name: 'remote-version', status: 'skip', message: 'passe --channel e --platform para consultar versionCode/buildNumber' })\n\t\tchecks.push({ name: 'fingerprint', status: 'skip', message: 'passe --channel para avaliar runtimeVersion' })\n\t}\n\n\tassertExpoDoctor(ctx, checks, config)\n\n\tconst failed = checks.filter((item) => item.status === 'fail')\n\treturn {\n\t\tok: failed.length === 0,\n\t\tchecks,\n\t\ttoolchainDrift: toolchain.toolchainDrift,\n\t}\n}\n\nexport function printDoctorReport(report: DoctorReport, ctx: ReleaseKitContext): void {\n\tfor (const item of report.checks) {\n\t\tconst mark = item.status === 'pass' ? '✓' : item.status === 'skip' ? '·' : item.status === 'warn' ? '!' : '✗'\n\t\tctx.log.info(`${mark} ${item.name}: ${item.message}`)\n\t}\n}\n\nexport function requireDoctorPass(report: DoctorReport): void {\n\tif (report.ok) return\n\tconst failed = report.checks.filter((item) => item.status === 'fail')\n\tconst summary = failed.map((item) => `- ${item.name}: ${item.message}`).join('\\n')\n\tfail(`doctor falhou:\\n${summary}`)\n}\n","import { copyFileSync, existsSync, mkdirSync, unlinkSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport type { ReleaseKitContext } from '../context.js'\nimport { fail, formatCommand, requireSuccess } from '../exec/run.js'\nimport type { Platform, ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { readAppVersion } from '../project/version.js'\nimport { readEasJson } from '../project/detect.js'\nimport { androidBuildTypeExt } from '../eas/profiles.js'\nimport { easBuild, projectRemoteVersion } from '../eas/cli.js'\nimport { assertChannelOptIn, type ProtectedGateOptions } from './gate.js'\nimport { gitInfo, sha256File, writeMetadata, type ReleaseMetadata } from './metadata.js'\nimport { collectToolchain } from '../doctor/toolchain.js'\n\nexport interface BuildOptions extends ProtectedGateOptions {\n\tchannel: string\n\tplatform: Platform\n\tcloud?: boolean\n\toutput?: string\n\ttoolchainDrift?: boolean\n}\n\nexport interface BuildResult {\n\tdryRun?: boolean\n\tcommand?: string\n\tartifactPath?: string\n\tmetadata?: ReleaseMetadata\n\tstaging?: string\n}\n\nexport function artifactExt(ctx: ReleaseKitContext, platform: Platform, buildProfile: string): 'ipa' | 'apk' | 'aab' {\n\tif (platform === 'ios') return 'ipa'\n\tconst easJson = readEasJson(ctx.appDir)\n\tif (!easJson) fail(`eas.json não encontrado em ${ctx.appDir}.`)\n\treturn androidBuildTypeExt(easJson, buildProfile)\n}\n\nexport function buildRelease(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: BuildOptions): BuildResult {\n\tconst channel = channelOf(config, opts.channel)\n\tassertChannelOptIn(ctx, config, channel, opts)\n\n\tif (!config.platforms.includes(opts.platform)) {\n\t\tfail(`--platform ${opts.platform} não está em config.platforms.`)\n\t}\n\n\tconst ext = artifactExt(ctx, opts.platform, channel.buildProfile)\n\tconst staging = opts.output\n\t\t? resolve(ctx.repoRoot, opts.output)\n\t\t: join(ctx.releaseDir, `_building-${opts.platform}-${opts.channel}.${ext}`)\n\n\tconst local = !opts.cloud\n\tif (ctx.dryRun) {\n\t\tconst env = channel.env\n\t\tconst command = formatCommand('eas', ['build', '-p', opts.platform, '--profile', channel.buildProfile, ...(local ? ['--local'] : []), '--output', staging], env)\n\t\tctx.log.info(`[dry-run] cd ${ctx.appDir} && ${command}`)\n\t\treturn { dryRun: true, command, staging }\n\t}\n\n\tmkdirSync(dirname(staging), { recursive: true })\n\tctx.log.step(`eas build ${local ? '--local' : '(cloud)'} (${opts.platform}/${opts.channel})`)\n\trequireSuccess(\n\t\teasBuild(ctx, { platform: opts.platform, buildProfile: channel.buildProfile, local, output: local ? staging : undefined, env: channel.env }),\n\t\t'eas build'\n\t)\n\n\tif (local && !existsSync(staging)) fail(`Build concluiu sem artefato em ${staging}.`)\n\n\tconst remote = projectRemoteVersion(ctx, { platform: opts.platform, buildProfile: channel.buildProfile })\n\tconst version = readAppVersion(ctx.appDir, config)\n\tconst versionCode = remote.versionCode\n\tconst buildNumber = opts.platform === 'ios' ? remote.buildNumber : remote.versionCode\n\tconst git = gitInfo(ctx)\n\tconst dirName = `${opts.platform}-${opts.channel}-${version}-${buildNumber || 'unknown'}`\n\tconst finalDir = join(ctx.releaseDir, dirName)\n\tmkdirSync(finalDir, { recursive: true })\n\tconst finalPath = local ? join(finalDir, `app.${ext}`) : ''\n\n\tif (local && resolve(staging) !== resolve(finalPath)) {\n\t\tcopyFileSync(staging, finalPath)\n\t\tif (staging.includes('_building-')) {\n\t\t\ttry {\n\t\t\t\tunlinkSync(staging)\n\t\t\t} catch {\n\t\t\t\t// leftover em .release/ é gitignored\n\t\t\t}\n\t\t}\n\t}\n\n\tconst metadata = writeMetadata(finalDir, {\n\t\tplatform: opts.platform,\n\t\tchannel: opts.channel,\n\t\tbuildProfile: channel.buildProfile,\n\t\tversion,\n\t\tbuildNumber,\n\t\tversionCode,\n\t\tartifactPath: finalPath,\n\t\tsha256: local && existsSync(finalPath) ? sha256File(finalPath) : '',\n\t\tcommitSha: git.sha,\n\t\tbranch: git.branch,\n\t\ttag: git.tag,\n\t\tcreatedAt: new Date().toISOString(),\n\t\ttoolchain: collectToolchain(ctx),\n\t\ttoolchainDrift: Boolean(opts.toolchainDrift),\n\t})\n\n\tif (local) {\n\t\tctx.log.success(`artefato ${finalPath}`)\n\t} else {\n\t\tctx.log.success('build enviado ao EAS Build Cloud — use `eas build:list` para acompanhar e baixar o artefato.')\n\t}\n\tctx.log.success(`metadata ${join(finalDir, 'metadata.json')}`)\n\treturn { artifactPath: finalPath, metadata }\n}\n","import { fail } from '../exec/run.js'\n\ninterface EasBuildProfileRaw {\n\textends?: string\n\tandroid?: { buildType?: string }\n\tios?: { distribution?: string }\n\tenvironment?: string\n\tautoIncrement?: boolean\n\t[key: string]: unknown\n}\n\n/**\n * Resolve a cadeia de `extends` de um build profile do eas.json (o EAS\n * suporta um nível de herança). Devolve o profile com os campos herdados\n * já mesclados (o filho ganha de quem ele estende).\n */\nexport function resolveBuildProfileChain(easJson: Record<string, unknown>, profileName: string): EasBuildProfileRaw {\n\tconst build = (easJson.build as Record<string, EasBuildProfileRaw> | undefined) ?? {}\n\tconst profile = build[profileName]\n\tif (!profile) fail(`build profile \"${profileName}\" não existe no eas.json.`)\n\n\tconst chain: EasBuildProfileRaw[] = [profile]\n\tlet cursor: EasBuildProfileRaw | undefined = profile\n\tconst seen = new Set([profileName])\n\twhile (cursor?.extends) {\n\t\tconst parentName: string = cursor.extends\n\t\tif (seen.has(parentName)) break\n\t\tseen.add(parentName)\n\t\tconst parent: EasBuildProfileRaw | undefined = build[parentName]\n\t\tif (!parent) break\n\t\tchain.push(parent)\n\t\tcursor = parent\n\t}\n\n\t// merge do mais genérico (base) pro mais específico\n\tconst merged: EasBuildProfileRaw = {}\n\tfor (const step of chain.slice().reverse()) {\n\t\tObject.assign(merged, step)\n\t\tif (step.android) merged.android = { ...merged.android, ...step.android }\n\t\tif (step.ios) merged.ios = { ...merged.ios, ...step.ios }\n\t}\n\treturn merged\n}\n\nexport function androidBuildTypeExt(easJson: Record<string, unknown>, profileName: string): 'apk' | 'aab' {\n\tconst resolved = resolveBuildProfileChain(easJson, profileName)\n\treturn resolved.android?.buildType === 'apk' ? 'apk' : 'aab'\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport { fail } from '../exec/run.js'\nimport type { ChannelConfig, ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { readAppVersion } from '../project/version.js'\n\nexport interface ProtectedGateOptions {\n\tiKnowThisIsProduction?: boolean\n\tconfirmVersion?: string\n}\n\n/**\n * Gate fail-closed para canais `protected: true`: exige\n * `--i-know-this-is-production` (não-interativo) ou confirmação digitando a\n * versão exata. Sem isso, nenhum comando toca um canal protegido — nem\n * build, nem submit, nem update OTA.\n */\nexport function assertChannelOptIn(\n\tctx: ReleaseKitContext,\n\tconfig: ReleaseKitConfig,\n\tchannel: ChannelConfig,\n\topts: ProtectedGateOptions\n): void {\n\tif (!channel.protected) return\n\tif (opts.iKnowThisIsProduction) return\n\tconst version = readAppVersion(ctx.appDir, config)\n\tif (opts.confirmVersion && opts.confirmVersion.trim() === version) return\n\tfail(\n\t\t`canal protegido: passe --i-know-this-is-production (não-interativo) ou confirme digitando a versão exata (${version}). \\`release-kit\\` sem argumentos nunca resolve para um canal protegido.`\n\t)\n}\n\n/**\n * No menu interativo/TTY, pede para digitar a versão em vez de exigir a\n * flag. Não é chamado em modo não-interativo — lá o gate só aceita a flag.\n */\nexport async function confirmProtectedChannelVersion(\n\tctx: ReleaseKitContext,\n\tconfig: ReleaseKitConfig,\n\tchannelName: string\n): Promise<string> {\n\tconst channel = channelOf(config, channelName)\n\tif (!channel.protected) return ''\n\tconst version = readAppVersion(ctx.appDir, config)\n\tif (!ctx.confirm) return ''\n\tctx.log.warn(`canal \"${channelName}\" é protegido — gera binário/OTA de produção.`)\n\tconst answer = await ctx.confirm(`Digite a versão exatamente (${version}) para continuar: `)\n\treturn String(answer || '').trim()\n}\n","import { createHash } from 'node:crypto'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport type { ReleaseKitContext } from '../context.js'\nimport { fail } from '../exec/run.js'\nimport { git } from '../git/policy.js'\nimport type { Platform } from '../config/schema.js'\nimport type { ToolchainInfo } from '../doctor/toolchain.js'\n\nexport interface ReleaseMetadata {\n\tplatform: Platform\n\tchannel: string\n\tbuildProfile: string\n\tversion: string\n\tbuildNumber: string | null\n\tversionCode: string | null\n\tartifactPath: string\n\tsha256: string\n\tcommitSha: string\n\tbranch: string\n\ttag: string\n\tcreatedAt: string\n\ttoolchain: ToolchainInfo | null\n\ttoolchainDrift: boolean\n}\n\nexport function sha256File(path: string): string {\n\treturn createHash('sha256').update(readFileSync(path)).digest('hex')\n}\n\nexport interface GitInfo {\n\tsha: string\n\tbranch: string\n\ttag: string\n}\n\nexport function gitInfo(ctx: ReleaseKitContext): GitInfo {\n\tconst sha = git(ctx, ['rev-parse', 'HEAD']).stdout.trim()\n\tconst branch = git(ctx, ['rev-parse', '--abbrev-ref', 'HEAD']).stdout.trim()\n\tconst tagResult = git(ctx, ['tag', '--points-at', 'HEAD'], { allowFail: true })\n\tconst tag =\n\t\t(tagResult.stdout || '')\n\t\t\t.split('\\n')\n\t\t\t.map((line) => line.trim())\n\t\t\t.find((line) => /^v\\d/.test(line)) || ''\n\treturn { sha, branch, tag }\n}\n\nexport function writeMetadata(dir: string, payload: Omit<ReleaseMetadata, never>): ReleaseMetadata {\n\tmkdirSync(dir, { recursive: true })\n\twriteFileSync(join(dir, 'metadata.json'), `${JSON.stringify(payload, null, 2)}\\n`)\n\treturn payload\n}\n\nexport interface MetadataEntry {\n\tdir: string\n\tmetaPath: string\n\tmetadata: ReleaseMetadata\n\tcreatedAt: string\n}\n\nexport function findLatestMetadata(releaseDir: string, { channel, platform }: { channel?: string; platform?: Platform } = {}): MetadataEntry {\n\tif (!existsSync(releaseDir)) fail(`Nenhum artefato em ${releaseDir}. Rode \\`release-kit build\\` primeiro.`)\n\tconst entries = readdirSync(releaseDir)\n\t\t.map((name): MetadataEntry | null => {\n\t\t\tconst dir = join(releaseDir, name)\n\t\t\tconst metaPath = join(dir, 'metadata.json')\n\t\t\tif (!statSync(dir).isDirectory() || !existsSync(metaPath)) return null\n\t\t\tconst metadata = JSON.parse(readFileSync(metaPath, 'utf8')) as ReleaseMetadata\n\t\t\tif (platform && metadata.platform !== platform) return null\n\t\t\tif (channel && metadata.channel !== channel) return null\n\t\t\treturn { dir, metaPath, metadata, createdAt: metadata.createdAt || '' }\n\t\t})\n\t\t.filter((entry): entry is MetadataEntry => entry !== null)\n\t\t.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n\tconst [first] = entries\n\tif (!first) {\n\t\tfail(`Nenhum metadata.json${platform ? ` para ${platform}` : ''}${channel ? ` (canal ${channel})` : ''} em ${releaseDir}.`)\n\t}\n\treturn first\n}\n","import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { ReleaseKitContext } from '../context.js'\nimport { fail, formatCommand, requireSuccess } from '../exec/run.js'\nimport type { Platform, ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { easSubmit } from '../eas/cli.js'\nimport { assertChannelOptIn, type ProtectedGateOptions } from './gate.js'\nimport { findLatestMetadata, type ReleaseMetadata } from './metadata.js'\n\nexport interface SubmitOptions extends ProtectedGateOptions {\n\tchannel: string\n\tplatform?: Platform\n\t/** true = usa o metadata.json mais recente gerado por `build`. */\n\tlatest?: boolean\n\t/** artefato avulso (.aab/.ipa), sem passar por `build`. */\n\tpath?: string\n}\n\nexport interface SubmitResult {\n\tdryRun?: boolean\n\tcommand?: string\n\tsubmitProfile: string\n\tartifactPath: string\n}\n\nexport function inferPlatformFromArtifact(artifactPath: string): Platform {\n\tconst lower = artifactPath.toLowerCase()\n\tif (lower.endsWith('.apk')) {\n\t\tfail('Submit Android exige AAB. O profile de sideload não vai à loja; gere o binário com um profile de release/production.')\n\t}\n\tif (lower.endsWith('.aab')) return 'android'\n\tif (lower.endsWith('.ipa')) return 'ios'\n\tfail('submit --path exige um arquivo .aab ou .ipa.')\n}\n\nexport function submitRelease(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: SubmitOptions): SubmitResult {\n\tconst channel = channelOf(config, opts.channel)\n\tassertChannelOptIn(ctx, config, channel, opts)\n\tif (!channel.store) {\n\t\tfail(`canal \"${opts.channel}\" não envia à loja (store: false).`)\n\t}\n\tconst submitProfile = channel.submitProfile ?? channel.buildProfile\n\n\tlet artifactPath: string\n\tlet platform: Platform\n\n\tif (opts.path) {\n\t\tartifactPath = resolve(ctx.repoRoot, opts.path)\n\t\tif (!existsSync(artifactPath)) fail(`Artefato não encontrado: ${artifactPath}.`)\n\t\tplatform = inferPlatformFromArtifact(artifactPath)\n\t\tif (opts.platform && opts.platform !== platform) {\n\t\t\tfail(`--platform ${opts.platform} não corresponde ao arquivo (${platform}).`)\n\t\t}\n\t} else {\n\t\tconst entry = findLatestMetadata(ctx.releaseDir, { channel: opts.channel, platform: opts.platform })\n\t\tconst metadata = entry.metadata as ReleaseMetadata\n\t\tartifactPath = metadata.artifactPath\n\t\tplatform = metadata.platform\n\t\tif (!artifactPath || !existsSync(artifactPath)) {\n\t\t\tfail(`Artefato não encontrado: ${artifactPath || '(ausente no metadata)'}. Builds na nuvem não têm artefato local — use --path após baixar.`)\n\t\t}\n\t}\n\n\tif (platform === 'android' && !artifactPath.toLowerCase().endsWith('.aab')) {\n\t\tfail('Submit Android exige AAB.')\n\t}\n\n\tif (ctx.dryRun) {\n\t\tconst command = formatCommand('eas', ['submit', '-p', platform, '--profile', submitProfile, '--path', artifactPath], channel.env)\n\t\tctx.log.info(`[dry-run] cd ${ctx.appDir} && ${command}`)\n\t\treturn { dryRun: true, command, submitProfile, artifactPath }\n\t}\n\n\tctx.log.step(`eas submit --path (${platform}/${submitProfile})`)\n\trequireSuccess(easSubmit(ctx, { platform, submitProfile, path: artifactPath, env: channel.env }), 'eas submit')\n\treturn { submitProfile, artifactPath }\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport type { ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { fail } from '../exec/run.js'\nimport { requireDoctorPass, runDoctor } from '../doctor/run.js'\nimport { buildRelease, type BuildOptions } from './build.js'\nimport { submitRelease, type SubmitResult } from './submit.js'\n\nexport interface ShipOptions extends BuildOptions {\n\tskipDoctor?: boolean\n\tallowToolchainDrift?: boolean\n}\n\nexport interface ShipResult {\n\tdryRun?: boolean\n\tartifactPath?: string\n\tsubmit?: SubmitResult\n}\n\nexport function shipRelease(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: ShipOptions): ShipResult {\n\tconst channel = channelOf(config, opts.channel)\n\tif (!channel.store) {\n\t\tfail(`canal \"${opts.channel}\" não envia à loja (store: false). Use \\`release-kit build\\` direto para gerar o artefato de sideload.`)\n\t}\n\n\tlet toolchainDrift = opts.toolchainDrift\n\tif (!opts.skipDoctor) {\n\t\tconst report = runDoctor(ctx, config, {\n\t\t\tchannel: opts.channel,\n\t\t\tplatform: opts.platform,\n\t\t\tallowToolchainDrift: opts.allowToolchainDrift,\n\t\t})\n\t\trequireDoctorPass(report)\n\t\ttoolchainDrift = report.toolchainDrift\n\t}\n\n\tconst built = buildRelease(ctx, config, { ...opts, toolchainDrift })\n\tif (ctx.dryRun) return { dryRun: true, artifactPath: built.artifactPath }\n\n\tconst submitted = submitRelease(ctx, config, {\n\t\tchannel: opts.channel,\n\t\tplatform: opts.platform,\n\t\tlatest: true,\n\t\tiKnowThisIsProduction: opts.iKnowThisIsProduction,\n\t\tconfirmVersion: opts.confirmVersion,\n\t})\n\treturn { artifactPath: built.artifactPath, submit: submitted }\n}\n","import { relative } from 'node:path'\nimport type { ReleaseKitContext } from '../context.js'\nimport type { ReleaseKitConfig } from '../config/schema.js'\nimport { fail, requireSuccess } from '../exec/run.js'\nimport { git, isWorkingTreeClean, renderTag } from '../git/policy.js'\nimport { nextVersion, readAppVersion, writeAppVersion, type VersionBump } from '../project/version.js'\n\nexport interface BumpVersionOptions {\n\tbump: VersionBump\n\tpush?: boolean\n}\n\nexport interface BumpVersionResult {\n\tfrom: string\n\tto: string\n\ttag: string\n\tdryRun?: boolean\n}\n\nexport function bumpVersion(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: BumpVersionOptions): BumpVersionResult {\n\tif (!isWorkingTreeClean(ctx)) {\n\t\tfail('working tree suja. Commit ou descarte as mudanças antes de rodar `release-kit version`.')\n\t}\n\tconst current = readAppVersion(ctx.appDir, config)\n\tconst next = nextVersion(current, opts.bump)\n\tconst tag = renderTag(config.git.tagFormat, next)\n\n\tif (ctx.dryRun) {\n\t\tctx.log.info(`[dry-run] ${current} → ${next} (tag ${tag})`)\n\t\treturn { from: current, to: next, tag, dryRun: true }\n\t}\n\n\tconst path = writeAppVersion(ctx.appDir, config, next)\n\tconst relPath = relative(ctx.repoRoot, path)\n\tgit(ctx, ['add', relPath])\n\tgit(ctx, ['commit', '-m', `chore(release): ${tag}`])\n\tgit(ctx, ['tag', tag])\n\tctx.log.success(`${current} → ${next} (commit + tag ${tag})`)\n\n\tif (opts.push) {\n\t\trequireSuccess(git(ctx, ['push', config.git.remote, config.git.releaseBranch]), 'git push')\n\t\trequireSuccess(git(ctx, ['push', config.git.remote, tag]), 'git push tag')\n\t\tctx.log.success(`push ${config.git.remote} ${config.git.releaseBranch} + tag ${tag}`)\n\t}\n\n\treturn { from: current, to: next, tag }\n}\n","import { existsSync } from 'node:fs'\nimport type { ReleaseKitContext } from '../context.js'\nimport type { ReleaseKitConfig } from '../config/schema.js'\nimport { readAppVersion } from '../project/version.js'\nimport { commitsSinceLastTag } from '../git/commits.js'\nimport { draftNotes } from '../notes/draft.js'\nimport { openInEditor } from '../notes/editor.js'\nimport { assertNotesWithinLimit, type NotesTarget } from '../notes/limits.js'\nimport { notesFilePath, readNotesFile, writeNotesFile } from '../notes/paths.js'\n\nexport interface NotesOptions {\n\tversion?: string\n\t/** Reabre no editor mesmo se o arquivo já existir. */\n\tedit?: boolean\n\tskipEditor?: boolean\n}\n\nexport interface NotesResult {\n\tversion: string\n\tfiles: Array<{ path: string; target: NotesTarget; locale: string }>\n}\n\nfunction targetsFor(config: ReleaseKitConfig): NotesTarget[] {\n\tconst targets: NotesTarget[] = []\n\tif (config.platforms.includes('ios')) targets.push('ios')\n\tif (config.platforms.includes('android')) targets.push('play')\n\treturn targets\n}\n\n/**\n * Gera (se faltar) e abre para edição as notas de cada locale/loja. Não\n * publica nada — só prepara os arquivos que `promote`/`review`/`notes`\n * (comando de loja) vão ler depois.\n */\nexport function draftAndEditNotes(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: NotesOptions): NotesResult {\n\tconst version = opts.version ?? readAppVersion(ctx.appDir, config)\n\tconst commits = commitsSinceLastTag(ctx, config.git.tagFormat)\n\tconst targets = targetsFor(config)\n\tconst files: NotesResult['files'] = []\n\n\tfor (const locale of config.locales) {\n\t\tfor (const target of targets) {\n\t\t\tconst path = notesFilePath(ctx.appDir, config.notesDir, version, locale, target)\n\t\t\tconst isNew = !existsSync(path)\n\t\t\tif (isNew) {\n\t\t\t\twriteNotesFile(path, draftNotes(commits, version))\n\t\t\t\tctx.log.step(`rascunho criado: ${path}`)\n\t\t\t}\n\t\t\tif (!opts.skipEditor && (isNew || opts.edit)) {\n\t\t\t\topenInEditor(ctx, path)\n\t\t\t}\n\t\t\tconst text = readNotesFile(path)\n\t\t\tassertNotesWithinLimit(text, target, locale)\n\t\t\tfiles.push({ path, target, locale })\n\t\t}\n\t}\n\n\treturn { version, files }\n}\n","import type { CommitEntry } from '../git/commits.js'\nimport { userFacingCommits } from '../git/commits.js'\n\n/**\n * Rascunho a partir dos commits (feat/fix) desde a última tag. Não traduz\n * nem reescreve em linguagem de usuário — é ponto de partida para editar\n * no $EDITOR, não o texto final.\n */\nexport function draftNotes(commits: CommitEntry[], version: string): string {\n\tconst facing = userFacingCommits(commits)\n\tif (facing.length === 0) {\n\t\treturn `Novidades da versão ${version}\\n\\n(sem commits feat/fix desde a última tag — escreva as notas manualmente)\\n`\n\t}\n\tconst features = facing.filter((c) => c.type === 'feat')\n\tconst fixes = facing.filter((c) => c.type === 'fix')\n\tconst lines: string[] = [`Novidades da versão ${version}`, '']\n\tif (features.length) {\n\t\tlines.push('Novidades:')\n\t\tfor (const commit of features) lines.push(`- ${capitalize(commit.description)}`)\n\t\tlines.push('')\n\t}\n\tif (fixes.length) {\n\t\tlines.push('Correções:')\n\t\tfor (const commit of fixes) lines.push(`- ${capitalize(commit.description)}`)\n\t\tlines.push('')\n\t}\n\tlines.push('# Revise este rascunho antes de publicar — ele vem direto dos commits (feat/fix) e não foi reescrito em linguagem de usuário.')\n\treturn lines.join('\\n')\n}\n\nfunction capitalize(text: string): string {\n\tif (!text) return text\n\treturn text[0]!.toUpperCase() + text.slice(1)\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport { requireSuccess } from '../exec/run.js'\n\nfunction defaultEditor(): string {\n\tif (process.platform === 'win32') return 'notepad'\n\treturn 'nano'\n}\n\n/** Abre `path` no $EDITOR (com fallback por SO) e bloqueia até o editor fechar. */\nexport function openInEditor(ctx: ReleaseKitContext, path: string): void {\n\tconst editor = ctx.env.EDITOR || ctx.env.VISUAL || defaultEditor()\n\tconst [command, ...args] = editor.split(' ')\n\tif (!command) return\n\trequireSuccess(ctx.run(command, [...args, path], { inherit: true }), `${editor} ${path}`)\n}\n","import { fail } from '../exec/run.js'\n\nexport const PLAY_NOTES_MAX = 500\nexport const APPLE_WHATS_NEW_MAX = 4000\n\nexport type NotesTarget = 'ios' | 'play'\n\nexport function notesMaxFor(target: NotesTarget): number {\n\treturn target === 'play' ? PLAY_NOTES_MAX : APPLE_WHATS_NEW_MAX\n}\n\nexport function assertNotesWithinLimit(text: string, target: NotesTarget, locale: string): void {\n\tconst max = notesMaxFor(target)\n\tif (text.length > max) {\n\t\tfail(`Notas ${target} (${locale}) têm ${text.length} caracteres (máximo ${max}).`)\n\t}\n\tif (!text.trim()) {\n\t\tfail(`Notas ${target} (${locale}) estão vazias.`)\n\t}\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { fail } from '../exec/run.js'\nimport type { NotesTarget } from './limits.js'\n\nexport function notesDirFor(appDir: string, notesDir: string, version: string): string {\n\treturn join(appDir, notesDir, version)\n}\n\nexport function notesFilePath(appDir: string, notesDir: string, version: string, locale: string, target: NotesTarget): string {\n\treturn join(notesDirFor(appDir, notesDir, version), `${locale}.${target}.txt`)\n}\n\nexport function readNotesFile(path: string): string {\n\tif (!existsSync(path)) fail(`Notas não encontradas: ${path}. Rode \\`release-kit notes\\` primeiro.`)\n\tconst text = readFileSync(path, 'utf8').trim()\n\tif (!text) fail(`Notas vazias em ${path}.`)\n\treturn text\n}\n\nexport function writeNotesFile(path: string, text: string): void {\n\tmkdirSync(join(path, '..'), { recursive: true })\n\twriteFileSync(path, `${text.trim()}\\n`)\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { fail } from '../exec/run.js'\nimport { resolveFileCredential } from '../env/store.js'\nimport { AppStoreConnectClient } from './apple/client.js'\nimport { AndroidPublisherClient } from './google/client.js'\nimport { parseServiceAccountJson } from './google/auth.js'\n\nexport interface Cleanup {\n\tcleanup: () => void\n}\n\nexport function createAppleClient(env: NodeJS.ProcessEnv): AppStoreConnectClient & Cleanup {\n\tconst keyId = env.ASC_KEY_ID\n\tconst issuerId = env.ASC_ISSUER_ID\n\tif (!keyId || !issuerId) {\n\t\tfail('Credenciais App Store Connect ausentes: ASC_KEY_ID, ASC_ISSUER_ID. Rode `release-kit credentials apple`.')\n\t}\n\tconst resolved = resolveFileCredential(env, 'ASC_KEY_PATH', 'ASC_KEY_P8_CONTENT', 'AuthKey.p8')\n\tif (!resolved) {\n\t\tfail('Credencial ASC_KEY_PATH (ou ASC_KEY_P8_CONTENT em CI) ausente. Rode `release-kit credentials apple`.')\n\t}\n\tif (!existsSync(resolved.path)) fail(`ASC_KEY_PATH não existe: ${resolved.path}`)\n\tconst privateKeyPem = readFileSync(resolved.path, 'utf8')\n\tconst client = new AppStoreConnectClient({ credentials: { keyId, issuerId, privateKeyPem } })\n\treturn Object.assign(client, { cleanup: resolved.cleanup })\n}\n\nexport function createGoogleClient(env: NodeJS.ProcessEnv): AndroidPublisherClient & Cleanup {\n\tconst resolved = resolveFileCredential(env, 'GOOGLE_PLAY_JSON_KEY', 'GOOGLE_PLAY_JSON_CONTENT', 'play-service-account.json')\n\tif (!resolved) {\n\t\tfail(\n\t\t\t'Credencial GOOGLE_PLAY_JSON_KEY (ou GOOGLE_PLAY_JSON_CONTENT em CI) ausente. Rode `release-kit credentials google`.'\n\t\t)\n\t}\n\tif (!existsSync(resolved.path)) fail(`GOOGLE_PLAY_JSON_KEY não existe: ${resolved.path}`)\n\tconst account = parseServiceAccountJson(readFileSync(resolved.path, 'utf8'))\n\tconst client = new AndroidPublisherClient({ account })\n\treturn Object.assign(client, { cleanup: resolved.cleanup })\n}\n","import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport { homedir, tmpdir } from 'node:os'\nimport { basename, join } from 'node:path'\nimport dotenv from 'dotenv'\n\nexport const ENV_FILENAME = '.env.release'\n\nexport function envPath(repoRoot: string): string {\n\treturn join(repoRoot, ENV_FILENAME)\n}\n\nexport function readEnvFile(repoRoot: string): Record<string, string> {\n\tconst path = envPath(repoRoot)\n\tif (!existsSync(path)) return {}\n\treturn dotenv.parse(readFileSync(path, 'utf8'))\n}\n\n/** Faz merge com o que já existe no arquivo — nunca apaga chaves não tocadas. */\nexport function writeEnvFile(repoRoot: string, updates: Record<string, string | undefined>): string {\n\tconst current = readEnvFile(repoRoot)\n\tconst merged: Record<string, string> = { ...current }\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\tif (value === undefined) continue\n\t\tmerged[key] = value\n\t}\n\tconst body = Object.entries(merged)\n\t\t.map(([key, value]) => `${key}=${escapeEnvValue(value)}`)\n\t\t.join('\\n')\n\tconst path = envPath(repoRoot)\n\twriteFileSync(path, `${body}\\n`)\n\ttry {\n\t\tchmodSync(path, 0o600)\n\t} catch {\n\t\t// best-effort — algumas plataformas (Windows/FAT) não suportam chmod\n\t}\n\treturn path\n}\n\nfunction escapeEnvValue(value: string): string {\n\tif (/[\\s#\"'$]/.test(value)) return `\"${value.replace(/\"/g, '\\\\\"')}\"`\n\treturn value\n}\n\n/** Diretório fora do repo onde ficam os arquivos de credencial (.p8, .json da SA). */\nexport function credentialsDir(slug: string): string {\n\treturn join(homedir(), '.release-kit', slug)\n}\n\n/**\n * Copia um arquivo de credencial para fora do repositório, com permissão\n * 600. Retorna o path final — é o que vai para o .env.release.\n */\nexport function storeCredentialFile(slug: string, sourcePath: string, filename?: string): string {\n\tconst dir = credentialsDir(slug)\n\tmkdirSync(dir, { recursive: true, mode: 0o700 })\n\tconst destName = filename ?? basename(sourcePath)\n\tconst dest = join(dir, destName)\n\tcopyFileSync(sourcePath, dest)\n\ttry {\n\t\tchmodSync(dest, 0o600)\n\t} catch {\n\t\t// best-effort fora do macOS/Linux\n\t}\n\treturn dest\n}\n\nexport interface MaterializedSecret {\n\tpath: string\n\tcleanup: () => void\n}\n\n/**\n * Em CI a credencial vem como conteúdo em uma env var (*_CONTENT), não como\n * arquivo no disco. Grava um arquivo temporário com permissão 600 e devolve\n * uma função de cleanup para apagar depois de usar.\n */\nexport function materializeSecretContent(content: string, filename: string): MaterializedSecret {\n\tconst dir = mkdtempSync(join(tmpdir(), 'release-kit-'))\n\tconst path = join(dir, filename)\n\twriteFileSync(path, content)\n\ttry {\n\t\tchmodSync(path, 0o600)\n\t} catch {\n\t\t// best-effort\n\t}\n\treturn {\n\t\tpath,\n\t\tcleanup: () => rmSync(dir, { recursive: true, force: true }),\n\t}\n}\n\n/**\n * Resolve uma credencial de arquivo a partir de duas env vars possíveis:\n * `<KEY>_PATH` (path direto) ou `<KEY>_CONTENT` (conteúdo, materializado em\n * um temp file — uso típico em CI/secrets). Se nenhuma existir, retorna null.\n */\nexport function resolveFileCredential(\n\tenv: NodeJS.ProcessEnv,\n\tpathKey: string,\n\tcontentKey: string,\n\tfilename: string\n): { path: string; cleanup: () => void } | null {\n\tconst directPath = env[pathKey]\n\tif (directPath) return { path: directPath, cleanup: () => {} }\n\tconst content = env[contentKey]\n\tif (content) return materializeSecretContent(content, filename)\n\treturn null\n}\n","import { createPrivateKey, createSign } from 'node:crypto'\n\nexport interface AppStoreConnectCredentials {\n\tkeyId: string\n\tissuerId: string\n\t/** Conteúdo do arquivo .p8 (PEM), não o path. */\n\tprivateKeyPem: string\n}\n\nfunction base64url(input: Buffer | string): string {\n\tconst buffer = typeof input === 'string' ? Buffer.from(input) : input\n\treturn buffer.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\n/**\n * JWT ES256 exigido pela App Store Connect API. Sem SDK (Spaceship) —\n * assinatura via node:crypto puro, então funciona igual em qualquer SO.\n * Expira em 20 minutos (o máximo aceito pela Apple); gerar um novo por\n * chamada evita lidar com relógio/cache entre processos.\n */\nexport function createAppStoreConnectToken(credentials: AppStoreConnectCredentials, now: number = Date.now()): string {\n\tconst iat = Math.floor(now / 1000)\n\tconst exp = iat + 19 * 60\n\n\tconst header = base64url(JSON.stringify({ alg: 'ES256', kid: credentials.keyId, typ: 'JWT' }))\n\tconst payload = base64url(\n\t\tJSON.stringify({\n\t\t\tiss: credentials.issuerId,\n\t\t\tiat,\n\t\t\texp,\n\t\t\taud: 'appstoreconnect-v1',\n\t\t})\n\t)\n\tconst signingInput = `${header}.${payload}`\n\n\tconst key = createPrivateKey({ key: credentials.privateKeyPem, format: 'pem' })\n\tconst signer = createSign('SHA256')\n\tsigner.update(signingInput)\n\tsigner.end()\n\t// dsaEncoding \"ieee-p1363\" devolve r||s cru (o formato que JWS ES256 exige),\n\t// em vez do DER que createSign produz por padrão.\n\tconst signature = signer.sign({ key, dsaEncoding: 'ieee-p1363' })\n\n\treturn `${signingInput}.${base64url(signature)}`\n}\n","import { fail } from '../../exec/run.js'\nimport { createAppStoreConnectToken, type AppStoreConnectCredentials } from './auth.js'\n\nexport const APP_STORE_CONNECT_BASE = 'https://api.appstoreconnect.apple.com/v1'\n\nexport type FetchLike = typeof fetch\n\nexport interface AppStoreConnectClientOptions {\n\tcredentials: AppStoreConnectCredentials\n\tbaseUrl?: string\n\tfetchImpl?: FetchLike\n}\n\nexport interface JsonApiDocument<TAttributes = Record<string, unknown>> {\n\tdata: {\n\t\tid: string\n\t\ttype: string\n\t\tattributes: TAttributes\n\t\trelationships?: Record<string, unknown>\n\t}\n}\n\nexport interface JsonApiCollection<TAttributes = Record<string, unknown>> {\n\tdata: Array<{\n\t\tid: string\n\t\ttype: string\n\t\tattributes: TAttributes\n\t\trelationships?: Record<string, unknown>\n\t}>\n\tlinks?: { next?: string }\n}\n\n/**\n * Cliente fino para a App Store Connect API. Sem SDK — todo o resto do\n * módulo `stores/apple` fala só com os métodos abaixo, então trocar de HTTP\n * client ou mockar em teste é local a este arquivo.\n */\nexport class AppStoreConnectClient {\n\tprivate readonly credentials: AppStoreConnectCredentials\n\tprivate readonly baseUrl: string\n\tprivate readonly fetchImpl: FetchLike\n\n\tconstructor(options: AppStoreConnectClientOptions) {\n\t\tthis.credentials = options.credentials\n\t\tthis.baseUrl = options.baseUrl ?? APP_STORE_CONNECT_BASE\n\t\tthis.fetchImpl = options.fetchImpl ?? fetch\n\t}\n\n\tprivate token(): string {\n\t\treturn createAppStoreConnectToken(this.credentials)\n\t}\n\n\tasync request<T>(method: string, path: string, body?: unknown): Promise<T> {\n\t\tconst url = path.startsWith('http') ? path : `${this.baseUrl}${path}`\n\t\tconst response = await this.fetchImpl(url, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${this.token()}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t\tbody: body ? JSON.stringify(body) : undefined,\n\t\t})\n\t\tconst text = await response.text()\n\t\tif (!response.ok) {\n\t\t\tfail(`App Store Connect API ${method} ${path} → ${response.status}\\n${text}`)\n\t\t}\n\t\tif (!text) return undefined as T\n\t\treturn JSON.parse(text) as T\n\t}\n\n\tget<T>(path: string): Promise<T> {\n\t\treturn this.request<T>('GET', path)\n\t}\n\n\tpost<T>(path: string, body: unknown): Promise<T> {\n\t\treturn this.request<T>('POST', path, body)\n\t}\n\n\tpatch<T>(path: string, body: unknown): Promise<T> {\n\t\treturn this.request<T>('PATCH', path, body)\n\t}\n}\n","import { createSign } from 'node:crypto'\nimport { fail } from '../../exec/run.js'\n\nexport interface GoogleServiceAccount {\n\tclient_email: string\n\tprivate_key: string\n\t[key: string]: unknown\n}\n\nexport function parseServiceAccountJson(raw: string): GoogleServiceAccount {\n\tlet parsed: unknown\n\ttry {\n\t\tparsed = JSON.parse(raw)\n\t} catch (error) {\n\t\tfail(`JSON da service account inválido: ${(error as Error).message}`)\n\t}\n\tconst account = parsed as Partial<GoogleServiceAccount>\n\tif (!account.client_email || !account.private_key) {\n\t\tfail('JSON da service account sem client_email/private_key.')\n\t}\n\treturn account as GoogleServiceAccount\n}\n\nfunction base64url(input: Buffer | string): string {\n\tconst buffer = typeof input === 'string' ? Buffer.from(input) : input\n\treturn buffer.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nconst TOKEN_URL = 'https://oauth2.googleapis.com/token'\nconst ANDROID_PUBLISHER_SCOPE = 'https://www.googleapis.com/auth/androidpublisher'\n\n/**\n * Fluxo OAuth de service account (JWT bearer, RFC 7523), sem\n * `google-auth-library`: assina um JWT RS256 com a private_key da SA e\n * troca por um access_token de curta duração. node:crypto puro.\n */\nexport async function fetchAccessToken(\n\taccount: GoogleServiceAccount,\n\tfetchImpl: typeof fetch = fetch,\n\tnow: number = Date.now()\n): Promise<string> {\n\tconst iat = Math.floor(now / 1000)\n\tconst exp = iat + 60 * 60\n\n\tconst header = base64url(JSON.stringify({ alg: 'RS256', typ: 'JWT' }))\n\tconst payload = base64url(\n\t\tJSON.stringify({\n\t\t\tiss: account.client_email,\n\t\t\tscope: ANDROID_PUBLISHER_SCOPE,\n\t\t\taud: TOKEN_URL,\n\t\t\tiat,\n\t\t\texp,\n\t\t})\n\t)\n\tconst signingInput = `${header}.${payload}`\n\tconst signer = createSign('RSA-SHA256')\n\tsigner.update(signingInput)\n\tsigner.end()\n\tconst signature = signer.sign(account.private_key)\n\tconst assertion = `${signingInput}.${base64url(signature)}`\n\n\tconst response = await fetchImpl(TOKEN_URL, {\n\t\tmethod: 'POST',\n\t\theaders: { 'Content-Type': 'application/x-www-form-urlencoded' },\n\t\tbody: new URLSearchParams({\n\t\t\tgrant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',\n\t\t\tassertion,\n\t\t}).toString(),\n\t})\n\tconst text = await response.text()\n\tif (!response.ok) fail(`Falha ao obter access_token do Google: ${response.status}\\n${text}`)\n\tconst json = JSON.parse(text) as { access_token?: string }\n\tif (!json.access_token) fail('Resposta do Google sem access_token.')\n\treturn json.access_token\n}\n","import { fail } from '../../exec/run.js'\nimport { fetchAccessToken, type GoogleServiceAccount } from './auth.js'\n\nexport const ANDROID_PUBLISHER_BASE = 'https://androidpublisher.googleapis.com/androidpublisher/v3'\n\nexport type FetchLike = typeof fetch\n\nexport interface AndroidPublisherClientOptions {\n\taccount: GoogleServiceAccount\n\tbaseUrl?: string\n\tfetchImpl?: FetchLike\n}\n\n/** Cliente fino para a Android Publisher API v3 — sem googleapis/SDK. */\nexport class AndroidPublisherClient {\n\tprivate readonly account: GoogleServiceAccount\n\tprivate readonly baseUrl: string\n\tprivate readonly fetchImpl: FetchLike\n\tprivate cachedToken: string | null = null\n\n\tconstructor(options: AndroidPublisherClientOptions) {\n\t\tthis.account = options.account\n\t\tthis.baseUrl = options.baseUrl ?? ANDROID_PUBLISHER_BASE\n\t\tthis.fetchImpl = options.fetchImpl ?? fetch\n\t}\n\n\tprivate async token(): Promise<string> {\n\t\tif (!this.cachedToken) {\n\t\t\tthis.cachedToken = await fetchAccessToken(this.account, this.fetchImpl)\n\t\t}\n\t\treturn this.cachedToken\n\t}\n\n\tasync request<T>(method: string, path: string, body?: unknown): Promise<T> {\n\t\tconst token = await this.token()\n\t\tconst response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t\tbody: body ? JSON.stringify(body) : undefined,\n\t\t})\n\t\tconst text = await response.text()\n\t\tif (!response.ok) fail(`Android Publisher API ${method} ${path} → ${response.status}\\n${text}`)\n\t\tif (!text) return undefined as T\n\t\treturn JSON.parse(text) as T\n\t}\n\n\tget<T>(path: string): Promise<T> {\n\t\treturn this.request<T>('GET', path)\n\t}\n\n\tput<T>(path: string, body: unknown): Promise<T> {\n\t\treturn this.request<T>('PUT', path, body)\n\t}\n\n\tpost<T>(path: string, body?: unknown): Promise<T> {\n\t\treturn this.request<T>('POST', path, body)\n\t}\n\n\tdelete<T>(path: string): Promise<T> {\n\t\treturn this.request<T>('DELETE', path)\n\t}\n}\n","import { fail } from '../../exec/run.js'\nimport { PLAY_NOTES_MAX } from '../../notes/limits.js'\nimport type { AndroidPublisherClient } from './client.js'\n\nexport interface PlayRelease {\n\tname?: string\n\tversionCodes?: string[]\n\tstatus: 'completed' | 'inProgress' | 'halted' | 'draft'\n\treleaseNotes?: Array<{ language: string; text: string }>\n\tuserFraction?: number\n}\n\nexport interface PlayTrack {\n\ttrack: string\n\treleases?: PlayRelease[]\n}\n\ninterface EditHandle {\n\tid: string\n}\n\n/** Toda operação de escrita na Play precisa de um \"edit\" — insere, aplica, comita. */\nasync function withEdit<T>(\n\tclient: AndroidPublisherClient,\n\tpackageName: string,\n\tfn: (editId: string) => Promise<T>\n): Promise<T> {\n\tconst edit = await client.post<EditHandle>(`/applications/${packageName}/edits`)\n\ttry {\n\t\tconst result = await fn(edit.id)\n\t\tawait client.post(`/applications/${packageName}/edits/${edit.id}:commit`)\n\t\treturn result\n\t} catch (error) {\n\t\tawait client.delete(`/applications/${packageName}/edits/${edit.id}`).catch(() => {})\n\t\tthrow error\n\t}\n}\n\n/** Leitura: insere o edit só pra ver o estado atual e descarta sem comitar. */\nasync function withReadOnlyEdit<T>(\n\tclient: AndroidPublisherClient,\n\tpackageName: string,\n\tfn: (editId: string) => Promise<T>\n): Promise<T> {\n\tconst edit = await client.post<EditHandle>(`/applications/${packageName}/edits`)\n\ttry {\n\t\treturn await fn(edit.id)\n\t} finally {\n\t\tawait client.delete(`/applications/${packageName}/edits/${edit.id}`).catch(() => {})\n\t}\n}\n\nfunction findTargetRelease(releases: PlayRelease[], versionCode?: string): PlayRelease | undefined {\n\tif (versionCode) {\n\t\treturn releases.find((release) => (release.versionCodes ?? []).includes(String(versionCode)))\n\t}\n\treturn releases.find((release) => release.status === 'completed') ?? releases[0]\n}\n\n/** Valida acesso ao app: insere e descarta um edit vazio (usado no wizard). */\nexport async function validatePlayAccess(client: AndroidPublisherClient, packageName: string): Promise<void> {\n\tawait withReadOnlyEdit(client, packageName, async () => undefined)\n}\n\nexport interface UpdateTrackNotesInput {\n\tpackageName: string\n\ttrack: string\n\tnotesByLocale: Record<string, string>\n\tversionCode?: string\n}\n\n/** Porta de `play_update_notes.rb`: atualiza releaseNotes sem reupload de AAB. */\nexport async function updateTrackNotes(client: AndroidPublisherClient, input: UpdateTrackNotesInput): Promise<PlayRelease> {\n\tfor (const [locale, text] of Object.entries(input.notesByLocale)) {\n\t\tif (text.length > PLAY_NOTES_MAX) fail(`notas Play (${locale}) têm ${text.length} chars (máximo ${PLAY_NOTES_MAX}).`)\n\t}\n\treturn withEdit(client, input.packageName, async (editId) => {\n\t\tconst track = await client.get<PlayTrack>(`/applications/${input.packageName}/edits/${editId}/tracks/${input.track}`)\n\t\tconst releases = track.releases ?? []\n\t\tconst target = findTargetRelease(releases, input.versionCode)\n\t\tif (!target) fail(`faixa ${input.track} sem releases (versionCode: ${input.versionCode ?? '(completed)'}).`)\n\t\ttarget.releaseNotes = Object.entries(input.notesByLocale).map(([language, text]) => ({ language, text }))\n\t\tawait client.put(`/applications/${input.packageName}/edits/${editId}/tracks/${input.track}`, {\n\t\t\ttrack: input.track,\n\t\t\treleases,\n\t\t})\n\t\treturn target\n\t})\n}\n\nexport interface PromoteReleaseInput {\n\tpackageName: string\n\tfromTrack: string\n\ttoTrack: string\n\tnotesByLocale?: Record<string, string>\n\t/** 0 < x < 1 inicia em rollout parcial; 1 (default) publica 100%. */\n\tinitialRollout?: number\n}\n\n/** Copia a release \"completed\" da faixa de teste para a faixa de produção, sem reupload de AAB. */\nexport async function promoteRelease(client: AndroidPublisherClient, input: PromoteReleaseInput): Promise<PlayRelease> {\n\treturn withEdit(client, input.packageName, async (editId) => {\n\t\tconst source = await client.get<PlayTrack>(`/applications/${input.packageName}/edits/${editId}/tracks/${input.fromTrack}`)\n\t\tconst releases = source.releases ?? []\n\t\tconst target = findTargetRelease(releases)\n\t\tif (!target || !target.versionCodes?.length) {\n\t\t\tfail(`faixa ${input.fromTrack} sem release para promover.`)\n\t\t}\n\t\tconst fraction = input.initialRollout ?? 1\n\t\tconst status: PlayRelease['status'] = fraction < 1 ? 'inProgress' : 'completed'\n\t\tconst releaseNotes = input.notesByLocale\n\t\t\t? Object.entries(input.notesByLocale).map(([language, text]) => ({ language, text }))\n\t\t\t: target!.releaseNotes\n\t\tconst newRelease: PlayRelease = {\n\t\t\tversionCodes: target!.versionCodes,\n\t\t\tstatus,\n\t\t\treleaseNotes,\n\t\t\t...(status === 'inProgress' ? { userFraction: fraction } : {}),\n\t\t}\n\t\tawait client.put(`/applications/${input.packageName}/edits/${editId}/tracks/${input.toTrack}`, {\n\t\t\ttrack: input.toTrack,\n\t\t\treleases: [newRelease],\n\t\t})\n\t\treturn newRelease\n\t})\n}\n\nexport type RolloutTarget = number | 'complete' | 'halt'\n\n/** Avança/pausa/completa o rollout em uma faixa já em `inProgress`. */\nexport async function setRollout(client: AndroidPublisherClient, packageName: string, track: string, target: RolloutTarget): Promise<PlayRelease> {\n\treturn withEdit(client, packageName, async (editId) => {\n\t\tconst current = await client.get<PlayTrack>(`/applications/${packageName}/edits/${editId}/tracks/${track}`)\n\t\tconst releases = current.releases ?? []\n\t\tconst active = releases.find((release) => release.status === 'inProgress') ?? releases[releases.length - 1]\n\t\tif (!active) fail(`faixa ${track} sem release em rollout.`)\n\n\t\tif (target === 'complete') {\n\t\t\tactive.status = 'completed'\n\t\t\tdelete active.userFraction\n\t\t} else if (target === 'halt') {\n\t\t\tactive.status = 'halted'\n\t\t} else {\n\t\t\tif (target <= 0 || target > 1) fail(`--to precisa ser um valor entre 0 e 1 (ou complete/halt).`)\n\t\t\tactive.status = 'inProgress'\n\t\t\tactive.userFraction = target\n\t\t}\n\n\t\tawait client.put(`/applications/${packageName}/edits/${editId}/tracks/${track}`, { track, releases })\n\t\treturn active\n\t})\n}\n\nexport async function getTrackStatus(client: AndroidPublisherClient, packageName: string, track: string): Promise<PlayTrack> {\n\treturn withReadOnlyEdit(client, packageName, (editId) =>\n\t\tclient.get<PlayTrack>(`/applications/${packageName}/edits/${editId}/tracks/${track}`)\n\t)\n}\n","import { fail } from '../../exec/run.js'\nimport type { AppStoreConnectClient, JsonApiCollection } from './client.js'\n\nexport interface AppAttributes {\n\tbundleId: string\n\tname: string\n}\n\n/** GET /v1/apps?filter[bundleId]= — usado no wizard pra achar o ascAppId automaticamente. */\nexport async function findAppByBundleId(client: AppStoreConnectClient, bundleId: string): Promise<{ id: string; name: string } | null> {\n\tconst result = await client.get<JsonApiCollection<AppAttributes>>(`/apps?filter[bundleId]=${encodeURIComponent(bundleId)}`)\n\tconst [app] = result.data\n\tif (!app) return null\n\treturn { id: app.id, name: app.attributes.name }\n}\n\nexport async function requireAppByBundleId(client: AppStoreConnectClient, bundleId: string): Promise<{ id: string; name: string }> {\n\tconst app = await findAppByBundleId(client, bundleId)\n\tif (!app) fail(`App com bundleId ${bundleId} não encontrado no App Store Connect (chave sem acesso ao app, ou app ainda não criado).`)\n\treturn app\n}\n","import { fail } from '../../exec/run.js'\nimport { requireAppByBundleId } from './apps.js'\nimport type { AppStoreConnectClient, JsonApiCollection, JsonApiDocument } from './client.js'\n\n/**\n * Porta de `asc_submit_review.rb` (Spaceship) para chamadas diretas à App\n * Store Connect API v1. Superfície grande e pouco documentada em um só\n * lugar — validar contra uma conta real antes de confiar em produção\n * (spike previsto no plano: \"endpoints ASC de review submission e phased\n * release\"). Rode sempre com --dry-run primeiro numa conta nova.\n */\n\ninterface AppStoreVersionAttributes {\n\tversionString: string\n\tplatform: string\n\tappStoreState?: string\n\treleaseType?: string\n\tcopyright?: string\n}\n\ninterface BuildAttributes {\n\tprocessingState: string\n\tversion: string\n}\n\ninterface ReviewSubmissionAttributes {\n\tplatform: string\n\tstate: string\n\tsubmitted?: boolean\n}\n\ninterface LocalizationAttributes {\n\tlocale: string\n\twhatsNew?: string\n}\n\nconst IN_PROGRESS_STATES = new Set(['READY_FOR_REVIEW', 'WAITING_FOR_REVIEW', 'IN_REVIEW', 'PROCESSING'])\nconst TERMINAL_STATES = new Set(['COMPLETE', 'CANCELED'])\n\nexport interface ReviewSubmissionInput {\n\tbundleId: string\n\tversionString: string\n\twhatsNewByLocale: Record<string, string>\n\tautomaticRelease?: boolean\n\tphasedRelease?: boolean\n\tcopyright?: string\n}\n\nexport interface ReviewSubmissionResult {\n\tappId: string\n\tappStoreVersionId: string\n\tbuildId: string\n\tsubmissionId: string\n\tstate: string\n\talreadyInProgress: boolean\n}\n\nexport async function submitForReview(client: AppStoreConnectClient, input: ReviewSubmissionInput): Promise<ReviewSubmissionResult> {\n\tconst app = await requireAppByBundleId(client, input.bundleId)\n\n\tconst inProgress = await findInProgressReviewSubmission(client, app.id)\n\tif (inProgress) {\n\t\treturn {\n\t\t\tappId: app.id,\n\t\t\tappStoreVersionId: '',\n\t\t\tbuildId: '',\n\t\t\tsubmissionId: inProgress.id,\n\t\t\tstate: inProgress.attributes.state,\n\t\t\talreadyInProgress: true,\n\t\t}\n\t}\n\n\tconst version = await ensureAppStoreVersion(client, app.id, input.versionString)\n\n\tif (input.copyright && !version.attributes.copyright) {\n\t\tawait client.patch(`/appStoreVersions/${version.id}`, {\n\t\t\tdata: { id: version.id, type: 'appStoreVersions', attributes: { copyright: input.copyright } },\n\t\t})\n\t}\n\n\tawait client.patch(`/appStoreVersions/${version.id}`, {\n\t\tdata: {\n\t\t\tid: version.id,\n\t\t\ttype: 'appStoreVersions',\n\t\t\tattributes: { releaseType: input.automaticRelease ? 'AFTER_APPROVAL' : 'MANUAL' },\n\t\t},\n\t})\n\n\tconst build = await findValidBuild(client, app.id, input.versionString)\n\tif (!build) fail(`Nenhum build VALID no TestFlight para a versão ${input.versionString}.`)\n\n\tawait client.request('POST', `/appStoreVersions/${version.id}/relationships/build`, {\n\t\tdata: { id: build.id, type: 'builds' },\n\t})\n\n\tif (input.phasedRelease) {\n\t\tawait client.post('/appStoreVersionPhasedReleases', {\n\t\t\tdata: {\n\t\t\t\ttype: 'appStoreVersionPhasedReleases',\n\t\t\t\trelationships: { appStoreVersion: { data: { id: version.id, type: 'appStoreVersions' } } },\n\t\t\t},\n\t\t})\n\t}\n\n\tfor (const [locale, whatsNew] of Object.entries(input.whatsNewByLocale)) {\n\t\tconst localization = await findLocalization(client, version.id, locale)\n\t\tif (!localization) fail(`Localization ${locale} ausente na versão ${input.versionString} do App Store Connect.`)\n\t\tawait client.patch(`/appStoreVersionLocalizations/${localization.id}`, {\n\t\t\tdata: { id: localization.id, type: 'appStoreVersionLocalizations', attributes: { whatsNew } },\n\t\t})\n\t}\n\n\tconst submission = await createReviewSubmission(client, app.id)\n\tawait client.post('/reviewSubmissionItems', {\n\t\tdata: {\n\t\t\ttype: 'reviewSubmissionItems',\n\t\t\trelationships: {\n\t\t\t\treviewSubmission: { data: { id: submission.id, type: 'reviewSubmissions' } },\n\t\t\t\tappStoreVersion: { data: { id: version.id, type: 'appStoreVersions' } },\n\t\t\t},\n\t\t},\n\t})\n\tconst submitted = await client.patch<JsonApiDocument<ReviewSubmissionAttributes>>(`/reviewSubmissions/${submission.id}`, {\n\t\tdata: { id: submission.id, type: 'reviewSubmissions', attributes: { submitted: true } },\n\t})\n\n\treturn {\n\t\tappId: app.id,\n\t\tappStoreVersionId: version.id,\n\t\tbuildId: build.id,\n\t\tsubmissionId: submission.id,\n\t\tstate: submitted.data.attributes.state,\n\t\talreadyInProgress: false,\n\t}\n}\n\nexport interface IosStatus {\n\tappId: string\n\tversionString: string\n\tappStoreState: string | null\n\treviewSubmissionState: string | null\n}\n\n/** Usado por `release-kit status`: estado da versão + de uma submission em andamento, se houver. */\nexport async function getIosStatus(client: AppStoreConnectClient, bundleId: string, versionString: string): Promise<IosStatus> {\n\tconst app = await requireAppByBundleId(client, bundleId)\n\tconst version = await findAppStoreVersion(client, app.id, versionString)\n\tconst inProgress = await findInProgressReviewSubmission(client, app.id)\n\treturn {\n\t\tappId: app.id,\n\t\tversionString,\n\t\tappStoreState: version?.attributes.appStoreState ?? null,\n\t\treviewSubmissionState: inProgress?.attributes.state ?? null,\n\t}\n}\n\nasync function findInProgressReviewSubmission(\n\tclient: AppStoreConnectClient,\n\tappId: string\n): Promise<{ id: string; attributes: ReviewSubmissionAttributes } | null> {\n\tconst result = await client.get<JsonApiCollection<ReviewSubmissionAttributes>>(\n\t\t`/apps/${appId}/reviewSubmissions?filter[platform]=IOS`\n\t)\n\tconst active = result.data.find(\n\t\t(item) => IN_PROGRESS_STATES.has(item.attributes.state) && !TERMINAL_STATES.has(item.attributes.state)\n\t)\n\treturn active ?? null\n}\n\nasync function ensureAppStoreVersion(\n\tclient: AppStoreConnectClient,\n\tappId: string,\n\tversionString: string\n): Promise<{ id: string; attributes: AppStoreVersionAttributes }> {\n\tconst existing = await findAppStoreVersion(client, appId, versionString)\n\tif (existing) return existing\n\n\tconst created = await client.post<JsonApiDocument<AppStoreVersionAttributes>>('/appStoreVersions', {\n\t\tdata: {\n\t\t\ttype: 'appStoreVersions',\n\t\t\tattributes: { platform: 'IOS', versionString },\n\t\t\trelationships: { app: { data: { id: appId, type: 'apps' } } },\n\t\t},\n\t})\n\treturn { id: created.data.id, attributes: created.data.attributes }\n}\n\nasync function findAppStoreVersion(\n\tclient: AppStoreConnectClient,\n\tappId: string,\n\tversionString: string\n): Promise<{ id: string; attributes: AppStoreVersionAttributes } | null> {\n\tconst result = await client.get<JsonApiCollection<AppStoreVersionAttributes>>(\n\t\t`/apps/${appId}/appStoreVersions?filter[versionString]=${encodeURIComponent(versionString)}&filter[platform]=IOS`\n\t)\n\tconst [version] = result.data\n\treturn version ? { id: version.id, attributes: version.attributes } : null\n}\n\nasync function findValidBuild(\n\tclient: AppStoreConnectClient,\n\tappId: string,\n\tversionString: string\n): Promise<{ id: string; attributes: BuildAttributes } | null> {\n\tconst result = await client.get<JsonApiCollection<BuildAttributes>>(\n\t\t`/builds?filter[app]=${appId}&filter[preReleaseVersion.version]=${encodeURIComponent(versionString)}&sort=-uploadedDate&limit=20`\n\t)\n\tconst valid = result.data.find((item) => item.attributes.processingState === 'VALID')\n\tconst build = valid ?? result.data[0]\n\treturn build ? { id: build.id, attributes: build.attributes } : null\n}\n\nasync function findLocalization(\n\tclient: AppStoreConnectClient,\n\tversionId: string,\n\tlocale: string\n): Promise<{ id: string; attributes: LocalizationAttributes } | null> {\n\tconst result = await client.get<JsonApiCollection<LocalizationAttributes>>(\n\t\t`/appStoreVersions/${versionId}/appStoreVersionLocalizations`\n\t)\n\tconst match = result.data.find((item) => item.attributes.locale === locale)\n\treturn match ? { id: match.id, attributes: match.attributes } : null\n}\n\nasync function createReviewSubmission(\n\tclient: AppStoreConnectClient,\n\tappId: string\n): Promise<{ id: string; attributes: ReviewSubmissionAttributes }> {\n\tconst created = await client.post<JsonApiDocument<ReviewSubmissionAttributes>>('/reviewSubmissions', {\n\t\tdata: {\n\t\t\ttype: 'reviewSubmissions',\n\t\t\tattributes: { platform: 'IOS' },\n\t\t\trelationships: { app: { data: { id: appId, type: 'apps' } } },\n\t\t},\n\t})\n\treturn { id: created.data.id, attributes: created.data.attributes }\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport type { Platform, ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { fail } from '../exec/run.js'\nimport { readAppVersion } from '../project/version.js'\nimport { notesFilePath, readNotesFile } from '../notes/paths.js'\nimport { assertChannelOptIn, type ProtectedGateOptions } from './gate.js'\nimport { createAppleClient, createGoogleClient } from '../stores/credentials.js'\nimport { promoteRelease as promotePlayRelease } from '../stores/google/tracks.js'\nimport { submitForReview } from '../stores/apple/review.js'\n\nexport interface PromoteOptions extends ProtectedGateOptions {\n\tchannel: string\n\tplatform?: Platform\n}\n\nexport interface PromoteResult {\n\tandroid?: { versionCodes?: string[]; status: string }\n\tios?: { submissionId: string; state: string; alreadyInProgress: boolean }\n}\n\nfunction notesByLocale(ctx: ReleaseKitContext, config: ReleaseKitConfig, version: string, target: 'ios' | 'play'): Record<string, string> {\n\tconst result: Record<string, string> = {}\n\tfor (const locale of config.locales) {\n\t\tconst path = notesFilePath(ctx.appDir, config.notesDir, version, locale, target)\n\t\tresult[locale] = readNotesFile(path)\n\t}\n\treturn result\n}\n\n/**\n * `build` + `submit` já colocaram o binário na faixa de teste\n * (Play Internal / TestFlight). `promote` não faz upload nenhum: copia a\n * release pra faixa de produção (Play) ou cria a Review Submission\n * (Apple) — é o equivalente ao `local-validation` → produção do kit\n * original.\n */\nexport async function promoteRelease(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: PromoteOptions): Promise<PromoteResult> {\n\tconst channel = channelOf(config, opts.channel)\n\tassertChannelOptIn(ctx, config, channel, opts)\n\tconst version = readAppVersion(ctx.appDir, config)\n\tconst result: PromoteResult = {}\n\n\tconst wantsAndroid = (!opts.platform || opts.platform === 'android') && channel.android\n\tconst wantsIos = (!opts.platform || opts.platform === 'ios') && channel.ios\n\n\tif (!wantsAndroid && !wantsIos) fail('nenhuma plataforma configurada no canal para promover.')\n\n\tif (ctx.dryRun) {\n\t\tif (wantsAndroid) ctx.log.info(`[dry-run] Play: promover ${channel.android!.testTrack} → ${channel.android!.productionTrack} (${channel.android!.package})`)\n\t\tif (wantsIos) ctx.log.info(`[dry-run] Apple: criar Review Submission para ${channel.ios!.bundleId} v${version}`)\n\t\treturn result\n\t}\n\n\tif (wantsAndroid) {\n\t\tconst android = channel.android!\n\t\tconst google = createGoogleClient(ctx.env)\n\t\ttry {\n\t\t\tconst notes = notesByLocale(ctx, config, version, 'play')\n\t\t\tctx.log.step(`Play: promovendo ${android.testTrack} → ${android.productionTrack}`)\n\t\t\tconst release = await promotePlayRelease(google, {\n\t\t\t\tpackageName: android.package,\n\t\t\t\tfromTrack: android.testTrack,\n\t\t\t\ttoTrack: android.productionTrack,\n\t\t\t\tnotesByLocale: notes,\n\t\t\t\tinitialRollout: android.initialRollout,\n\t\t\t})\n\t\t\tctx.log.success(`Play: ${android.productionTrack} status=${release.status} versionCodes=${(release.versionCodes ?? []).join(',')}`)\n\t\t\tresult.android = { versionCodes: release.versionCodes, status: release.status }\n\t\t} finally {\n\t\t\tgoogle.cleanup()\n\t\t}\n\t}\n\n\tif (wantsIos) {\n\t\tconst ios = channel.ios!\n\t\tconst apple = createAppleClient(ctx.env)\n\t\ttry {\n\t\t\tconst notes = notesByLocale(ctx, config, version, 'ios')\n\t\t\tctx.log.step(`Apple: enviando Review Submission para ${ios.bundleId} v${version}`)\n\t\t\tconst submission = await submitForReview(apple, {\n\t\t\t\tbundleId: ios.bundleId,\n\t\t\t\tversionString: version,\n\t\t\t\twhatsNewByLocale: notes,\n\t\t\t\tautomaticRelease: ios.automaticRelease,\n\t\t\t\tphasedRelease: ios.phasedRelease,\n\t\t\t\tcopyright: ios.copyright,\n\t\t\t})\n\t\t\tif (submission.alreadyInProgress) {\n\t\t\t\tctx.log.warn(`Apple: já existe submission em análise (${submission.submissionId}, state=${submission.state}).`)\n\t\t\t} else {\n\t\t\t\tctx.log.success(`Apple: submission ${submission.submissionId} enviada (state=${submission.state}).`)\n\t\t\t}\n\t\t\tresult.ios = { submissionId: submission.submissionId, state: submission.state, alreadyInProgress: submission.alreadyInProgress }\n\t\t} finally {\n\t\t\tapple.cleanup()\n\t\t}\n\t}\n\n\treturn result\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport type { Platform, ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { fail } from '../exec/run.js'\nimport { assertChannelOptIn, type ProtectedGateOptions } from './gate.js'\nimport { createGoogleClient } from '../stores/credentials.js'\nimport { setRollout, type RolloutTarget } from '../stores/google/tracks.js'\n\nexport interface RolloutOptions extends ProtectedGateOptions {\n\tchannel: string\n\tplatform: Platform\n\tto: RolloutTarget\n}\n\n/**\n * Só Android tem rollout percentual manipulável via API sem reupload\n * (`userFraction`). No iOS o equivalente é o phased release, controlado\n * pelo próprio App Store Connect após a review — não há endpoint de\n * pause/resume simples e estável na API pública hoje; documentado como\n * limitação em vez de fingir suporte.\n */\nexport async function rolloutRelease(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: RolloutOptions) {\n\tif (opts.platform !== 'android') {\n\t\tfail('rollout percentual só é suportado para Android nesta versão. iOS: acompanhe o phased release no App Store Connect.')\n\t}\n\tconst channel = channelOf(config, opts.channel)\n\tassertChannelOptIn(ctx, config, channel, opts)\n\tif (!channel.android) fail(`canal \"${opts.channel}\" não tem configuração android.`)\n\n\tif (ctx.dryRun) {\n\t\tctx.log.info(`[dry-run] Play: ${channel.android.productionTrack} → ${opts.to}`)\n\t\treturn { dryRun: true }\n\t}\n\n\tconst google = createGoogleClient(ctx.env)\n\ttry {\n\t\tconst release = await setRollout(google, channel.android.package, channel.android.productionTrack, opts.to)\n\t\tctx.log.success(`Play: ${channel.android.productionTrack} agora ${release.status}${release.userFraction ? ` (${Math.round(release.userFraction * 100)}%)` : ''}`)\n\t\treturn release\n\t} finally {\n\t\tgoogle.cleanup()\n\t}\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport type { ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { readAppVersion } from '../project/version.js'\nimport { createAppleClient, createGoogleClient } from '../stores/credentials.js'\nimport { getTrackStatus } from '../stores/google/tracks.js'\nimport { getIosStatus } from '../stores/apple/review.js'\n\nexport interface StatusOptions {\n\tchannel: string\n}\n\nexport interface StatusResult {\n\tversion: string\n\tandroid?: { track: string; releases: Array<{ status: string; versionCodes?: string[]; userFraction?: number }> }\n\tios?: { appStoreState: string | null; reviewSubmissionState: string | null }\n}\n\nexport async function statusOf(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: StatusOptions): Promise<StatusResult> {\n\tconst channel = channelOf(config, opts.channel)\n\tconst version = readAppVersion(ctx.appDir, config)\n\tconst result: StatusResult = { version }\n\n\tif (channel.android) {\n\t\tconst google = createGoogleClient(ctx.env)\n\t\ttry {\n\t\t\tconst track = await getTrackStatus(google, channel.android.package, channel.android.productionTrack)\n\t\t\tresult.android = {\n\t\t\t\ttrack: channel.android.productionTrack,\n\t\t\t\treleases: (track.releases ?? []).map((release) => ({\n\t\t\t\t\tstatus: release.status,\n\t\t\t\t\tversionCodes: release.versionCodes,\n\t\t\t\t\tuserFraction: release.userFraction,\n\t\t\t\t})),\n\t\t\t}\n\t\t} finally {\n\t\t\tgoogle.cleanup()\n\t\t}\n\t}\n\n\tif (channel.ios) {\n\t\tconst apple = createAppleClient(ctx.env)\n\t\ttry {\n\t\t\tconst status = await getIosStatus(apple, channel.ios.bundleId, version)\n\t\t\tresult.ios = { appStoreState: status.appStoreState, reviewSubmissionState: status.reviewSubmissionState }\n\t\t} finally {\n\t\t\tapple.cleanup()\n\t\t}\n\t}\n\n\treturn result\n}\n\nexport function printStatus(ctx: ReleaseKitContext, status: StatusResult): void {\n\tctx.log.info(`versão: ${status.version}`)\n\tif (status.android) {\n\t\tctx.log.info(`Play (${status.android.track}):`)\n\t\tfor (const release of status.android.releases) {\n\t\t\tconst fraction = release.userFraction ? ` (${Math.round(release.userFraction * 100)}%)` : ''\n\t\t\tctx.log.info(` - ${release.status}${fraction} — versionCodes: ${(release.versionCodes ?? []).join(', ')}`)\n\t\t}\n\t}\n\tif (status.ios) {\n\t\tctx.log.info(`App Store: appStoreState=${status.ios.appStoreState ?? '(sem versão editável)'} reviewSubmission=${status.ios.reviewSubmissionState ?? '(nenhuma em andamento)'}`)\n\t}\n}\n","import type { ReleaseKitContext } from '../context.js'\nimport { fail, formatCommand, requireSuccess } from '../exec/run.js'\nimport type { Platform, ReleaseKitConfig } from '../config/schema.js'\nimport { channelOf } from '../config/schema.js'\nimport { easUpdate } from '../eas/cli.js'\nimport { assertChannelOptIn, type ProtectedGateOptions } from './gate.js'\n\nexport interface UpdateOptions extends ProtectedGateOptions {\n\tchannel: string\n\tmessage?: string\n\tplatform?: Platform | 'all'\n}\n\nexport interface UpdateResult {\n\tdryRun?: boolean\n\tcommand?: string\n\tchannel: string\n}\n\n/**\n * OTA via `eas update`. Canal protegido passa pelo mesmo gate fail-closed\n * do build/submit: só roda com --i-know-this-is-production ou confirmando\n * a versão — nunca por padrão, mesmo em `release-kit update` sem flags.\n */\nexport function updateRelease(ctx: ReleaseKitContext, config: ReleaseKitConfig, opts: UpdateOptions): UpdateResult {\n\tconst channel = channelOf(config, opts.channel)\n\tassertChannelOptIn(ctx, config, channel, opts)\n\tif (!channel.ota) {\n\t\tfail(`canal \"${opts.channel}\" não tem \"ota.channel\" configurado.`)\n\t}\n\n\tif (ctx.dryRun) {\n\t\tconst command = formatCommand('eas', ['update', '--channel', channel.ota.channel, '--message', opts.message ?? '(sem mensagem)'], channel.env)\n\t\tctx.log.info(`[dry-run] cd ${ctx.appDir} && ${command}`)\n\t\treturn { dryRun: true, command, channel: channel.ota.channel }\n\t}\n\n\tctx.log.step(`eas update (channel ${channel.ota.channel})`)\n\trequireSuccess(\n\t\teasUpdate(ctx, { channel: channel.ota.channel, message: opts.message, platform: opts.platform, env: channel.env }),\n\t\t'eas update'\n\t)\n\treturn { channel: channel.ota.channel }\n}\n"],"mappings":"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","names":["z","z","existsSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync","writeFileSync","existsSync","join","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","join","existsSync","mkdirSync","join","existsSync","readdirSync","readFileSync","writeFileSync","join","readFileSync","writeFileSync","join","existsSync","readdirSync","join","mkdirSync","existsSync","git","existsSync","resolve","resolve","existsSync","existsSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","existsSync","readFileSync","mkdirSync","writeFileSync","existsSync","existsSync","readFileSync","copyFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","join","writeFileSync","createSign","base64url","createSign","existsSync","readFileSync","promoteRelease"]}
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@htgabriel/release-kit",
3
+ "version": "0.1.0",
4
+ "description": "Orquestrador de release reutilizável para apps Expo/EAS: setup guiado de credenciais, build/submit locais, versão, notas, App Review, rollout e OTA.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "bin": {
11
+ "release-kit": "dist/cli/index.js"
12
+ },
13
+ "main": "./dist/index.js",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ },
21
+ "./schema.json": "./schema.json"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "templates",
26
+ "schema.json",
27
+ "README.md"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "dev": "tsup --watch",
32
+ "typecheck": "tsc --noEmit",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "schema:generate": "tsx scripts/generate-schema.ts",
36
+ "prepublishOnly": "npm run build && npm run schema:generate"
37
+ },
38
+ "dependencies": {
39
+ "@clack/prompts": "^0.9.1",
40
+ "cross-spawn": "^7.0.6",
41
+ "dotenv": "^16.4.5",
42
+ "picocolors": "^1.1.1",
43
+ "semver": "^7.6.3",
44
+ "zod": "^3.23.8"
45
+ },
46
+ "devDependencies": {
47
+ "@types/cross-spawn": "^6.0.6",
48
+ "@types/node": "^20.14.0",
49
+ "@types/semver": "^7.5.8",
50
+ "tsup": "^8.3.5",
51
+ "tsx": "^4.19.2",
52
+ "typescript": "^5.6.3",
53
+ "vitest": "^2.1.4",
54
+ "zod-to-json-schema": "^3.23.5"
55
+ },
56
+ "packageManager": "npm@11.6.2",
57
+ "publishConfig": {
58
+ "access": "public"
59
+ },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/htgabriel/rn-release-kit.git"
63
+ },
64
+ "keywords": [
65
+ "expo",
66
+ "eas",
67
+ "react-native",
68
+ "release",
69
+ "app-store-connect",
70
+ "google-play"
71
+ ]
72
+ }