@gpc-cli/cli 0.9.31 → 0.9.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/dist/apps-CVBURB5V.js +0 -0
  3. package/dist/audit-A4BP27DN.js +0 -0
  4. package/dist/{auth-5XAQMZRV.js → auth-QSDK7NUO.js} +18 -1
  5. package/dist/{auth-5XAQMZRV.js.map → auth-QSDK7NUO.js.map} +1 -1
  6. package/dist/bin.js +5 -1
  7. package/dist/bin.js.map +1 -1
  8. package/dist/bundle-7IF5FIB4.js +0 -0
  9. package/dist/cache-SHWAVON6.js +114 -0
  10. package/dist/cache-SHWAVON6.js.map +1 -0
  11. package/dist/chunk-4O4D5SGL.js +0 -0
  12. package/dist/{chunk-5VVYPCDE.js → chunk-DMMFPBYF.js} +38 -5
  13. package/dist/chunk-DMMFPBYF.js.map +1 -0
  14. package/dist/chunk-ELXAK7GI.js +0 -0
  15. package/dist/chunk-FWKYRLKY.js +0 -0
  16. package/dist/chunk-NV75I5VP.js +0 -0
  17. package/dist/{update-GC2A2WVP.js → chunk-UH3TMIAL.js} +17 -154
  18. package/dist/chunk-UH3TMIAL.js.map +1 -0
  19. package/dist/chunk-Y3QZDAKS.js +0 -0
  20. package/dist/completion-C3PPWNS7.js +0 -0
  21. package/dist/config-2L7QUYWP.js +0 -0
  22. package/dist/data-safety-GDPKV5PN.js +0 -0
  23. package/dist/device-tiers-GHIYJPMB.js +0 -0
  24. package/dist/docs-HIGQU4UL.js +0 -0
  25. package/dist/doctor-UZB2UB5X.js +0 -0
  26. package/dist/external-transactions-HCL7ROMN.js +0 -0
  27. package/dist/feedback-W5MZMRF2.js +46 -0
  28. package/dist/feedback-W5MZMRF2.js.map +1 -0
  29. package/dist/generated-apks-VX7HYZDU.js +0 -0
  30. package/dist/iap-BBHF7BLZ.js +0 -0
  31. package/dist/index.js +1 -1
  32. package/dist/install-skills-OV4HVANW.js +0 -0
  33. package/dist/internal-sharing-E7SJYDW3.js +0 -0
  34. package/dist/listings-VSBHQY5H.js +0 -0
  35. package/dist/migrate-XQV7P4R7.js +0 -0
  36. package/dist/one-time-products-2PK4QKWE.js +0 -0
  37. package/dist/pricing-BYZSLN74.js +0 -0
  38. package/dist/prompt-BSV22CQZ.js +0 -0
  39. package/dist/publish-I6WJGR4S.js +0 -0
  40. package/dist/purchase-options-CKRN4VIW.js +0 -0
  41. package/dist/purchases-YRO6B7M6.js +0 -0
  42. package/dist/recovery-S5UNJDBO.js +0 -0
  43. package/dist/{releases-JMRKXEZU.js → releases-ANC54YWF.js} +88 -38
  44. package/dist/releases-ANC54YWF.js.map +1 -0
  45. package/dist/reports-N5X66IUN.js +0 -0
  46. package/dist/reviews-GJAQ5OVC.js +0 -0
  47. package/dist/status-6Y2CHHVD.js +0 -0
  48. package/dist/subscriptions-Z5ZPVUFM.js +0 -0
  49. package/dist/testers-UWSUGGVT.js +0 -0
  50. package/dist/tracks-XFUN7JJX.js +0 -0
  51. package/dist/update-NIVJLUNH.js +169 -0
  52. package/dist/update-NIVJLUNH.js.map +1 -0
  53. package/dist/users-JASXONRY.js +0 -0
  54. package/dist/validate-MHLPENCM.js +0 -0
  55. package/dist/version-7AI5IHVK.js +26 -0
  56. package/dist/version-7AI5IHVK.js.map +1 -0
  57. package/dist/vitals-KSNAVN5F.js +0 -0
  58. package/package.json +25 -19
  59. package/dist/chunk-5VVYPCDE.js.map +0 -1
  60. package/dist/releases-JMRKXEZU.js.map +0 -1
  61. package/dist/update-GC2A2WVP.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/releases.ts"],"sourcesContent":["import { appendFile, stat } from \"node:fs/promises\";\nimport { basename, extname } from \"node:path\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient, createReportingClient } from \"@gpc-cli/api\";\nimport type { RetryLogEntry } from \"@gpc-cli/api\";\nimport {\n uploadRelease,\n getReleasesStatus,\n promoteRelease,\n updateRollout,\n readReleaseNotesFromDir,\n generateNotesFromGit,\n writeAuditLog,\n createAuditEntry,\n uploadExternallyHosted,\n diffReleases,\n getVitalsCrashes,\n checkThreshold,\n} from \"@gpc-cli/core\";\nimport { formatOutput, sortResults, createSpinner } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, promptSelect, promptInput, requireOption } from \"../prompt.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nfunction createRetryLogger(retryLogPath?: string): ((entry: RetryLogEntry) => void) | undefined {\n if (!retryLogPath) return undefined;\n return (entry: RetryLogEntry) => {\n const line = JSON.stringify(entry) + \"\\n\";\n appendFile(retryLogPath, line).catch(() => {});\n };\n}\n\nasync function getClient(config: GpcConfig, retryLogPath?: string, uploadTimeout?: number) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth, onRetry: createRetryLogger(retryLogPath), uploadTimeout });\n}\n\nexport function registerReleasesCommands(program: Command): void {\n const releases = program.command(\"releases\").description(\"Manage releases and rollouts\");\n\n // Upload\n releases\n .command(\"upload <file>\")\n .description(\"Upload AAB/APK and assign to a track\")\n .option(\"--track <track>\", \"Target track\", \"internal\")\n .option(\"--rollout <percent>\", \"Staged rollout percentage (1-100)\")\n .option(\"--notes <text>\", \"Release notes (en-US)\")\n .option(\"--name <name>\", \"Release name\")\n .option(\"--mapping <file>\", \"ProGuard/R8 mapping file for deobfuscation\")\n .option(\"--notes-dir <dir>\", \"Read release notes from directory (<dir>/<lang>.txt)\")\n .option(\"--notes-from-git\", \"Generate release notes from git commit history\")\n .option(\"--since <ref>\", \"Git ref to start from (tag, SHA) — used with --notes-from-git\")\n .option(\"--retry-log <path>\", \"Write retry log entries to file (JSONL)\")\n .option(\"--timeout <ms>\", \"Upload timeout in milliseconds (auto-scales with file size by default)\", parseInt)\n .action(async (file: string, options) => {\n try {\n await stat(file);\n } catch {\n console.error(`Error: File not found: ${file}`);\n process.exit(2);\n }\n\n const ext = extname(file).toLowerCase();\n if (ext !== \".aab\" && ext !== \".apk\") {\n console.error(`Error: Expected .aab or .apk file, got \"${ext || \"(no extension)\"}\"`);\n process.exit(2);\n }\n\n const noteSources = [options.notes, options.notesDir, options.notesFromGit].filter(Boolean);\n if (noteSources.length > 1) {\n console.error(\"Error: Cannot combine --notes, --notes-dir, and --notes-from-git. Use only one.\");\n process.exit(2);\n }\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n // Interactive mode: prompt for missing options\n if (isInteractive(program)) {\n if (!options.track || options.track === \"internal\") {\n const tracks = [\"internal\", \"alpha\", \"beta\", \"production\"];\n options.track = await promptSelect(\"Select track:\", tracks, \"internal\");\n }\n\n if (!options.rollout && options.track === \"production\") {\n const rolloutStr = await promptInput(\n \"Staged rollout percentage (1-100, blank for full)\",\n \"100\",\n );\n if (rolloutStr && rolloutStr !== \"100\") {\n options.rollout = rolloutStr;\n }\n }\n\n if (!options.notes && !options.notesDir) {\n const notes = await promptInput(\"Release notes (en-US, blank to skip)\");\n if (notes) options.notes = notes;\n }\n }\n\n if (options.rollout !== undefined) {\n const rollout = Number(options.rollout);\n if (!Number.isFinite(rollout) || rollout < 1 || rollout > 100) {\n console.error(`Error: --rollout must be a number between 1 and 100 (got: ${options.rollout})`);\n process.exit(2);\n }\n }\n\n const { size: fileSize } = await stat(file);\n const jsonMode = format === \"json\";\n const client = await getClient(config, options.retryLog, options.timeout);\n\n // The API layer buffers the full file before sending, so byte-level streaming progress\n // isn't available. Use a time-based animation instead.\n const showProgress = !jsonMode && process.stderr.isTTY && !program.opts()[\"quiet\"];\n const sizeMB = (fileSize / (1024 * 1024)).toFixed(1);\n const FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n let progressInterval: ReturnType<typeof setInterval> | undefined;\n if (showProgress) {\n let frame = 0;\n const startTime = Date.now();\n progressInterval = setInterval(() => {\n const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);\n process.stderr.write(`\\r ${FRAMES[frame % FRAMES.length]} Uploading ${basename(file)} ${sizeMB} MB (${elapsed}s) `);\n frame++;\n }, 120);\n }\n const onProgress = undefined;\n\n if (isDryRun(program)) {\n try {\n const result = await uploadRelease(client, packageName, file, {\n track: options.track,\n userFraction: options.rollout ? Number(options.rollout) / 100 : undefined,\n dryRun: true,\n });\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n return;\n }\n\n const auditEntry = createAuditEntry(\n \"releases upload\",\n {\n file,\n track: options.track,\n rollout: options.rollout,\n },\n packageName,\n );\n\n const spinner = createSpinner(`Uploading ${basename(file)} (${sizeMB} MB)...`);\n if (!showProgress) spinner.start();\n\n try {\n let releaseNotes: { language: string; text: string }[] | undefined;\n if (options.notesFromGit) {\n const gitNotes = await generateNotesFromGit({ since: options.since });\n releaseNotes = [{ language: gitNotes.language, text: gitNotes.text }];\n } else if (options.notesDir) {\n releaseNotes = await readReleaseNotesFromDir(options.notesDir);\n } else if (options.notes) {\n releaseNotes = [{ language: \"en-US\", text: options.notes }];\n }\n\n const result = await uploadRelease(client, packageName, file, {\n track: options.track,\n userFraction: options.rollout ? Number(options.rollout) / 100 : undefined,\n releaseNotes,\n releaseName: options.name,\n mappingFile: options.mapping,\n onProgress,\n });\n if (progressInterval) { clearInterval(progressInterval); process.stderr.write(`\\r ✓ Uploaded ${basename(file)} ${sizeMB} MB\\n`); }\n spinner.stop(\"Upload complete\");\n console.log(formatOutput(result, format));\n auditEntry.success = true;\n } catch (error) {\n if (progressInterval) { clearInterval(progressInterval); process.stderr.write(\"\\n\"); }\n spinner.fail(\"Upload failed\");\n auditEntry.success = false;\n auditEntry.error = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n } finally {\n auditEntry.durationMs = Date.now() - new Date(auditEntry.timestamp).getTime();\n writeAuditLog(auditEntry).catch(() => {});\n }\n });\n\n // Status\n releases\n .command(\"status\")\n .description(\"Show current release status across tracks\")\n .option(\"--track <track>\", \"Filter by track\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const TRACK_ORDER = [\"production\", \"beta\", \"alpha\", \"internal\"];\n const rawStatuses = await getReleasesStatus(client, packageName, options.track);\n const statuses = options.track\n ? (Array.isArray(rawStatuses) ? rawStatuses.filter((s: any) => s.track === options.track) : rawStatuses)\n : rawStatuses;\n const sorted = Array.isArray(statuses)\n ? options.sort\n ? sortResults(statuses, options.sort)\n : [...statuses].sort((a, b) => {\n const ai = TRACK_ORDER.indexOf(String((a as Record<string, unknown>)[\"track\"] ?? \"\"));\n const bi = TRACK_ORDER.indexOf(String((b as Record<string, unknown>)[\"track\"] ?? \"\"));\n return (ai === -1 ? 99 : ai) - (bi === -1 ? 99 : bi);\n })\n : statuses;\n if (format !== \"json\" && Array.isArray(sorted)) {\n const rows = sorted.map((s: Record<string, unknown>) => ({\n track: s[\"track\"] || \"-\",\n status: s[\"status\"] || \"-\",\n name: s[\"name\"] || \"-\",\n versionCodes: Array.isArray(s[\"versionCodes\"]) ? (s[\"versionCodes\"] as unknown[]).join(\", \") : \"-\",\n userFraction: s[\"userFraction\"] !== undefined\n ? `${Math.round(Number(s[\"userFraction\"]) * 100)}%`\n : \"—\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(sorted, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Promote\n releases\n .command(\"promote\")\n .description(\"Promote a release from one track to another\")\n .option(\"--from <track>\", \"Source track\")\n .option(\"--to <track>\", \"Target track\")\n .option(\"--rollout <percent>\", \"Staged rollout percentage\")\n .option(\"--notes <text>\", \"Release notes\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n const tracks = [\"internal\", \"alpha\", \"beta\", \"production\"];\n\n options.from = await requireOption(\n \"from\",\n options.from,\n {\n message: \"Source track:\",\n choices: tracks,\n },\n interactive,\n );\n\n options.to = await requireOption(\n \"to\",\n options.to,\n {\n message: \"Target track:\",\n choices: tracks.filter((t: string) => t !== options.from),\n },\n interactive,\n );\n\n if (options.from === options.to) {\n console.error(`Error: --from and --to must be different tracks (both are \"${options.from}\")`);\n process.exit(2);\n }\n\n if (options.rollout !== undefined) {\n const rollout = Number(options.rollout);\n if (!Number.isFinite(rollout) || rollout < 1 || rollout > 100) {\n console.error(`Error: --rollout must be a number between 1 and 100 (got: ${options.rollout})`);\n process.exit(2);\n }\n }\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"releases promote\",\n action: \"promote\",\n target: `${options.from} → ${options.to}`,\n details: { rollout: options.rollout },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await promoteRelease(client, packageName, options.from, options.to, {\n userFraction: options.rollout ? Number(options.rollout) / 100 : undefined,\n releaseNotes: options.notes ? [{ language: \"en-US\", text: options.notes }] : undefined,\n });\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Rollout subcommands\n const rollout = releases.command(\"rollout\").description(\"Manage staged rollouts\");\n\n for (const action of [\"increase\", \"halt\", \"resume\", \"complete\"] as const) {\n const cmd = rollout\n .command(action)\n .description(`${action.charAt(0).toUpperCase() + action.slice(1)} a staged rollout`)\n .option(\"--track <track>\", \"Track name\");\n\n if (action === \"increase\") {\n cmd.option(\"--to <percent>\", \"New rollout percentage\");\n cmd.option(\"--vitals-gate\", \"Halt rollout if crash rate exceeds configured threshold\");\n }\n\n cmd.action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n const tracks = [\"internal\", \"alpha\", \"beta\", \"production\"];\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: tracks,\n },\n interactive,\n );\n\n if (action === \"increase\") {\n options.to = await requireOption(\n \"to\",\n options.to,\n {\n message: \"New rollout percentage (1-100):\",\n },\n interactive,\n );\n }\n\n if (action === \"increase\" && options.to !== undefined) {\n const to = Number(options.to);\n if (!Number.isFinite(to) || to < 1 || to > 100) {\n console.error(`Error: --to must be a number between 1 and 100 (got: ${options.to})`);\n process.exit(2);\n }\n }\n\n if (isDryRun(program)) {\n if (action === \"increase\" && options.vitalsGate) {\n console.error(\"Warning: --vitals-gate is ignored in --dry-run mode. Gate will run on live execution.\");\n }\n printDryRun(\n {\n command: `releases rollout ${action}`,\n action: action,\n target: options.track,\n details: { percentage: options.to !== undefined ? `${options.to}%` : undefined },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await updateRollout(\n client,\n packageName,\n options.track,\n action,\n options.to ? Number(options.to) / 100 : undefined,\n );\n\n // Vitals gate: check crash rate after rollout increase\n if (action === \"increase\" && options.vitalsGate) {\n const threshold = (config as any).vitals?.thresholds?.crashRate;\n if (!threshold) {\n console.error(\"Warning: --vitals-gate requires vitals.thresholds.crashRate in config. Skipping gate.\");\n } else {\n try {\n const { auth: authConfig } = config;\n const vitalsAuth = await resolveAuth({ serviceAccountPath: authConfig?.serviceAccount });\n const reportingClient = createReportingClient({ auth: vitalsAuth });\n const vitalsResult = await getVitalsCrashes(reportingClient, packageName, { days: 1 });\n const latest = (vitalsResult as any).data?.[0]?.crashRate;\n const check = checkThreshold(latest, threshold);\n if (check.breached) {\n await updateRollout(client, packageName, options.track, \"halt\");\n console.error(`Vitals gate: crash rate ${String(latest)}% > threshold ${String(threshold)}%. Rollout halted.`);\n process.exit(6);\n }\n } catch (vitalsErr) {\n console.error(`Warning: Vitals gate check failed: ${vitalsErr instanceof Error ? vitalsErr.message : String(vitalsErr)}`);\n }\n }\n }\n\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n }\n\n // Release notes\n releases\n .command(\"notes\")\n .description(\"Get or set release notes\")\n .argument(\"<action>\", \"Action: get|set\")\n .option(\"--track <track>\", \"Track name\")\n .option(\"--lang <language>\", \"Language code\", \"en-US\")\n .option(\"--notes <text>\", \"Release notes text\")\n .option(\"--file <path>\", \"Read notes from file\")\n .action(async (action: string, options) => {\n if (action === \"set\") {\n console.error(\n \"Error: gpc releases notes set is not implemented as a standalone command.\\n\" +\n \"Use --notes, --notes-dir, or --notes-from-git with:\\n\" +\n \" gpc releases upload\\n\" +\n \" gpc publish\"\n );\n process.exit(1);\n }\n\n if (action === \"get\") {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n const track = options.track ?? \"internal\";\n const statuses = await getReleasesStatus(client, packageName, track);\n const notes = Array.isArray(statuses)\n ? statuses.flatMap((s: any) => s.releaseNotes ?? [])\n : (statuses as any).releaseNotes ?? [];\n if (notes.length === 0) {\n console.log(\"No release notes found.\");\n return;\n }\n console.log(formatOutput(notes, format));\n return;\n }\n\n console.error(\"Usage: gpc releases notes <get|set> --track <track>\");\n process.exit(2);\n });\n\n // Upload externally hosted APK\n releases\n .command(\"upload-external\")\n .description(\"Upload an externally hosted APK configuration\")\n .requiredOption(\"--url <url>\", \"External URL where the APK is hosted\")\n .requiredOption(\"--file <config>\", \"Path to JSON config file with APK metadata\")\n .action(async (options: { url: string; file: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n try {\n const { readFile } = await import(\"node:fs/promises\");\n const raw = await readFile(options.file, \"utf-8\");\n const apkConfig = JSON.parse(raw) as Record<string, unknown>;\n\n // Override with CLI-provided URL\n apkConfig[\"externallyHostedUrl\"] = options.url;\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const result = await uploadExternallyHosted(\n client,\n packageName,\n apkConfig as import(\"@gpc-cli/api\").ExternallyHostedApk,\n );\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Diff\n releases\n .command(\"diff\")\n .description(\"Compare releases between two tracks\")\n .option(\"--from <track>\", \"Source track\", \"internal\")\n .option(\"--to <track>\", \"Target track\", \"production\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await diffReleases(client, packageName, options.from, options.to);\n if (result.diffs.length === 0) {\n console.log(`No differences between ${result.fromTrack} and ${result.toTrack}.`);\n } else {\n if (format === \"json\") {\n console.log(formatOutput(result, format));\n } else {\n console.log(`Differences: ${result.fromTrack} vs ${result.toTrack}\\n`);\n console.log(formatOutput(result.diffs, format));\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":["rollout"]}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ checkForUpdate,
4
+ fetchChecksums,
5
+ getCurrentBinaryPath,
6
+ getPlatformAsset,
7
+ updateBinaryInPlace,
8
+ updateViaBrew,
9
+ updateViaNpm
10
+ } from "./chunk-UH3TMIAL.js";
11
+ import "./chunk-4O4D5SGL.js";
12
+
13
+ // src/commands/update.ts
14
+ import { createSpinner } from "@gpc-cli/core";
15
+ function registerUpdateCommand(program) {
16
+ program.command("update").description("Update gpc to the latest version").option("--check", "Check for updates without installing (exits 0 always)").option("--force", "Update even if already on the latest version").action(async (opts, cmd) => {
17
+ const parentOpts = cmd.parent?.opts() ?? {};
18
+ const jsonMode = !!(parentOpts["json"] || parentOpts["output"] === "json");
19
+ const currentVersion = process.env["__GPC_VERSION"] ?? "0.0.0";
20
+ if (currentVersion === "0.0.0") {
21
+ if (jsonMode) {
22
+ console.log(
23
+ JSON.stringify({
24
+ success: false,
25
+ reason: "Cannot update a development build",
26
+ current: currentVersion
27
+ })
28
+ );
29
+ } else {
30
+ console.log("Cannot update a development build (version: 0.0.0).");
31
+ }
32
+ return;
33
+ }
34
+ const spinner = createSpinner("Checking for updates...");
35
+ spinner.start();
36
+ let result;
37
+ try {
38
+ result = await checkForUpdate(currentVersion);
39
+ } catch (err) {
40
+ spinner.fail("Failed to check for updates");
41
+ throw err;
42
+ }
43
+ if (opts.check) {
44
+ spinner.stop();
45
+ if (jsonMode) {
46
+ console.log(
47
+ JSON.stringify({
48
+ current: result.current,
49
+ latest: result.latest,
50
+ updateAvailable: result.updateAvailable,
51
+ installMethod: result.installMethod,
52
+ releaseUrl: result.release.html_url
53
+ })
54
+ );
55
+ } else if (result.updateAvailable) {
56
+ console.log(`Update available: ${result.current} \u2192 ${result.latest}`);
57
+ console.log(`Install method: ${result.installMethod}`);
58
+ console.log(`Release: ${result.release.html_url}`);
59
+ console.log(`
60
+ Run: gpc update`);
61
+ } else {
62
+ console.log(`Already on latest version: v${result.current}`);
63
+ console.log(`Install method: ${result.installMethod}`);
64
+ }
65
+ return;
66
+ }
67
+ if (!result.updateAvailable && !opts.force) {
68
+ spinner.stop(`Already on latest version: v${result.current}`);
69
+ if (jsonMode) {
70
+ console.log(
71
+ JSON.stringify({
72
+ success: true,
73
+ current: result.current,
74
+ latest: result.latest,
75
+ updated: false,
76
+ installMethod: result.installMethod
77
+ })
78
+ );
79
+ }
80
+ return;
81
+ }
82
+ spinner.update(
83
+ `Updating v${result.current} \u2192 v${result.latest} (${result.installMethod})...`
84
+ );
85
+ switch (result.installMethod) {
86
+ case "npm":
87
+ spinner.stop();
88
+ await updateViaNpm({ silent: jsonMode });
89
+ break;
90
+ case "homebrew":
91
+ spinner.stop();
92
+ await updateViaBrew({ silent: jsonMode });
93
+ break;
94
+ case "binary": {
95
+ const assetName = getPlatformAsset();
96
+ if (!assetName) {
97
+ spinner.fail();
98
+ console.error(
99
+ `Error: Unsupported platform: ${process.platform}/${process.arch}`
100
+ );
101
+ console.error(
102
+ `Download manually: ${result.release.html_url}`
103
+ );
104
+ process.exit(1);
105
+ }
106
+ const assetObj = result.release.assets.find((a) => a.name === assetName);
107
+ if (!assetObj) {
108
+ spinner.fail();
109
+ console.error(
110
+ `Error: No binary found for ${assetName} in release ${result.latestTag}`
111
+ );
112
+ console.error(`Check: ${result.release.html_url}`);
113
+ process.exit(1);
114
+ }
115
+ const sizeMB = (assetObj.size / (1024 * 1024)).toFixed(1);
116
+ spinner.stop();
117
+ const checksums = await fetchChecksums(result.release);
118
+ const expectedHash = checksums.get(assetName) ?? "";
119
+ const binaryPath = getCurrentBinaryPath();
120
+ if (jsonMode) {
121
+ await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath);
122
+ } else {
123
+ const label = `Downloading ${assetName} (${sizeMB} MB)`;
124
+ process.stdout.write(`${label}...
125
+ `);
126
+ let lastPct = -1;
127
+ await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath, {
128
+ onProgress(downloaded, total) {
129
+ if (total <= 0) return;
130
+ const pct = Math.min(100, Math.round(downloaded / total * 100));
131
+ if (pct === lastPct) return;
132
+ lastPct = pct;
133
+ const dlMB = (downloaded / (1024 * 1024)).toFixed(1);
134
+ process.stdout.write(
135
+ `\r${label} ${dlMB} / ${sizeMB} MB (${String(pct).padStart(3)}%) `
136
+ );
137
+ }
138
+ });
139
+ process.stdout.write("\n");
140
+ }
141
+ break;
142
+ }
143
+ case "unknown":
144
+ spinner.fail();
145
+ console.error("Error: Could not detect install method. Update manually:");
146
+ console.error(` npm: npm install -g @gpc-cli/cli@latest`);
147
+ console.error(` Homebrew: brew upgrade yasserstudio/tap/gpc`);
148
+ console.error(` Binary: https://github.com/yasserstudio/gpc/releases/latest`);
149
+ process.exit(1);
150
+ }
151
+ if (jsonMode) {
152
+ console.log(
153
+ JSON.stringify({
154
+ success: true,
155
+ previous: result.current,
156
+ current: result.latest,
157
+ method: result.installMethod
158
+ })
159
+ );
160
+ } else {
161
+ console.log(`
162
+ \u2714 Updated to v${result.latest}`);
163
+ }
164
+ });
165
+ }
166
+ export {
167
+ registerUpdateCommand
168
+ };
169
+ //# sourceMappingURL=update-NIVJLUNH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/update.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport {\n checkForUpdate,\n fetchChecksums,\n updateViaNpm,\n updateViaBrew,\n updateBinaryInPlace,\n getPlatformAsset,\n getCurrentBinaryPath,\n} from \"../updater.js\";\nimport { createSpinner } from \"@gpc-cli/core\";\n\nexport function registerUpdateCommand(program: Command): void {\n program\n .command(\"update\")\n .description(\"Update gpc to the latest version\")\n .option(\"--check\", \"Check for updates without installing (exits 0 always)\")\n .option(\"--force\", \"Update even if already on the latest version\")\n .action(async (opts: { check?: boolean; force?: boolean }, cmd) => {\n const parentOpts = (cmd.parent?.opts() ?? {}) as Record<string, unknown>;\n const jsonMode = !!(parentOpts[\"json\"] || parentOpts[\"output\"] === \"json\");\n const currentVersion = process.env[\"__GPC_VERSION\"] ?? \"0.0.0\";\n\n // Dev build guard\n if (currentVersion === \"0.0.0\") {\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: false,\n reason: \"Cannot update a development build\",\n current: currentVersion,\n }),\n );\n } else {\n console.log(\"Cannot update a development build (version: 0.0.0).\");\n }\n return;\n }\n\n const spinner = createSpinner(\"Checking for updates...\");\n spinner.start();\n\n let result;\n try {\n result = await checkForUpdate(currentVersion);\n } catch (err) {\n spinner.fail(\"Failed to check for updates\");\n throw err;\n }\n\n // --check mode: always exit 0, communicate via output\n if (opts.check) {\n spinner.stop();\n if (jsonMode) {\n console.log(\n JSON.stringify({\n current: result.current,\n latest: result.latest,\n updateAvailable: result.updateAvailable,\n installMethod: result.installMethod,\n releaseUrl: result.release.html_url,\n }),\n );\n } else if (result.updateAvailable) {\n console.log(`Update available: ${result.current} → ${result.latest}`);\n console.log(`Install method: ${result.installMethod}`);\n console.log(`Release: ${result.release.html_url}`);\n console.log(`\\nRun: gpc update`);\n } else {\n console.log(`Already on latest version: v${result.current}`);\n console.log(`Install method: ${result.installMethod}`);\n }\n return;\n }\n\n // Already up to date\n if (!result.updateAvailable && !opts.force) {\n spinner.stop(`Already on latest version: v${result.current}`);\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n current: result.current,\n latest: result.latest,\n updated: false,\n installMethod: result.installMethod,\n }),\n );\n }\n return;\n }\n\n spinner.update(\n `Updating v${result.current} → v${result.latest} (${result.installMethod})...`,\n );\n\n switch (result.installMethod) {\n case \"npm\":\n spinner.stop();\n await updateViaNpm({ silent: jsonMode });\n break;\n\n case \"homebrew\":\n spinner.stop();\n await updateViaBrew({ silent: jsonMode });\n break;\n\n case \"binary\": {\n const assetName = getPlatformAsset();\n if (!assetName) {\n spinner.fail();\n console.error(\n `Error: Unsupported platform: ${process.platform}/${process.arch}`,\n );\n console.error(\n `Download manually: ${result.release.html_url}`,\n );\n process.exit(1);\n }\n\n const assetObj = result.release.assets.find((a) => a.name === assetName);\n if (!assetObj) {\n spinner.fail();\n console.error(\n `Error: No binary found for ${assetName} in release ${result.latestTag}`,\n );\n console.error(`Check: ${result.release.html_url}`);\n process.exit(1);\n }\n\n const sizeMB = (assetObj.size / (1024 * 1024)).toFixed(1);\n spinner.stop();\n\n const checksums = await fetchChecksums(result.release);\n const expectedHash = checksums.get(assetName) ?? \"\";\n const binaryPath = getCurrentBinaryPath();\n\n if (jsonMode) {\n await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath);\n } else {\n // Show live download progress on a single overwriting line\n const label = `Downloading ${assetName} (${sizeMB} MB)`;\n process.stdout.write(`${label}...\\n`);\n let lastPct = -1;\n await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath, {\n onProgress(downloaded, total) {\n if (total <= 0) return;\n const pct = Math.min(100, Math.round((downloaded / total) * 100));\n if (pct === lastPct) return; // avoid redundant writes\n lastPct = pct;\n const dlMB = (downloaded / (1024 * 1024)).toFixed(1);\n process.stdout.write(\n `\\r${label} ${dlMB} / ${sizeMB} MB (${String(pct).padStart(3)}%) `,\n );\n },\n });\n process.stdout.write(\"\\n\");\n }\n break;\n }\n\n case \"unknown\":\n spinner.fail();\n console.error(\"Error: Could not detect install method. Update manually:\");\n console.error(` npm: npm install -g @gpc-cli/cli@latest`);\n console.error(` Homebrew: brew upgrade yasserstudio/tap/gpc`);\n console.error(` Binary: https://github.com/yasserstudio/gpc/releases/latest`);\n process.exit(1);\n }\n\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n previous: result.current,\n current: result.latest,\n method: result.installMethod,\n }),\n );\n } else {\n console.log(`\\n✔ Updated to v${result.latest}`);\n }\n });\n}\n"],"mappings":"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","names":[]}
File without changes
File without changes
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ detectInstallMethod
4
+ } from "./chunk-UH3TMIAL.js";
5
+ import "./chunk-4O4D5SGL.js";
6
+
7
+ // src/commands/version.ts
8
+ function registerVersionCommand(program) {
9
+ program.command("version").description("Show version information").action(() => {
10
+ const version = process.env["__GPC_VERSION"] || "0.0.0";
11
+ if (program.opts()["output"] === "json") {
12
+ console.log(JSON.stringify({
13
+ version,
14
+ node: process.version,
15
+ platform: `${process.platform}/${process.arch}`,
16
+ installMethod: detectInstallMethod()
17
+ }));
18
+ } else {
19
+ console.log(version);
20
+ }
21
+ });
22
+ }
23
+ export {
24
+ registerVersionCommand
25
+ };
26
+ //# sourceMappingURL=version-7AI5IHVK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/version.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { detectInstallMethod } from \"../updater.js\";\n\nexport function registerVersionCommand(program: Command): void {\n program\n .command(\"version\")\n .description(\"Show version information\")\n .action(() => {\n const version = process.env[\"__GPC_VERSION\"] || \"0.0.0\";\n if (program.opts()[\"output\"] === \"json\") {\n console.log(JSON.stringify({\n version,\n node: process.version,\n platform: `${process.platform}/${process.arch}`,\n installMethod: detectInstallMethod(),\n }));\n } else {\n console.log(version);\n }\n });\n}\n"],"mappings":";;;;;;;AAGO,SAAS,uBAAuB,SAAwB;AAC7D,UACG,QAAQ,SAAS,EACjB,YAAY,0BAA0B,EACtC,OAAO,MAAM;AACZ,UAAM,UAAU,QAAQ,IAAI,eAAe,KAAK;AAChD,QAAI,QAAQ,KAAK,EAAE,QAAQ,MAAM,QAAQ;AACvC,cAAQ,IAAI,KAAK,UAAU;AAAA,QACzB;AAAA,QACA,MAAM,QAAQ;AAAA,QACd,UAAU,GAAG,QAAQ,QAAQ,IAAI,QAAQ,IAAI;AAAA,QAC7C,eAAe,oBAAoB;AAAA,MACrC,CAAC,CAAC;AAAA,IACJ,OAAO;AACL,cAAQ,IAAI,OAAO;AAAA,IACrB;AAAA,EACF,CAAC;AACL;","names":[]}
File without changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gpc-cli/cli",
3
- "version": "0.9.31",
4
- "description": "The complete Google Play CLI",
3
+ "version": "0.9.33",
4
+ "description": "GPC Google Play Console CLI. 187 API endpoints, one tool.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "gpc": "./dist/bin.js"
@@ -17,29 +17,26 @@
17
17
  "files": [
18
18
  "dist"
19
19
  ],
20
- "scripts": {
21
- "build": "tsup",
22
- "dev": "tsup --watch",
23
- "test": "vitest run",
24
- "test:watch": "vitest",
25
- "lint": "eslint src/",
26
- "typecheck": "tsc --noEmit",
27
- "clean": "rm -rf dist"
28
- },
29
20
  "dependencies": {
30
- "@gpc-cli/api": "workspace:*",
31
- "@gpc-cli/auth": "workspace:^",
32
- "@gpc-cli/config": "workspace:*",
33
- "@gpc-cli/core": "workspace:*",
34
- "@gpc-cli/plugin-sdk": "workspace:*",
35
- "commander": "^14.0.3"
21
+ "commander": "^14.0.3",
22
+ "@gpc-cli/api": "1.0.18",
23
+ "@gpc-cli/plugin-sdk": "0.9.7",
24
+ "@gpc-cli/auth": "^0.9.10",
25
+ "@gpc-cli/config": "0.9.9",
26
+ "@gpc-cli/core": "0.9.28"
36
27
  },
37
28
  "keywords": [
38
29
  "google-play",
30
+ "google-play-console",
31
+ "google-play-console-cli",
39
32
  "cli",
40
33
  "android",
41
34
  "play-store",
42
- "play-console"
35
+ "play-console",
36
+ "fastlane-alternative",
37
+ "release-automation",
38
+ "devops",
39
+ "ci-cd"
43
40
  ],
44
41
  "engines": {
45
42
  "node": ">=20"
@@ -50,5 +47,14 @@
50
47
  },
51
48
  "devDependencies": {
52
49
  "@types/node": "^25.3.5"
50
+ },
51
+ "scripts": {
52
+ "build": "tsup",
53
+ "dev": "tsup --watch",
54
+ "test": "vitest run",
55
+ "test:watch": "vitest",
56
+ "lint": "eslint src/",
57
+ "typecheck": "tsc --noEmit",
58
+ "clean": "rm -rf dist"
53
59
  }
54
- }
60
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/plugins.ts","../src/program.ts","../src/error-handler.ts"],"sourcesContent":["import { PluginManager, discoverPlugins } from \"@gpc-cli/core\";\nimport type { Command } from \"commander\";\n\n/**\n * Load and initialize all plugins.\n * First-party plugins (@gpc-cli/*) are auto-trusted.\n * Third-party plugins require prior approval stored in config.\n * Plugin loading is disabled in standalone binary mode.\n */\nexport async function loadPlugins(): Promise<PluginManager> {\n const manager = new PluginManager();\n\n // Standalone binary cannot resolve external npm packages at runtime\n if (process.env[\"__GPC_BINARY\"] === \"1\") {\n return manager;\n }\n\n try {\n const { loadConfig } = await import(\"@gpc-cli/config\");\n const config = await loadConfig();\n const plugins = await discoverPlugins({ configPlugins: config.plugins });\n const approved = new Set(config.approvedPlugins ?? []);\n\n for (const plugin of plugins) {\n const isTrusted = plugin.name.startsWith(\"@gpc-cli/\");\n\n if (!isTrusted && !approved.has(plugin.name)) {\n // Skip unapproved third-party plugins silently in non-interactive mode\n // In interactive mode, the user would run `gpc plugins approve <name>` first\n const isQuiet = process.argv.includes(\"--quiet\") || process.argv.includes(\"-q\");\n if (!isQuiet) {\n console.error(\n `Plugin \"${plugin.name}\" is not approved. Run: gpc plugins approve ${plugin.name}`,\n );\n }\n continue;\n }\n\n try {\n await manager.load(plugin);\n } catch {\n // Skip plugins that fail to load — don't block the CLI\n }\n }\n } catch {\n // Config loading failure shouldn't block plugin-free commands\n }\n\n return manager;\n}\n\n/**\n * Register plugin-defined commands with the Commander program.\n */\nexport function registerPluginCommands(program: Command, manager: PluginManager): void {\n for (const def of manager.getRegisteredCommands()) {\n const cmd = program.command(def.name).description(def.description);\n\n if (def.arguments) {\n for (const arg of def.arguments) {\n const syntax = arg.required ? `<${arg.name}>` : `[${arg.name}]`;\n cmd.argument(syntax, arg.description);\n }\n }\n\n if (def.options) {\n for (const opt of def.options) {\n cmd.option(\n opt.flags,\n opt.description,\n opt.defaultValue as string | boolean | string[] | undefined,\n );\n }\n }\n\n cmd.action(async (...rawArgs: unknown[]) => {\n const opts = rawArgs[rawArgs.length - 2] as Record<string, unknown>;\n const args: Record<string, unknown> = {};\n\n if (def.arguments) {\n def.arguments.forEach((argDef, i) => {\n args[argDef.name] = rawArgs[i];\n });\n }\n\n await def.action(args, opts);\n });\n }\n}\n","import { Command } from \"commander\";\nimport type { PluginManager } from \"@gpc-cli/core\";\nimport type { CommandEvent, CommandResult } from \"@gpc-cli/plugin-sdk\";\nimport { registerPluginCommands } from \"./plugins.js\";\n\nexport async function createProgram(pluginManager?: PluginManager): Promise<Command> {\n const program = new Command();\n\n program\n .name(\"gpc\")\n .description(\"The complete Google Play CLI\")\n .version(process.env[\"__GPC_VERSION\"] || \"0.0.0\", \"-V, --version\")\n .option(\"-o, --output <format>\", \"Output format: table, json, yaml, markdown, junit\")\n .option(\"-v, --verbose\", \"Enable debug logging\")\n .option(\"-q, --quiet\", \"Suppress non-essential output\")\n .option(\"-a, --app <package>\", \"App package name\")\n .option(\"-p, --profile <name>\", \"Auth profile name\")\n .option(\"--no-color\", \"Disable colored output\")\n .option(\"--no-interactive\", \"Disable interactive prompts\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .option(\"--dry-run\", \"Preview changes without executing\")\n .option(\"--notify [target]\", \"Send webhook notification on completion (slack, discord, custom)\")\n .option(\"--ci\", \"Force CI mode (JSON output, no prompts, strict exit codes)\")\n .option(\"-j, --json\", \"Shorthand for --output json\")\n .showSuggestionAfterError(true);\n\n const commandLoaders: Record<string, () => Promise<void>> = {\n auth: async () => {\n (await import(\"./commands/auth.js\")).registerAuthCommands(program);\n },\n config: async () => {\n (await import(\"./commands/config.js\")).registerConfigCommands(program);\n },\n doctor: async () => {\n (await import(\"./commands/doctor.js\")).registerDoctorCommand(program);\n },\n update: async () => {\n (await import(\"./commands/update.js\")).registerUpdateCommand(program);\n },\n docs: async () => {\n (await import(\"./commands/docs.js\")).registerDocsCommand(program);\n },\n completion: async () => {\n (await import(\"./commands/completion.js\")).registerCompletionCommand(program);\n },\n apps: async () => {\n (await import(\"./commands/apps.js\")).registerAppsCommands(program);\n },\n releases: async () => {\n (await import(\"./commands/releases.js\")).registerReleasesCommands(program);\n },\n tracks: async () => {\n (await import(\"./commands/tracks.js\")).registerTracksCommands(program);\n },\n status: async () => {\n (await import(\"./commands/status.js\")).registerStatusCommand(program);\n },\n listings: async () => {\n (await import(\"./commands/listings.js\")).registerListingsCommands(program);\n },\n reviews: async () => {\n (await import(\"./commands/reviews.js\")).registerReviewsCommands(program);\n },\n vitals: async () => {\n (await import(\"./commands/vitals.js\")).registerVitalsCommands(program);\n },\n subscriptions: async () => {\n (await import(\"./commands/subscriptions.js\")).registerSubscriptionsCommands(program);\n },\n iap: async () => {\n (await import(\"./commands/iap.js\")).registerIapCommands(program);\n },\n purchases: async () => {\n (await import(\"./commands/purchases.js\")).registerPurchasesCommands(program);\n },\n pricing: async () => {\n (await import(\"./commands/pricing.js\")).registerPricingCommands(program);\n },\n reports: async () => {\n (await import(\"./commands/reports.js\")).registerReportsCommands(program);\n },\n users: async () => {\n (await import(\"./commands/users.js\")).registerUsersCommands(program);\n },\n testers: async () => {\n (await import(\"./commands/testers.js\")).registerTestersCommands(program);\n },\n validate: async () => {\n (await import(\"./commands/validate.js\")).registerValidateCommand(program);\n },\n publish: async () => {\n (await import(\"./commands/publish.js\")).registerPublishCommand(program);\n },\n recovery: async () => {\n (await import(\"./commands/recovery.js\")).registerRecoveryCommands(program);\n },\n \"data-safety\": async () => {\n (await import(\"./commands/data-safety.js\")).registerDataSafetyCommands(program);\n },\n \"external-transactions\": async () => {\n (await import(\"./commands/external-transactions.js\")).registerExternalTransactionsCommands(\n program,\n );\n },\n \"device-tiers\": async () => {\n (await import(\"./commands/device-tiers.js\")).registerDeviceTiersCommands(program);\n },\n \"one-time-products\": async () => {\n (await import(\"./commands/one-time-products.js\")).registerOneTimeProductsCommands(program);\n },\n \"internal-sharing\": async () => {\n (await import(\"./commands/internal-sharing.js\")).registerInternalSharingCommands(program);\n },\n \"generated-apks\": async () => {\n (await import(\"./commands/generated-apks.js\")).registerGeneratedApksCommands(program);\n },\n \"purchase-options\": async () => {\n (await import(\"./commands/purchase-options.js\")).registerPurchaseOptionsCommands(program);\n },\n bundle: async () => {\n (await import(\"./commands/bundle.js\")).registerBundleCommands(program);\n },\n audit: async () => {\n (await import(\"./commands/audit.js\")).registerAuditCommands(program);\n },\n migrate: async () => {\n (await import(\"./commands/migrate.js\")).registerMigrateCommands(program);\n },\n \"install-skills\": async () => {\n (await import(\"./commands/install-skills.js\")).registerInstallSkillsCommand(program);\n },\n plugins: async () => {\n registerPluginsCommand(program, pluginManager);\n },\n };\n\n // Resolve command aliases for lazy loading\n const commandAliases: Record<string, string> = {\n \"ext-txn\": \"external-transactions\",\n otp: \"one-time-products\",\n };\n\n const rawTarget = process.argv[2];\n const target = rawTarget ? (commandAliases[rawTarget] ?? rawTarget) : undefined;\n\n const loader = target ? commandLoaders[target] : undefined;\n if (loader) {\n await loader();\n } else {\n await Promise.all(Object.values(commandLoaders).map((loader) => loader()));\n }\n\n // Register plugin-defined commands\n if (pluginManager) {\n registerPluginCommands(program, pluginManager);\n }\n\n // Wire plugin lifecycle hooks around command execution\n if (pluginManager) {\n wrapCommandHooks(program, pluginManager);\n }\n\n return program;\n}\n\n/**\n * `gpc plugins` — manage plugins.\n */\nfunction registerPluginsCommand(program: Command, manager?: PluginManager): void {\n const cmd = program.command(\"plugins\").description(\"Manage plugins\");\n\n cmd\n .command(\"list\")\n .description(\"List loaded plugins\")\n .action(() => {\n const plugins = manager?.getLoadedPlugins() ?? [];\n const opts = program.opts();\n\n if (opts[\"output\"] === \"json\") {\n console.log(JSON.stringify(plugins, null, 2));\n return;\n }\n\n if (plugins.length === 0) {\n console.log(\"No plugins loaded.\");\n console.log('\\nConfigure plugins in .gpcrc.json: { \"plugins\": [\"@gpc-cli/plugin-ci\"] }');\n return;\n }\n\n console.log(\"Loaded plugins:\\n\");\n for (const p of plugins) {\n const trust = p.trusted ? \"trusted\" : \"third-party\";\n console.log(` ${p.name}@${p.version} (${trust})`);\n }\n\n const commands = manager?.getRegisteredCommands() ?? [];\n if (commands.length > 0) {\n console.log(\"\\nPlugin commands:\\n\");\n for (const c of commands) {\n console.log(` gpc ${c.name} — ${c.description}`);\n }\n }\n });\n\n cmd\n .command(\"init <name>\")\n .description(\"Scaffold a new plugin project\")\n .option(\"-d, --dir <path>\", \"Output directory (defaults to ./gpc-plugin-<name>)\")\n .option(\"--description <text>\", \"Plugin description\")\n .action(async (name: string, opts: { dir?: string; description?: string }) => {\n const { scaffoldPlugin } = await import(\"@gpc-cli/core\");\n const pluginName = name.startsWith(\"gpc-plugin-\") ? name : `gpc-plugin-${name}`;\n const dir = opts.dir ?? `./${pluginName}`;\n\n const result = await scaffoldPlugin({ name, dir, description: opts.description });\n\n console.log(`Plugin scaffolded at ${result.dir}/\\n`);\n console.log(\"Files created:\");\n for (const f of result.files) {\n console.log(` ${f}`);\n }\n console.log(`\\nNext steps:`);\n console.log(` cd ${pluginName}`);\n console.log(` npm install`);\n console.log(` npm run build`);\n console.log(` npm test`);\n });\n\n cmd\n .command(\"approve <name>\")\n .description(\"Approve a third-party plugin for loading\")\n .action(async (name: string) => {\n const { approvePlugin } = await import(\"@gpc-cli/config\");\n await approvePlugin(name);\n console.log(`Plugin \"${name}\" approved. It will be loaded on next run.`);\n });\n\n cmd\n .command(\"revoke <name>\")\n .description(\"Revoke approval for a third-party plugin\")\n .action(async (name: string) => {\n const { revokePluginApproval } = await import(\"@gpc-cli/config\");\n const removed = await revokePluginApproval(name);\n if (removed) {\n console.log(`Plugin \"${name}\" approval revoked.`);\n } else {\n console.log(`Plugin \"${name}\" was not in the approved list.`);\n }\n });\n}\n\n/**\n * Wrap all registered commands so plugin hooks fire before/after each command.\n */\nfunction wrapCommandHooks(program: Command, manager: PluginManager): void {\n program.hook(\"preAction\", async (thisCommand) => {\n const event: CommandEvent = {\n command: getFullCommandName(thisCommand),\n args: thisCommand.opts(),\n app: program.opts()[\"app\"] as string | undefined,\n startedAt: new Date(),\n };\n\n // Store on the command for afterCommand/onError\n (thisCommand as unknown as Record<string, unknown>)[\"__pluginEvent\"] = event;\n\n await manager.runBeforeCommand(event);\n });\n\n program.hook(\"postAction\", async (thisCommand) => {\n const event: CommandEvent = (thisCommand as unknown as Record<string, unknown>)[\n \"__pluginEvent\"\n ] as CommandEvent;\n if (!event) return;\n\n const result: CommandResult = {\n success: true,\n durationMs: Date.now() - event.startedAt.getTime(),\n exitCode: 0,\n };\n\n await manager.runAfterCommand(event, result);\n });\n}\n\nfunction getFullCommandName(cmd: Command): string {\n const parts: string[] = [];\n let current: Command | null = cmd;\n while (current && current.name() !== \"gpc\") {\n parts.unshift(current.name());\n current = current.parent;\n }\n return parts.join(\" \");\n}\n","/**\n * Shared error formatting for CLI output.\n * Extracts error code, message, and suggestion from typed errors (GpcError, AuthError, ApiError, ConfigError).\n */\n\ninterface TypedError {\n message: string;\n code?: string;\n suggestion?: string;\n exitCode?: number;\n}\n\nfunction isTypedError(error: unknown): error is Error & TypedError {\n return error instanceof Error && \"code\" in error && typeof (error as TypedError).code === \"string\";\n}\n\n/**\n * Format an error for CLI output. Prints:\n * Error [CODE]: message\n * Suggestion: suggestion (if available)\n *\n * Returns the appropriate exit code.\n */\nexport function handleCliError(error: unknown): number {\n if (isTypedError(error)) {\n console.error(`Error [${error.code}]: ${error.message}`);\n if (error.suggestion) {\n console.error(`Suggestion: ${error.suggestion}`);\n }\n return error.exitCode ?? 1;\n }\n\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${message}`);\n return 1;\n}\n"],"mappings":"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","names":["loader"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/releases.ts"],"sourcesContent":["import { appendFile, stat } from \"node:fs/promises\";\nimport { basename } from \"node:path\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport type { RetryLogEntry } from \"@gpc-cli/api\";\nimport {\n uploadRelease,\n getReleasesStatus,\n promoteRelease,\n updateRollout,\n readReleaseNotesFromDir,\n generateNotesFromGit,\n writeAuditLog,\n createAuditEntry,\n uploadExternallyHosted,\n diffReleases,\n} from \"@gpc-cli/core\";\nimport { formatOutput, sortResults, createSpinner } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, promptSelect, promptInput, requireOption } from \"../prompt.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nfunction createRetryLogger(retryLogPath?: string): ((entry: RetryLogEntry) => void) | undefined {\n if (!retryLogPath) return undefined;\n return (entry: RetryLogEntry) => {\n const line = JSON.stringify(entry) + \"\\n\";\n appendFile(retryLogPath, line).catch(() => {});\n };\n}\n\nasync function getClient(config: GpcConfig, retryLogPath?: string, uploadTimeout?: number) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth, onRetry: createRetryLogger(retryLogPath), uploadTimeout });\n}\n\nexport function registerReleasesCommands(program: Command): void {\n const releases = program.command(\"releases\").description(\"Manage releases and rollouts\");\n\n // Upload\n releases\n .command(\"upload <file>\")\n .description(\"Upload AAB/APK and assign to a track\")\n .option(\"--track <track>\", \"Target track\", \"internal\")\n .option(\"--rollout <percent>\", \"Staged rollout percentage (1-100)\")\n .option(\"--notes <text>\", \"Release notes (en-US)\")\n .option(\"--name <name>\", \"Release name\")\n .option(\"--mapping <file>\", \"ProGuard/R8 mapping file for deobfuscation\")\n .option(\"--notes-dir <dir>\", \"Read release notes from directory (<dir>/<lang>.txt)\")\n .option(\"--notes-from-git\", \"Generate release notes from git commit history\")\n .option(\"--since <ref>\", \"Git ref to start from (tag, SHA) — used with --notes-from-git\")\n .option(\"--retry-log <path>\", \"Write retry log entries to file (JSONL)\")\n .option(\"--timeout <ms>\", \"Upload timeout in milliseconds (auto-scales with file size by default)\", parseInt)\n .action(async (file: string, options) => {\n try {\n await stat(file);\n } catch {\n console.error(`Error: File not found: ${file}`);\n process.exit(2);\n }\n\n const noteSources = [options.notes, options.notesDir, options.notesFromGit].filter(Boolean);\n if (noteSources.length > 1) {\n console.error(\"Error: Cannot combine --notes, --notes-dir, and --notes-from-git. Use only one.\");\n process.exit(2);\n }\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n // Interactive mode: prompt for missing options\n if (isInteractive(program)) {\n if (!options.track || options.track === \"internal\") {\n const tracks = [\"internal\", \"alpha\", \"beta\", \"production\"];\n options.track = await promptSelect(\"Select track:\", tracks, \"internal\");\n }\n\n if (!options.rollout && options.track === \"production\") {\n const rolloutStr = await promptInput(\n \"Staged rollout percentage (1-100, blank for full)\",\n \"100\",\n );\n if (rolloutStr && rolloutStr !== \"100\") {\n options.rollout = rolloutStr;\n }\n }\n\n if (!options.notes && !options.notesDir) {\n const notes = await promptInput(\"Release notes (en-US, blank to skip)\");\n if (notes) options.notes = notes;\n }\n }\n\n if (options.rollout !== undefined) {\n const rollout = Number(options.rollout);\n if (!Number.isFinite(rollout) || rollout < 1 || rollout > 100) {\n console.error(`Error: --rollout must be a number between 1 and 100 (got: ${options.rollout})`);\n process.exit(2);\n }\n }\n\n const { size: fileSize } = await stat(file);\n const client = await getClient(config, options.retryLog, options.timeout);\n\n if (isDryRun(program)) {\n try {\n const result = await uploadRelease(client, packageName, file, {\n track: options.track,\n userFraction: options.rollout ? Number(options.rollout) / 100 : undefined,\n dryRun: true,\n });\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n return;\n }\n\n const auditEntry = createAuditEntry(\n \"releases upload\",\n {\n file,\n track: options.track,\n rollout: options.rollout,\n },\n packageName,\n );\n\n const sizeMB = (fileSize / (1024 * 1024)).toFixed(1);\n const spinner = createSpinner(`Uploading ${basename(file)} (${sizeMB} MB)...`);\n if (!program.opts()[\"quiet\"] && process.stderr.isTTY) spinner.start();\n\n try {\n let releaseNotes: { language: string; text: string }[] | undefined;\n if (options.notesFromGit) {\n const gitNotes = await generateNotesFromGit({ since: options.since });\n releaseNotes = [{ language: gitNotes.language, text: gitNotes.text }];\n } else if (options.notesDir) {\n releaseNotes = await readReleaseNotesFromDir(options.notesDir);\n } else if (options.notes) {\n releaseNotes = [{ language: \"en-US\", text: options.notes }];\n }\n\n const result = await uploadRelease(client, packageName, file, {\n track: options.track,\n userFraction: options.rollout ? Number(options.rollout) / 100 : undefined,\n releaseNotes,\n releaseName: options.name,\n mappingFile: options.mapping,\n });\n spinner.stop(\"Upload complete\");\n console.log(formatOutput(result, format));\n auditEntry.success = true;\n } catch (error) {\n spinner.fail(\"Upload failed\");\n auditEntry.success = false;\n auditEntry.error = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n } finally {\n auditEntry.durationMs = Date.now() - new Date(auditEntry.timestamp).getTime();\n writeAuditLog(auditEntry).catch(() => {});\n }\n });\n\n // Status\n releases\n .command(\"status\")\n .description(\"Show current release status across tracks\")\n .option(\"--track <track>\", \"Filter by track\")\n .option(\"--sort <field>\", \"Sort by field (prefix with - for descending)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const TRACK_ORDER = [\"production\", \"beta\", \"alpha\", \"internal\"];\n const statuses = await getReleasesStatus(client, packageName, options.track);\n const sorted = Array.isArray(statuses)\n ? options.sort\n ? sortResults(statuses, options.sort)\n : [...statuses].sort((a, b) => {\n const ai = TRACK_ORDER.indexOf(String((a as Record<string, unknown>)[\"track\"] ?? \"\"));\n const bi = TRACK_ORDER.indexOf(String((b as Record<string, unknown>)[\"track\"] ?? \"\"));\n return (ai === -1 ? 99 : ai) - (bi === -1 ? 99 : bi);\n })\n : statuses;\n if (format !== \"json\" && Array.isArray(sorted)) {\n const rows = sorted.map((s: Record<string, unknown>) => ({\n track: s[\"track\"] || \"-\",\n status: s[\"status\"] || \"-\",\n name: s[\"name\"] || \"-\",\n versionCodes: Array.isArray(s[\"versionCodes\"]) ? (s[\"versionCodes\"] as unknown[]).join(\", \") : \"-\",\n userFraction: s[\"userFraction\"] !== undefined\n ? `${Math.round(Number(s[\"userFraction\"]) * 100)}%`\n : \"—\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(sorted, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Promote\n releases\n .command(\"promote\")\n .description(\"Promote a release from one track to another\")\n .option(\"--from <track>\", \"Source track\")\n .option(\"--to <track>\", \"Target track\")\n .option(\"--rollout <percent>\", \"Staged rollout percentage\")\n .option(\"--notes <text>\", \"Release notes\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n const tracks = [\"internal\", \"alpha\", \"beta\", \"production\"];\n\n options.from = await requireOption(\n \"from\",\n options.from,\n {\n message: \"Source track:\",\n choices: tracks,\n },\n interactive,\n );\n\n options.to = await requireOption(\n \"to\",\n options.to,\n {\n message: \"Target track:\",\n choices: tracks.filter((t: string) => t !== options.from),\n },\n interactive,\n );\n\n if (options.from === options.to) {\n console.error(`Error: --from and --to must be different tracks (both are \"${options.from}\")`);\n process.exit(2);\n }\n\n if (options.rollout !== undefined) {\n const rollout = Number(options.rollout);\n if (!Number.isFinite(rollout) || rollout < 1 || rollout > 100) {\n console.error(`Error: --rollout must be a number between 1 and 100 (got: ${options.rollout})`);\n process.exit(2);\n }\n }\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"releases promote\",\n action: \"promote\",\n target: `${options.from} → ${options.to}`,\n details: { rollout: options.rollout },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await promoteRelease(client, packageName, options.from, options.to, {\n userFraction: options.rollout ? Number(options.rollout) / 100 : undefined,\n releaseNotes: options.notes ? [{ language: \"en-US\", text: options.notes }] : undefined,\n });\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Rollout subcommands\n const rollout = releases.command(\"rollout\").description(\"Manage staged rollouts\");\n\n for (const action of [\"increase\", \"halt\", \"resume\", \"complete\"] as const) {\n const cmd = rollout\n .command(action)\n .description(`${action.charAt(0).toUpperCase() + action.slice(1)} a staged rollout`)\n .option(\"--track <track>\", \"Track name\");\n\n if (action === \"increase\") {\n cmd.option(\"--to <percent>\", \"New rollout percentage\");\n }\n\n cmd.action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n const tracks = [\"internal\", \"alpha\", \"beta\", \"production\"];\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: tracks,\n },\n interactive,\n );\n\n if (action === \"increase\") {\n options.to = await requireOption(\n \"to\",\n options.to,\n {\n message: \"New rollout percentage (1-100):\",\n },\n interactive,\n );\n }\n\n if (action === \"increase\" && options.to !== undefined) {\n const to = Number(options.to);\n if (!Number.isFinite(to) || to < 1 || to > 100) {\n console.error(`Error: --to must be a number between 1 and 100 (got: ${options.to})`);\n process.exit(2);\n }\n }\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: `releases rollout ${action}`,\n action: action,\n target: options.track,\n details: { percentage: options.to !== undefined ? `${options.to}%` : undefined },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await updateRollout(\n client,\n packageName,\n options.track,\n action,\n options.to ? Number(options.to) / 100 : undefined,\n );\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n }\n\n // Release notes\n releases\n .command(\"notes\")\n .description(\"Set release notes\")\n .argument(\"<action>\", \"Action: set\")\n .option(\"--track <track>\", \"Track name\")\n .option(\"--lang <language>\", \"Language code\", \"en-US\")\n .option(\"--notes <text>\", \"Release notes text\")\n .option(\"--file <path>\", \"Read notes from file\")\n .action(async (action: string, options) => {\n if (action !== \"set\") {\n console.error(\"Usage: gpc releases notes set --track <track> --notes <text>\");\n process.exit(2);\n }\n\n const interactive = isInteractive(program);\n const tracks = [\"internal\", \"alpha\", \"beta\", \"production\"];\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: tracks,\n },\n interactive,\n );\n\n let notesText = options.notes;\n if (options.file) {\n const { readFile } = await import(\"node:fs/promises\");\n notesText = await readFile(options.file, \"utf-8\");\n }\n\n if (!notesText && interactive) {\n notesText = await promptInput(\"Release notes text:\");\n }\n\n if (!notesText) {\n console.error(\"Provide --notes <text> or --file <path>\");\n process.exit(2);\n }\n\n console.error(\n \"Error: gpc releases notes set is not yet implemented as a standalone command.\\n\" +\n \"To set release notes, use --notes, --notes-dir, or --notes-from-git with:\\n\" +\n \" gpc releases upload\\n\" +\n \" gpc publish\"\n );\n process.exit(1);\n });\n\n // Upload externally hosted APK\n releases\n .command(\"upload-external\")\n .description(\"Upload an externally hosted APK configuration\")\n .requiredOption(\"--url <url>\", \"External URL where the APK is hosted\")\n .requiredOption(\"--file <config>\", \"Path to JSON config file with APK metadata\")\n .action(async (options: { url: string; file: string }) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n\n try {\n const { readFile } = await import(\"node:fs/promises\");\n const raw = await readFile(options.file, \"utf-8\");\n const apkConfig = JSON.parse(raw) as Record<string, unknown>;\n\n // Override with CLI-provided URL\n apkConfig[\"externallyHostedUrl\"] = options.url;\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const result = await uploadExternallyHosted(\n client,\n packageName,\n apkConfig as import(\"@gpc-cli/api\").ExternallyHostedApk,\n );\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n // Diff\n releases\n .command(\"diff\")\n .description(\"Compare releases between two tracks\")\n .option(\"--from <track>\", \"Source track\", \"internal\")\n .option(\"--to <track>\", \"Target track\", \"production\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n try {\n const result = await diffReleases(client, packageName, options.from, options.to);\n if (result.diffs.length === 0) {\n console.log(`No differences between ${result.fromTrack} and ${result.toTrack}.`);\n } else {\n if (format === \"json\") {\n console.log(formatOutput(result, format));\n } else {\n console.log(`Differences: ${result.fromTrack} vs ${result.toTrack}\\n`);\n console.log(formatOutput(result.diffs, format));\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":["rollout"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/updater.ts","../src/commands/update.ts"],"sourcesContent":["/**\n * Self-update logic for `gpc update`.\n *\n * All functions here are pure / testable — no Commander.js dependency.\n * The command layer in commands/update.ts handles output and flags.\n */\n\nimport { createWriteStream } from \"node:fs\";\nimport { rename, chmod, unlink, stat } from \"node:fs/promises\";\nimport { realpathSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable, Transform } from \"node:stream\";\nimport { spawn } from \"node:child_process\";\nimport { isNewerVersion } from \"./update-check.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type InstallMethod = \"npm\" | \"homebrew\" | \"binary\" | \"unknown\";\n\nexport interface GithubAsset {\n name: string;\n browser_download_url: string;\n size: number;\n}\n\nexport interface GithubRelease {\n tag_name: string;\n html_url: string;\n assets: GithubAsset[];\n}\n\nexport interface UpdateCheckResult {\n current: string;\n latest: string;\n latestTag: string;\n updateAvailable: boolean;\n installMethod: InstallMethod;\n release: GithubRelease;\n}\n\nconst GITHUB_API_URL = \"https://api.github.com/repos/yasserstudio/gpc/releases/latest\";\nconst GITHUB_TIMEOUT_MS = 10_000;\nconst DOWNLOAD_TIMEOUT_MS = 120_000;\n\n// ---------------------------------------------------------------------------\n// Install method detection\n// ---------------------------------------------------------------------------\n\n/**\n * Detect how gpc was installed.\n *\n * Priority:\n * 1. __GPC_BINARY env var (injected by esbuild at compile time) → \"binary\"\n * 2. npm_config_prefix env var → \"npm\"\n * 3. realpathSync(process.argv[1]) contains \"cellar\" or \"homebrew\" → \"homebrew\"\n * 4. realpathSync(process.argv[1]) contains \"node_modules\" → \"npm\"\n * 5. fallback → \"unknown\"\n *\n * Using realpathSync(process.argv[1]) instead of shelling to `which gpc`:\n * - No child process spawn\n * - Works on Windows without `where.exe`\n * - Resolves symlinks — critical for Intel Mac Homebrew where the bin path\n * is a symlink but the real path contains \"Cellar\"\n */\nexport function detectInstallMethod(): InstallMethod {\n // 1. Compiled binary — most reliable, baked in at esbuild build time\n if (process.env[\"__GPC_BINARY\"] === \"1\") return \"binary\";\n\n // 2. npm global install\n if (process.env[\"npm_config_prefix\"]) return \"npm\";\n\n // 3. Resolve symlinks and inspect path\n try {\n const resolved = realpathSync(process.argv[1] ?? \"\").toLowerCase();\n if (resolved.includes(\"cellar\") || resolved.includes(\"homebrew\")) return \"homebrew\";\n if (resolved.includes(\"node_modules\")) return \"npm\";\n } catch {\n // realpathSync can throw if the path doesn't exist — fall through to unknown\n }\n\n return \"unknown\";\n}\n\n// ---------------------------------------------------------------------------\n// Platform asset mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the GitHub release asset name for the current platform/arch,\n * matching the names produced by scripts/build-binary.ts TARGETS map.\n */\nexport function getPlatformAsset(): string | null {\n const arch = process.arch === \"arm64\" ? \"arm64\" : \"x64\";\n switch (process.platform) {\n case \"darwin\":\n return `gpc-darwin-${arch}`;\n case \"linux\":\n return `gpc-linux-${arch}`;\n case \"win32\":\n return \"gpc-windows-x64.exe\";\n default:\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Current binary path\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the path of the currently running gpc binary.\n * For compiled binaries, process.execPath IS the binary.\n * For npm/dev installs, process.argv[1] is the script entrypoint.\n */\nexport function getCurrentBinaryPath(): string {\n if (process.env[\"__GPC_BINARY\"] === \"1\") return process.execPath;\n return process.argv[1] ?? process.execPath;\n}\n\n// ---------------------------------------------------------------------------\n// GitHub Releases API\n// ---------------------------------------------------------------------------\n\nfunction githubHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"User-Agent\": \"gpc-cli\",\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n };\n // Support GPC_GITHUB_TOKEN for authenticated requests (avoids 60 req/hr limit\n // on shared CI runner IPs)\n if (process.env[\"GPC_GITHUB_TOKEN\"]) {\n headers[\"Authorization\"] = `Bearer ${process.env[\"GPC_GITHUB_TOKEN\"]}`;\n }\n return headers;\n}\n\nexport async function fetchLatestRelease(): Promise<GithubRelease> {\n let response: Response;\n try {\n response = await fetch(GITHUB_API_URL, {\n headers: githubHeaders(),\n signal: AbortSignal.timeout(GITHUB_TIMEOUT_MS),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw Object.assign(new Error(`Network error checking for updates: ${msg}`), {\n code: \"NETWORK_ERROR\",\n exitCode: 5,\n });\n }\n\n if (response.status === 429) {\n throw Object.assign(\n new Error(\n \"GitHub API rate limit exceeded. Set GPC_GITHUB_TOKEN to increase the limit.\",\n ),\n { code: \"UPDATE_RATE_LIMITED\", exitCode: 4 },\n );\n }\n\n if (!response.ok) {\n throw Object.assign(new Error(`GitHub API returned HTTP ${response.status}`), {\n code: \"UPDATE_API_ERROR\",\n exitCode: 4,\n });\n }\n\n return (await response.json()) as GithubRelease;\n}\n\n/**\n * Fetch and parse checksums.txt from the release assets.\n * Returns a Map of filename → lowercase sha256 hex.\n * Returns an empty Map if the asset is missing or the fetch fails.\n */\nexport async function fetchChecksums(release: GithubRelease): Promise<Map<string, string>> {\n const asset = release.assets.find((a) => a.name === \"checksums.txt\");\n if (!asset) return new Map();\n\n try {\n const response = await fetch(asset.browser_download_url, {\n headers: githubHeaders(),\n signal: AbortSignal.timeout(GITHUB_TIMEOUT_MS),\n });\n if (!response.ok) return new Map();\n\n const map = new Map<string, string>();\n for (const line of (await response.text()).split(\"\\n\")) {\n const parts = line.trim().split(/\\s+/);\n const hash = parts[0];\n const name = parts[1];\n if (hash && name) map.set(name, hash.toLowerCase());\n }\n return map;\n } catch {\n return new Map();\n }\n}\n\n// ---------------------------------------------------------------------------\n// High-level update check\n// ---------------------------------------------------------------------------\n\nexport async function checkForUpdate(currentVersion: string): Promise<UpdateCheckResult> {\n const release = await fetchLatestRelease();\n const latest = release.tag_name.replace(/^v/, \"\");\n return {\n current: currentVersion,\n latest,\n latestTag: release.tag_name,\n updateAvailable: isNewerVersion(currentVersion, latest),\n installMethod: detectInstallMethod(),\n release,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Update execution paths\n// ---------------------------------------------------------------------------\n\nexport async function updateViaNpm(options: { silent?: boolean } = {}): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(\"npm\", [\"install\", \"-g\", \"@gpc-cli/cli@latest\"], {\n // In silent (JSON) mode, redirect npm's stdout to stderr so it doesn't\n // pollute the machine-readable JSON that gpc writes to stdout.\n stdio: options.silent ? [\"inherit\", process.stderr, process.stderr] : \"inherit\",\n shell: false,\n });\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(\n Object.assign(new Error(`npm exited with code ${code}`), {\n code: \"UPDATE_NPM_FAILED\",\n exitCode: 1,\n suggestion: \"Run manually: npm install -g @gpc-cli/cli@latest\",\n }),\n );\n }\n });\n proc.on(\"error\", (err) => {\n reject(\n Object.assign(new Error(`Failed to run npm: ${err.message}`), {\n code: \"UPDATE_NPM_SPAWN_FAILED\",\n exitCode: 1,\n suggestion: \"Ensure npm is in your PATH\",\n }),\n );\n });\n });\n}\n\nexport async function updateViaBrew(options: { silent?: boolean } = {}): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(\"brew\", [\"upgrade\", \"yasserstudio/tap/gpc\"], {\n // In silent (JSON) mode, redirect brew's stdout to stderr so it doesn't\n // pollute the machine-readable JSON that gpc writes to stdout.\n stdio: options.silent ? [\"inherit\", process.stderr, process.stderr] : \"inherit\",\n shell: false,\n });\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(\n Object.assign(new Error(`brew exited with code ${code}`), {\n code: \"UPDATE_BREW_FAILED\",\n exitCode: 1,\n suggestion: \"Run manually: brew upgrade yasserstudio/tap/gpc\",\n }),\n );\n }\n });\n proc.on(\"error\", (err) => {\n reject(\n Object.assign(new Error(`Failed to run brew: ${err.message}`), {\n code: \"UPDATE_BREW_SPAWN_FAILED\",\n exitCode: 1,\n suggestion: \"Ensure Homebrew is installed: https://brew.sh\",\n }),\n );\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Binary in-place replace\n// ---------------------------------------------------------------------------\n\nfunction isPermissionError(err: unknown): boolean {\n return (\n err instanceof Error &&\n \"code\" in err &&\n (err.code === \"EACCES\" || err.code === \"EPERM\")\n );\n}\n\nasync function sha256File(filePath: string): Promise<string> {\n const hash = createHash(\"sha256\");\n const { size } = await stat(filePath);\n if (size === 0) return hash.digest(\"hex\");\n\n // Read in 64 KB chunks\n const { createReadStream } = await import(\"node:fs\");\n const stream = createReadStream(filePath);\n await pipeline(stream, async function* (source) {\n for await (const chunk of source) {\n hash.update(chunk as Buffer);\n }\n });\n return hash.digest(\"hex\");\n}\n\n/**\n * Download a new binary and atomically replace the current one.\n *\n * macOS/Linux: rename(tmp, current) — safe because open files can be replaced\n * Windows: rename(current, .old) then rename(tmp, current) — avoids EBUSY\n * because Windows locks running executables\n */\nexport async function updateBinaryInPlace(\n assetUrl: string,\n expectedSha256: string,\n currentBinaryPath: string,\n options: { onProgress?: (downloaded: number, total: number) => void } = {},\n): Promise<void> {\n const dir = dirname(currentBinaryPath);\n const tmpPath = join(dir, `.gpc-update-${process.pid}.tmp`);\n const oldPath = join(dir, `.gpc-old-${process.pid}`);\n\n try {\n // 1. Download\n let response: Response;\n try {\n response = await fetch(assetUrl, {\n signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw Object.assign(new Error(`Download failed: ${msg}`), {\n code: \"UPDATE_DOWNLOAD_FAILED\",\n exitCode: 5,\n });\n }\n\n if (!response.ok) {\n throw Object.assign(new Error(`Download failed: HTTP ${response.status}`), {\n code: \"UPDATE_DOWNLOAD_FAILED\",\n exitCode: 4,\n });\n }\n if (!response.body) {\n throw Object.assign(new Error(\"Empty response body\"), {\n code: \"UPDATE_DOWNLOAD_FAILED\",\n exitCode: 4,\n });\n }\n\n const contentLength = response.headers.get(\"content-length\");\n const total = contentLength ? parseInt(contentLength, 10) : 0;\n let downloaded = 0;\n\n const dest = createWriteStream(tmpPath);\n const { onProgress } = options;\n\n if (onProgress) {\n const tracker = new Transform({\n transform(chunk: Buffer, _enc, cb) {\n downloaded += chunk.length;\n onProgress(downloaded, total);\n cb(null, chunk);\n },\n });\n await pipeline(\n Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]),\n tracker,\n dest,\n );\n } else {\n await pipeline(Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]), dest);\n }\n\n // 2. Verify checksum (skip if no checksum available)\n if (expectedSha256) {\n const actual = await sha256File(tmpPath);\n if (actual !== expectedSha256.toLowerCase()) {\n throw Object.assign(\n new Error(`Checksum mismatch — expected ${expectedSha256}, got ${actual}`),\n {\n code: \"UPDATE_CHECKSUM_MISMATCH\",\n exitCode: 1,\n suggestion: \"The download may be corrupt. Try again.\",\n },\n );\n }\n }\n\n // 3. Set executable bit (no-op on Windows)\n if (process.platform !== \"win32\") {\n await chmod(tmpPath, 0o755);\n }\n\n // 4. Atomic replace\n if (process.platform === \"win32\") {\n // Windows locks running executables, so we rename the current binary\n // out of the way first, then move the new one into place\n await rename(currentBinaryPath, oldPath);\n try {\n await rename(tmpPath, currentBinaryPath);\n } catch (renameErr) {\n // Roll back — restore original binary\n await rename(oldPath, currentBinaryPath).catch(() => {});\n throw renameErr;\n }\n // Delete the old binary in the background (best-effort)\n unlink(oldPath).catch(() => {});\n } else {\n await rename(tmpPath, currentBinaryPath);\n }\n } catch (err) {\n // Clean up temp file on any error\n await unlink(tmpPath).catch(() => {});\n\n if (isPermissionError(err)) {\n throw Object.assign(\n new Error(`Permission denied replacing ${currentBinaryPath}`),\n {\n code: \"UPDATE_PERMISSION_DENIED\",\n exitCode: 1,\n suggestion: `Run with elevated permissions: sudo gpc update`,\n },\n );\n }\n throw err;\n }\n}\n","import type { Command } from \"commander\";\nimport {\n checkForUpdate,\n fetchChecksums,\n updateViaNpm,\n updateViaBrew,\n updateBinaryInPlace,\n getPlatformAsset,\n getCurrentBinaryPath,\n} from \"../updater.js\";\nimport { createSpinner } from \"@gpc-cli/core\";\n\nexport function registerUpdateCommand(program: Command): void {\n program\n .command(\"update\")\n .description(\"Update gpc to the latest version\")\n .option(\"--check\", \"Check for updates without installing (exits 0 always)\")\n .option(\"--force\", \"Update even if already on the latest version\")\n .action(async (opts: { check?: boolean; force?: boolean }, cmd) => {\n const parentOpts = (cmd.parent?.opts() ?? {}) as Record<string, unknown>;\n const jsonMode = !!(parentOpts[\"json\"] || parentOpts[\"output\"] === \"json\");\n const currentVersion = process.env[\"__GPC_VERSION\"] ?? \"0.0.0\";\n\n // Dev build guard\n if (currentVersion === \"0.0.0\") {\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: false,\n reason: \"Cannot update a development build\",\n current: currentVersion,\n }),\n );\n } else {\n console.log(\"Cannot update a development build (version: 0.0.0).\");\n }\n return;\n }\n\n const spinner = createSpinner(\"Checking for updates...\");\n spinner.start();\n\n let result;\n try {\n result = await checkForUpdate(currentVersion);\n } catch (err) {\n spinner.fail(\"Failed to check for updates\");\n throw err;\n }\n\n // --check mode: always exit 0, communicate via output\n if (opts.check) {\n spinner.stop();\n if (jsonMode) {\n console.log(\n JSON.stringify({\n current: result.current,\n latest: result.latest,\n updateAvailable: result.updateAvailable,\n installMethod: result.installMethod,\n releaseUrl: result.release.html_url,\n }),\n );\n } else if (result.updateAvailable) {\n console.log(`Update available: ${result.current} → ${result.latest}`);\n console.log(`Install method: ${result.installMethod}`);\n console.log(`Release: ${result.release.html_url}`);\n console.log(`\\nRun: gpc update`);\n } else {\n console.log(`Already on latest version: v${result.current}`);\n }\n return;\n }\n\n // Already up to date\n if (!result.updateAvailable && !opts.force) {\n spinner.stop(`Already on latest version: v${result.current}`);\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n current: result.current,\n latest: result.latest,\n updated: false,\n }),\n );\n }\n return;\n }\n\n spinner.update(\n `Updating v${result.current} → v${result.latest} (${result.installMethod})...`,\n );\n\n switch (result.installMethod) {\n case \"npm\":\n spinner.stop();\n await updateViaNpm({ silent: jsonMode });\n break;\n\n case \"homebrew\":\n spinner.stop();\n await updateViaBrew({ silent: jsonMode });\n break;\n\n case \"binary\": {\n const assetName = getPlatformAsset();\n if (!assetName) {\n spinner.fail();\n console.error(\n `Error: Unsupported platform: ${process.platform}/${process.arch}`,\n );\n console.error(\n `Download manually: ${result.release.html_url}`,\n );\n process.exit(1);\n }\n\n const assetObj = result.release.assets.find((a) => a.name === assetName);\n if (!assetObj) {\n spinner.fail();\n console.error(\n `Error: No binary found for ${assetName} in release ${result.latestTag}`,\n );\n console.error(`Check: ${result.release.html_url}`);\n process.exit(1);\n }\n\n const sizeMB = (assetObj.size / (1024 * 1024)).toFixed(1);\n spinner.stop();\n\n const checksums = await fetchChecksums(result.release);\n const expectedHash = checksums.get(assetName) ?? \"\";\n const binaryPath = getCurrentBinaryPath();\n\n if (jsonMode) {\n await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath);\n } else {\n // Show live download progress on a single overwriting line\n const label = `Downloading ${assetName} (${sizeMB} MB)`;\n process.stdout.write(`${label}...\\n`);\n let lastPct = -1;\n await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath, {\n onProgress(downloaded, total) {\n if (total <= 0) return;\n const pct = Math.min(100, Math.round((downloaded / total) * 100));\n if (pct === lastPct) return; // avoid redundant writes\n lastPct = pct;\n const dlMB = (downloaded / (1024 * 1024)).toFixed(1);\n process.stdout.write(\n `\\r${label} ${dlMB} / ${sizeMB} MB (${String(pct).padStart(3)}%) `,\n );\n },\n });\n process.stdout.write(\"\\n\");\n }\n break;\n }\n\n case \"unknown\":\n spinner.fail();\n console.error(\"Error: Could not detect install method. Update manually:\");\n console.error(` npm: npm install -g @gpc-cli/cli@latest`);\n console.error(` Homebrew: brew upgrade yasserstudio/tap/gpc`);\n console.error(` Binary: https://github.com/yasserstudio/gpc/releases/latest`);\n process.exit(1);\n }\n\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n previous: result.current,\n current: result.latest,\n method: result.installMethod,\n }),\n );\n } else {\n console.log(`\\n✔ Updated to v${result.latest}`);\n }\n });\n}\n"],"mappings":"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","names":[]}