@gpc-cli/cli 0.9.34 → 0.9.35

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 (91) hide show
  1. package/README.md +20 -15
  2. package/dist/{apps-CVBURB5V.js → apps-J2446UDA.js} +2 -2
  3. package/dist/{apps-CVBURB5V.js.map → apps-J2446UDA.js.map} +1 -1
  4. package/dist/{audit-A4BP27DN.js → audit-4UPTLW37.js} +2 -3
  5. package/dist/{audit-A4BP27DN.js.map → audit-4UPTLW37.js.map} +1 -1
  6. package/dist/{auth-QSDK7NUO.js → auth-KPVEGAWV.js} +101 -9
  7. package/dist/auth-KPVEGAWV.js.map +1 -0
  8. package/dist/bin.js +2 -2
  9. package/dist/bin.js.map +1 -1
  10. package/dist/{bundle-7IF5FIB4.js → bundle-7XYHNVNF.js} +27 -2
  11. package/dist/bundle-7XYHNVNF.js.map +1 -0
  12. package/dist/{cache-SHWAVON6.js → cache-K23N6GJR.js} +1 -1
  13. package/dist/cache-K23N6GJR.js.map +1 -0
  14. package/dist/{chunk-UH3TMIAL.js → chunk-43SH6XEJ.js} +5 -5
  15. package/dist/{chunk-UH3TMIAL.js.map → chunk-43SH6XEJ.js.map} +1 -1
  16. package/dist/{chunk-5CSWPQO6.js → chunk-DDTPDKTB.js} +101 -31
  17. package/dist/chunk-DDTPDKTB.js.map +1 -0
  18. package/dist/{config-7EOY5HGL.js → config-REB7NINL.js} +4 -4
  19. package/dist/config-REB7NINL.js.map +1 -0
  20. package/dist/{data-safety-GDPKV5PN.js → data-safety-GN5VBKAK.js} +1 -1
  21. package/dist/data-safety-GN5VBKAK.js.map +1 -0
  22. package/dist/{doctor-UKKOK55S.js → doctor-QDIFTXNB.js} +44 -2
  23. package/dist/doctor-QDIFTXNB.js.map +1 -0
  24. package/dist/enterprise-IH5HXYRB.js +65 -0
  25. package/dist/enterprise-IH5HXYRB.js.map +1 -0
  26. package/dist/{feedback-W5MZMRF2.js → feedback-NVGHRU7A.js} +3 -3
  27. package/dist/feedback-NVGHRU7A.js.map +1 -0
  28. package/dist/games-X57AGM3E.js +80 -0
  29. package/dist/games-X57AGM3E.js.map +1 -0
  30. package/dist/grants-CXTTYKR3.js +123 -0
  31. package/dist/grants-CXTTYKR3.js.map +1 -0
  32. package/dist/{iap-6XHJV5HX.js → iap-MBDD7VWP.js} +1 -1
  33. package/dist/iap-MBDD7VWP.js.map +1 -0
  34. package/dist/index.js +1 -1
  35. package/dist/{listings-TOYS6XBU.js → listings-7TWCGGMS.js} +90 -9
  36. package/dist/listings-7TWCGGMS.js.map +1 -0
  37. package/dist/{publish-I6WJGR4S.js → publish-XM43UA5R.js} +2 -1
  38. package/dist/publish-XM43UA5R.js.map +1 -0
  39. package/dist/{purchases-YRO6B7M6.js → purchases-WIDU3FDQ.js} +28 -1
  40. package/dist/purchases-WIDU3FDQ.js.map +1 -0
  41. package/dist/quickstart-N7FXM5RQ.js +87 -0
  42. package/dist/quickstart-N7FXM5RQ.js.map +1 -0
  43. package/dist/quota-SNUI75NM.js +53 -0
  44. package/dist/quota-SNUI75NM.js.map +1 -0
  45. package/dist/{releases-ANC54YWF.js → releases-YRYM7JXC.js} +5 -1
  46. package/dist/releases-YRYM7JXC.js.map +1 -0
  47. package/dist/{reports-N5X66IUN.js → reports-YOT4DQGL.js} +1 -1
  48. package/dist/reports-YOT4DQGL.js.map +1 -0
  49. package/dist/{reviews-UHK4FGK6.js → reviews-NN7YQITF.js} +55 -3
  50. package/dist/reviews-NN7YQITF.js.map +1 -0
  51. package/dist/{status-DQYZ7A6Y.js → status-L5S2FGZ4.js} +13 -3
  52. package/dist/status-L5S2FGZ4.js.map +1 -0
  53. package/dist/{subscriptions-Z5ZPVUFM.js → subscriptions-OXAE7SNS.js} +32 -1
  54. package/dist/subscriptions-OXAE7SNS.js.map +1 -0
  55. package/dist/{testers-UWSUGGVT.js → testers-SDLVWQ2Z.js} +1 -1
  56. package/dist/testers-SDLVWQ2Z.js.map +1 -0
  57. package/dist/{tracks-XFUN7JJX.js → tracks-NERFFEDT.js} +2 -2
  58. package/dist/tracks-NERFFEDT.js.map +1 -0
  59. package/dist/train-PX5Z26PQ.js +150 -0
  60. package/dist/train-PX5Z26PQ.js.map +1 -0
  61. package/dist/{update-NIVJLUNH.js → update-6XSZRXSU.js} +3 -3
  62. package/dist/{update-NIVJLUNH.js.map → update-6XSZRXSU.js.map} +1 -1
  63. package/dist/{validate-MHLPENCM.js → validate-NC4MWKOB.js} +9 -4
  64. package/dist/validate-NC4MWKOB.js.map +1 -0
  65. package/dist/{version-7AI5IHVK.js → version-2X32UAAE.js} +3 -3
  66. package/dist/version-2X32UAAE.js.map +1 -0
  67. package/dist/{vitals-QGWOFH7E.js → vitals-LFL75LA6.js} +113 -2
  68. package/dist/vitals-LFL75LA6.js.map +1 -0
  69. package/package.json +8 -4
  70. package/dist/auth-QSDK7NUO.js.map +0 -1
  71. package/dist/bundle-7IF5FIB4.js.map +0 -1
  72. package/dist/cache-SHWAVON6.js.map +0 -1
  73. package/dist/chunk-5CSWPQO6.js.map +0 -1
  74. package/dist/config-7EOY5HGL.js.map +0 -1
  75. package/dist/data-safety-GDPKV5PN.js.map +0 -1
  76. package/dist/doctor-UKKOK55S.js.map +0 -1
  77. package/dist/feedback-W5MZMRF2.js.map +0 -1
  78. package/dist/iap-6XHJV5HX.js.map +0 -1
  79. package/dist/listings-TOYS6XBU.js.map +0 -1
  80. package/dist/publish-I6WJGR4S.js.map +0 -1
  81. package/dist/purchases-YRO6B7M6.js.map +0 -1
  82. package/dist/releases-ANC54YWF.js.map +0 -1
  83. package/dist/reports-N5X66IUN.js.map +0 -1
  84. package/dist/reviews-UHK4FGK6.js.map +0 -1
  85. package/dist/status-DQYZ7A6Y.js.map +0 -1
  86. package/dist/subscriptions-Z5ZPVUFM.js.map +0 -1
  87. package/dist/testers-UWSUGGVT.js.map +0 -1
  88. package/dist/tracks-XFUN7JJX.js.map +0 -1
  89. package/dist/validate-MHLPENCM.js.map +0 -1
  90. package/dist/version-7AI5IHVK.js.map +0 -1
  91. package/dist/vitals-QGWOFH7E.js.map +0 -1
package/README.md CHANGED
@@ -27,12 +27,17 @@ brew install yasserstudio/tap/gpc
27
27
  curl -fsSL https://raw.githubusercontent.com/yasserstudio/gpc/main/scripts/install.sh | sh
28
28
  ```
29
29
 
30
+ Free. Open-source. No account required beyond your existing Google Play service account.
31
+
30
32
  ## Quick Start
31
33
 
32
34
  ```bash
33
35
  # Authenticate
34
36
  gpc auth login --service-account path/to/key.json
35
37
 
38
+ # Verify your setup
39
+ gpc doctor
40
+
36
41
  # App health at a glance — releases, vitals, and reviews in one command
37
42
  gpc status
38
43
 
@@ -72,23 +77,23 @@ REVIEWS (last 30 days)
72
77
 
73
78
  187 API endpoints across these command groups:
74
79
 
75
- | Group | Examples |
76
- | ----------------- | -------------------------------------------------------------- |
77
- | **Releases** | `upload`, `promote`, `rollout increase/halt/resume`, `publish` |
78
- | **Listings** | `pull`, `push`, `images upload/delete`, Fastlane format |
79
- | **Reviews** | `list`, `reply`, `export --format csv` |
80
- | **Vitals** | `crashes`, `anr`, `startup`, `rendering`, `battery`, `memory` |
81
- | **Bundle** | `analyze` (size breakdown), `compare` (size diff) |
82
- | **Subscriptions** | `list`, `create`, `update`, `base-plans`, `offers` |
83
- | **IAP** | `list`, `create`, `sync --dir products/`, `batch-get/update` |
84
- | **Purchases** | `get`, `acknowledge`, `cancel`, `refund`, `voided list` |
85
- | **Reports** | `download financial`, `download stats` |
86
- | **Testers** | `add`, `remove`, `import --file testers.csv` |
87
- | **Users** | `invite`, `update`, `remove`, per-app grants |
80
+ | Group | What you can do |
81
+ | ----------------- | ------------------------------------------------------------------------------------- |
82
+ | **Releases** | Upload, promote, rollout increase/halt/resume, end-to-end `publish` |
83
+ | **Listings** | Pull and push store listings, upload screenshots — works with Fastlane metadata format |
84
+ | **Reviews** | Filter by stars, reply to users, export to CSV |
85
+ | **Vitals** | Crash rates, ANR, startup, rendering with CI threshold gates |
86
+ | **Bundle** | Per-module size breakdown, build-to-build diff, size CI gates |
87
+ | **Subscriptions** | Create and manage base plans, offers, and pricing |
88
+ | **IAP** | Sync products from local files, batch get and update |
89
+ | **Purchases** | Verify, acknowledge, cancel, refund, list voided |
90
+ | **Reports** | Download financial and stats reports |
91
+ | **Testers** | Add, remove, import from CSV |
92
+ | **Users** | Invite, update, remove, manage per-app grants |
88
93
 
89
94
  ## CI/CD Ready
90
95
 
91
- JSON output when piped. Formatted tables in your terminal. Semantic exit codes (0-6) your CI can react to.
96
+ JSON output when piped. Formatted tables in your terminal. Semantic exit codes (06) your CI can react to. Every write operation supports `--dry-run`.
92
97
 
93
98
  ```yaml
94
99
  - name: Upload
@@ -100,7 +105,7 @@ JSON output when piped. Formatted tables in your terminal. Semantic exit codes (
100
105
  gpc releases upload app.aab --track internal
101
106
  ```
102
107
 
103
- Every write operation supports `--dry-run`.
108
+ Already on Fastlane? See the [migration guide](https://yasserstudio.github.io/gpc/migration/from-fastlane) — most commands map one-to-one.
104
109
 
105
110
  ## Part of the GPC Monorepo
106
111
 
@@ -82,7 +82,7 @@ function registerAppsCommands(program) {
82
82
  process.exit(4);
83
83
  }
84
84
  });
85
- apps.command("list").description("List configured applications").option("--limit <n>", "Maximum results to return").option("--next-page <token>", "Pagination token for next page").action(async (options) => {
85
+ apps.command("list").description("List configured applications").option("--limit <n>", "Maximum results to return").option("--next-page <token>", "Pagination token for next page").action(async (_options) => {
86
86
  const config = await loadConfig();
87
87
  const format = getOutputFormat(program, config);
88
88
  if (config.app) {
@@ -102,4 +102,4 @@ function registerAppsCommands(program) {
102
102
  export {
103
103
  registerAppsCommands
104
104
  };
105
- //# sourceMappingURL=apps-CVBURB5V.js.map
105
+ //# sourceMappingURL=apps-J2446UDA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/apps.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport { getAppInfo, updateAppDetails } from \"@gpc-cli/core\";\nimport { formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\n\nexport function registerAppsCommands(program: Command): void {\n const apps = program.command(\"apps\").description(\"Manage applications\");\n\n apps\n .command(\"info [package]\")\n .description(\"Show app details\")\n .action(async (packageArg?: string) => {\n const config = await loadConfig();\n const packageName = packageArg || config.app;\n\n if (!packageName) {\n console.error(\"Error: No package name provided.\");\n console.error(\"Usage: gpc apps info <package>\");\n console.error(\"Or set a default: gpc config set app com.example.app\");\n process.exit(2);\n }\n\n try {\n const auth = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n });\n const client = createApiClient({ auth });\n const info = await getAppInfo(client, packageName);\n const format = getOutputFormat(program, config);\n console.log(formatOutput(info, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n apps\n .command(\"update\")\n .description(\"Update app details\")\n .option(\"--email <email>\", \"Contact email\")\n .option(\"--phone <phone>\", \"Contact phone\")\n .option(\"--website <url>\", \"Contact website\")\n .option(\"--default-lang <lang>\", \"Default language\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = options[\"app\"] || program.opts()[\"app\"] || config.app;\n\n if (!packageName) {\n console.error(\"Error: No package name provided.\");\n console.error(\"Usage: gpc apps update --email user@example.com\");\n process.exit(2);\n }\n\n const data: Record<string, string> = {};\n if (options[\"email\"]) data[\"contactEmail\"] = options[\"email\"];\n if (options[\"phone\"]) data[\"contactPhone\"] = options[\"phone\"];\n if (options[\"website\"]) data[\"contactWebsite\"] = options[\"website\"];\n if (options[\"defaultLang\"]) data[\"defaultLanguage\"] = options[\"defaultLang\"];\n\n if (Object.keys(data).length === 0) {\n console.error(\n \"Error: Provide at least one field to update (--email, --phone, --website, --default-lang).\",\n );\n process.exit(2);\n }\n\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"apps update\",\n action: \"update app details for\",\n target: packageName,\n details: data,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n try {\n const auth = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n });\n const client = createApiClient({ auth });\n const result = await updateAppDetails(client, packageName, data);\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 apps\n .command(\"list\")\n .description(\"List configured applications\")\n .option(\"--limit <n>\", \"Maximum results to return\")\n .option(\"--next-page <token>\", \"Pagination token for next page\")\n .action(async (options) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n\n if (config.app) {\n const apps = [{ packageName: config.app, source: \"config\" }];\n console.log(formatOutput(apps, format));\n } else {\n console.log(\"No apps configured.\");\n console.log(\"\");\n console.log(\"Set a default app:\");\n console.log(\" gpc config set app com.example.myapp\");\n console.log(\"\");\n console.log(\"Or use the --app flag:\");\n console.log(\" gpc apps info --app com.example.myapp\");\n }\n });\n}\n"],"mappings":"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","names":["apps"]}
1
+ {"version":3,"sources":["../src/commands/apps.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport { getAppInfo, updateAppDetails } from \"@gpc-cli/core\";\nimport { formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\n\nexport function registerAppsCommands(program: Command): void {\n const apps = program.command(\"apps\").description(\"Manage applications\");\n\n apps\n .command(\"info [package]\")\n .description(\"Show app details\")\n .action(async (packageArg?: string) => {\n const config = await loadConfig();\n const packageName = packageArg || config.app;\n\n if (!packageName) {\n console.error(\"Error: No package name provided.\");\n console.error(\"Usage: gpc apps info <package>\");\n console.error(\"Or set a default: gpc config set app com.example.app\");\n process.exit(2);\n }\n\n try {\n const auth = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n });\n const client = createApiClient({ auth });\n const info = await getAppInfo(client, packageName);\n const format = getOutputFormat(program, config);\n console.log(formatOutput(info, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n apps\n .command(\"update\")\n .description(\"Update app details\")\n .option(\"--email <email>\", \"Contact email\")\n .option(\"--phone <phone>\", \"Contact phone\")\n .option(\"--website <url>\", \"Contact website\")\n .option(\"--default-lang <lang>\", \"Default language\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = options[\"app\"] || program.opts()[\"app\"] || config.app;\n\n if (!packageName) {\n console.error(\"Error: No package name provided.\");\n console.error(\"Usage: gpc apps update --email user@example.com\");\n process.exit(2);\n }\n\n const data: Record<string, string> = {};\n if (options[\"email\"]) data[\"contactEmail\"] = options[\"email\"];\n if (options[\"phone\"]) data[\"contactPhone\"] = options[\"phone\"];\n if (options[\"website\"]) data[\"contactWebsite\"] = options[\"website\"];\n if (options[\"defaultLang\"]) data[\"defaultLanguage\"] = options[\"defaultLang\"];\n\n if (Object.keys(data).length === 0) {\n console.error(\n \"Error: Provide at least one field to update (--email, --phone, --website, --default-lang).\",\n );\n process.exit(2);\n }\n\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"apps update\",\n action: \"update app details for\",\n target: packageName,\n details: data,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n try {\n const auth = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n });\n const client = createApiClient({ auth });\n const result = await updateAppDetails(client, packageName, data);\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 apps\n .command(\"list\")\n .description(\"List configured applications\")\n .option(\"--limit <n>\", \"Maximum results to return\")\n .option(\"--next-page <token>\", \"Pagination token for next page\")\n .action(async (_options) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n\n if (config.app) {\n const apps = [{ packageName: config.app, source: \"config\" }];\n console.log(formatOutput(apps, format));\n } else {\n console.log(\"No apps configured.\");\n console.log(\"\");\n console.log(\"Set a default app:\");\n console.log(\" gpc config set app com.example.myapp\");\n console.log(\"\");\n console.log(\"Or use the --app flag:\");\n console.log(\" gpc apps info --app com.example.myapp\");\n }\n });\n}\n"],"mappings":"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","names":["apps"]}
@@ -96,8 +96,7 @@ function registerAuditCommands(program) {
96
96
  });
97
97
  audit.command("clear").description("Clear audit log entries").option("--before <date>", "Clear entries before date (ISO 8601)").option("--dry-run", "Preview what would be cleared").action(async (options, cmd) => {
98
98
  const dryRun = options.dryRun || isDryRun(cmd);
99
- const config = await loadConfig();
100
- const format = getOutputFormat(program, config);
99
+ await loadConfig();
101
100
  initAudit(getConfigDir());
102
101
  if (!dryRun && !options.before) {
103
102
  await requireConfirm("Clear all audit log entries?", program);
@@ -121,4 +120,4 @@ function registerAuditCommands(program) {
121
120
  export {
122
121
  registerAuditCommands
123
122
  };
124
- //# sourceMappingURL=audit-A4BP27DN.js.map
123
+ //# sourceMappingURL=audit-4UPTLW37.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/audit.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { getConfigDir } from \"@gpc-cli/config\";\nimport {\n initAudit,\n listAuditEvents,\n searchAuditEvents,\n clearAuditLog,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\n\nfunction formatAuditTimestamp(iso: string): string {\n const date = new Date(iso);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 60) return diffMin < 1 ? \"just now\" : `${diffMin} min ago`;\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24) return `${String(date.getHours()).padStart(2, \"0\")}:${String(date.getMinutes()).padStart(2, \"0\")}:${String(date.getSeconds()).padStart(2, \"0\")}`;\n const diffDays = Math.floor(diffHr / 24);\n if (diffDays < 7) {\n const days = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n return `${days[date.getDay()]} ${String(date.getHours()).padStart(2, \"0\")}:${String(date.getMinutes()).padStart(2, \"0\")}`;\n }\n const months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;\n}\n\nexport function registerAuditCommands(program: Command): void {\n const audit = program.command(\"audit\").description(\"Query and manage audit logs\");\n\n audit\n .command(\"list\")\n .description(\"List recent audit events\")\n .option(\"--limit <n>\", \"Maximum events to show\", parseInt, 50)\n .option(\"--since <date>\", \"Show events since date (ISO 8601)\")\n .option(\"--command <name>\", \"Filter by command name\")\n .action(async (options) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n initAudit(getConfigDir());\n\n try {\n const events = await listAuditEvents({\n limit: options.limit,\n since: options.since,\n command: options.command,\n });\n if (events.length === 0 && format !== \"json\") {\n console.log(\"No audit events found.\");\n return;\n }\n if (format !== \"json\") {\n const rows = events.map((e) => ({\n timestamp: formatAuditTimestamp(e.timestamp),\n command: e.command,\n app: e.app || \"-\",\n success: e.success !== undefined ? String(e.success) : \"-\",\n durationMs: e.durationMs ?? \"-\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(events, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n\n audit\n .command(\"search <query>\")\n .description(\"Search audit events by keyword\")\n .action(async (query: string) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n initAudit(getConfigDir());\n\n try {\n const events = await searchAuditEvents(query);\n if (events.length === 0 && format !== \"json\") {\n console.log(`No audit events matching \"${query}\".`);\n return;\n }\n if (format !== \"json\") {\n const rows = events.map((e) => ({\n timestamp: formatAuditTimestamp(e.timestamp),\n command: e.command,\n app: e.app || \"-\",\n success: e.success !== undefined ? String(e.success) : \"-\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(events, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n\n audit\n .command(\"clear\")\n .description(\"Clear audit log entries\")\n .option(\"--before <date>\", \"Clear entries before date (ISO 8601)\")\n .option(\"--dry-run\", \"Preview what would be cleared\")\n .action(async (options, cmd: Command) => {\n const dryRun = options.dryRun || isDryRun(cmd);\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n initAudit(getConfigDir());\n\n if (!dryRun && !options.before) {\n await requireConfirm(\"Clear all audit log entries?\", program);\n }\n\n try {\n const result = await clearAuditLog({\n before: options.before,\n dryRun,\n });\n if (dryRun) {\n console.log(`[dry-run] Would delete ${result.deleted} entries, ${result.remaining} would remain.`);\n } else {\n console.log(`Deleted ${result.deleted} entries. ${result.remaining} remaining.`);\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/audit.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { getConfigDir } from \"@gpc-cli/config\";\nimport {\n initAudit,\n listAuditEvents,\n searchAuditEvents,\n clearAuditLog,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\n\nfunction formatAuditTimestamp(iso: string): string {\n const date = new Date(iso);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 60) return diffMin < 1 ? \"just now\" : `${diffMin} min ago`;\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24) return `${String(date.getHours()).padStart(2, \"0\")}:${String(date.getMinutes()).padStart(2, \"0\")}:${String(date.getSeconds()).padStart(2, \"0\")}`;\n const diffDays = Math.floor(diffHr / 24);\n if (diffDays < 7) {\n const days = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n return `${days[date.getDay()]} ${String(date.getHours()).padStart(2, \"0\")}:${String(date.getMinutes()).padStart(2, \"0\")}`;\n }\n const months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n return `${months[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;\n}\n\nexport function registerAuditCommands(program: Command): void {\n const audit = program.command(\"audit\").description(\"Query and manage audit logs\");\n\n audit\n .command(\"list\")\n .description(\"List recent audit events\")\n .option(\"--limit <n>\", \"Maximum events to show\", parseInt, 50)\n .option(\"--since <date>\", \"Show events since date (ISO 8601)\")\n .option(\"--command <name>\", \"Filter by command name\")\n .action(async (options) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n initAudit(getConfigDir());\n\n try {\n const events = await listAuditEvents({\n limit: options.limit,\n since: options.since,\n command: options.command,\n });\n if (events.length === 0 && format !== \"json\") {\n console.log(\"No audit events found.\");\n return;\n }\n if (format !== \"json\") {\n const rows = events.map((e) => ({\n timestamp: formatAuditTimestamp(e.timestamp),\n command: e.command,\n app: e.app || \"-\",\n success: e.success !== undefined ? String(e.success) : \"-\",\n durationMs: e.durationMs ?? \"-\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(events, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n\n audit\n .command(\"search <query>\")\n .description(\"Search audit events by keyword\")\n .action(async (query: string) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n initAudit(getConfigDir());\n\n try {\n const events = await searchAuditEvents(query);\n if (events.length === 0 && format !== \"json\") {\n console.log(`No audit events matching \"${query}\".`);\n return;\n }\n if (format !== \"json\") {\n const rows = events.map((e) => ({\n timestamp: formatAuditTimestamp(e.timestamp),\n command: e.command,\n app: e.app || \"-\",\n success: e.success !== undefined ? String(e.success) : \"-\",\n }));\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(events, format));\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n\n audit\n .command(\"clear\")\n .description(\"Clear audit log entries\")\n .option(\"--before <date>\", \"Clear entries before date (ISO 8601)\")\n .option(\"--dry-run\", \"Preview what would be cleared\")\n .action(async (options, cmd: Command) => {\n const dryRun = options.dryRun || isDryRun(cmd);\n await loadConfig();\n initAudit(getConfigDir());\n\n if (!dryRun && !options.before) {\n await requireConfirm(\"Clear all audit log entries?\", program);\n }\n\n try {\n const result = await clearAuditLog({\n before: options.before,\n dryRun,\n });\n if (dryRun) {\n console.log(`[dry-run] Would delete ${result.deleted} entries, ${result.remaining} would remain.`);\n } else {\n console.log(`Deleted ${result.deleted} entries. ${result.remaining} remaining.`);\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -4,9 +4,70 @@ import {
4
4
  } from "./chunk-ELXAK7GI.js";
5
5
 
6
6
  // src/commands/auth.ts
7
+ import { createInterface } from "readline";
8
+ import { access } from "fs/promises";
7
9
  import { resolveAuth, loadServiceAccountKey, clearTokenCache, AuthError } from "@gpc-cli/auth";
8
10
  import { loadConfig, getCacheDir } from "@gpc-cli/config";
9
11
  import { formatOutput } from "@gpc-cli/core";
12
+ async function askQuestion(rl, question) {
13
+ return new Promise((resolve) => {
14
+ rl.question(question, (answer) => resolve(answer.trim()));
15
+ });
16
+ }
17
+ async function runLoginWizard() {
18
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
19
+ try {
20
+ console.log("\nGPC Authentication Setup");
21
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
22
+ console.log("\nAuthentication methods:");
23
+ console.log(" 1. Service account key file (recommended)");
24
+ console.log(" 2. Application Default Credentials (ADC)");
25
+ const method = await askQuestion(rl, "\nSelect method [1]: ");
26
+ const useAdc = method === "2";
27
+ if (useAdc) {
28
+ const { resolveAuth: ra } = await import("@gpc-cli/auth");
29
+ const client = await ra();
30
+ console.log(`
31
+ Authenticated via Application Default Credentials`);
32
+ console.log(`Account: ${client.getClientEmail()}`);
33
+ return;
34
+ }
35
+ let saPath = "";
36
+ while (!saPath) {
37
+ const input = await askQuestion(rl, "\nPath to service account JSON key: ");
38
+ if (!input) {
39
+ console.log(" Path is required.");
40
+ continue;
41
+ }
42
+ try {
43
+ await access(input);
44
+ saPath = input;
45
+ } catch {
46
+ console.log(` File not found: ${input}`);
47
+ }
48
+ }
49
+ const profileName = await askQuestion(rl, "\nProfile name (optional, press Enter to skip): ");
50
+ const packageName = await askQuestion(rl, "Default package name (optional, e.g. com.example.app): ");
51
+ const { loadServiceAccountKey: loadKey } = await import("@gpc-cli/auth");
52
+ const key = await loadKey(saPath);
53
+ if (profileName) {
54
+ const { setProfileConfig } = await import("@gpc-cli/config");
55
+ await setProfileConfig(profileName, { auth: { serviceAccount: saPath }, ...packageName && { app: packageName } });
56
+ console.log(`
57
+ Profile "${profileName}" configured with ${key.client_email}`);
58
+ } else {
59
+ const { setConfigValue } = await import("@gpc-cli/config");
60
+ await setConfigValue("auth.serviceAccount", saPath);
61
+ if (packageName) await setConfigValue("app", packageName);
62
+ console.log(`
63
+ Authenticated as ${key.client_email}`);
64
+ }
65
+ console.log(`Project: ${key.project_id}`);
66
+ console.log("\nRun 'gpc doctor' to verify your setup.");
67
+ } finally {
68
+ rl.close();
69
+ }
70
+ }
10
71
  function registerAuthCommands(program) {
11
72
  const auth = program.command("auth").description("Manage authentication");
12
73
  auth.command("login").description("Authenticate with Google Play Developer API").option("--service-account <path>", "Path to service account JSON key file").option("--adc", "Use Application Default Credentials").option("--profile <name>", "Store credentials under a named profile").action(async (options) => {
@@ -30,14 +91,20 @@ function registerAuthCommands(program) {
30
91
  console.log(`Authenticated via Application Default Credentials`);
31
92
  console.log(`Account: ${client.getClientEmail()}`);
32
93
  } else {
33
- console.log("Usage: gpc auth login --service-account <path>");
34
- console.log("");
35
- console.log("Authentication methods:");
36
- console.log(" --service-account <path> Service account JSON key file");
37
- console.log(" --adc Application Default Credentials");
38
- console.log("");
39
- console.log("Options:");
40
- console.log(" --profile <name> Store under a named profile");
94
+ const opts = program.opts();
95
+ const interactive = opts["interactive"] !== false && opts["ci"] !== true && process.stdin.isTTY;
96
+ if (interactive) {
97
+ await runLoginWizard();
98
+ } else {
99
+ console.log("Usage: gpc auth login --service-account <path>");
100
+ console.log("");
101
+ console.log("Authentication methods:");
102
+ console.log(" --service-account <path> Service account JSON key file");
103
+ console.log(" --adc Application Default Credentials");
104
+ console.log("");
105
+ console.log("Options:");
106
+ console.log(" --profile <name> Store under a named profile");
107
+ }
41
108
  }
42
109
  } catch (error) {
43
110
  if (error instanceof AuthError) {
@@ -127,6 +194,31 @@ function registerAuthCommands(program) {
127
194
  throw error;
128
195
  }
129
196
  });
197
+ auth.command("setup-gcp").description("Step-by-step guide to create a Google Cloud service account").action(() => {
198
+ console.log("\nGPC \u2014 Google Cloud Service Account Setup");
199
+ console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
200
+ console.log("\nStep 1: Open the Google Cloud Console");
201
+ console.log(" https://console.cloud.google.com/iam-admin/serviceaccounts");
202
+ console.log("\nStep 2: Create a service account");
203
+ console.log(" \u2022 Click 'Create Service Account'");
204
+ console.log(" \u2022 Name it: gpc-deploy (or any name you like)");
205
+ console.log(" \u2022 Description: GPC Google Play Console access");
206
+ console.log("\nStep 3: Grant roles");
207
+ console.log(" No GCP roles needed \u2014 permissions are managed in Google Play Console.");
208
+ console.log("\nStep 4: Download the JSON key");
209
+ console.log(" \u2022 Click your new service account \u2192 Keys \u2192 Add Key \u2192 Create new key \u2192 JSON");
210
+ console.log(" \u2022 Save as: ~/gpc-service-account.json");
211
+ console.log("\nStep 5: Add to Google Play Console");
212
+ console.log(" https://play.google.com/console/developers");
213
+ console.log(" \u2022 Users and Permissions \u2192 Invite new users");
214
+ console.log(" \u2022 Paste the service account email (ends with @...gserviceaccount.com)");
215
+ console.log(" \u2022 Grant: Release manager + View app info + Reply to reviews");
216
+ console.log("\nStep 6: Authenticate");
217
+ console.log(" gpc auth login --service-account ~/gpc-service-account.json");
218
+ console.log("\nStep 7: Verify");
219
+ console.log(" gpc doctor");
220
+ console.log("\nSee full docs: https://yasserstudio.github.io/gpc/guide/authentication");
221
+ });
130
222
  auth.command("profiles").description("List configured profiles").action(async () => {
131
223
  const { listProfiles } = await import("@gpc-cli/config");
132
224
  const config = await loadConfig();
@@ -148,4 +240,4 @@ function registerAuthCommands(program) {
148
240
  export {
149
241
  registerAuthCommands
150
242
  };
151
- //# sourceMappingURL=auth-QSDK7NUO.js.map
243
+ //# sourceMappingURL=auth-KPVEGAWV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/auth.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { createInterface } from \"node:readline\";\nimport { access } from \"node:fs/promises\";\nimport { resolveAuth, loadServiceAccountKey, clearTokenCache, AuthError } from \"@gpc-cli/auth\";\nimport { loadConfig, getCacheDir } from \"@gpc-cli/config\";\nimport { formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\nasync function askQuestion(rl: ReturnType<typeof createInterface>, question: string): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n}\n\nasync function runLoginWizard(): Promise<void> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n try {\n console.log(\"\\nGPC Authentication Setup\");\n console.log(\"─────────────────────────\");\n\n // Step 1: auth method\n console.log(\"\\nAuthentication methods:\");\n console.log(\" 1. Service account key file (recommended)\");\n console.log(\" 2. Application Default Credentials (ADC)\");\n const method = await askQuestion(rl, \"\\nSelect method [1]: \");\n const useAdc = method === \"2\";\n\n if (useAdc) {\n const { resolveAuth: ra } = await import(\"@gpc-cli/auth\");\n const client = await ra();\n console.log(`\\nAuthenticated via Application Default Credentials`);\n console.log(`Account: ${client.getClientEmail()}`);\n return;\n }\n\n // Step 2: credentials path with validation loop\n let saPath = \"\";\n while (!saPath) {\n const input = await askQuestion(rl, \"\\nPath to service account JSON key: \");\n if (!input) { console.log(\" Path is required.\"); continue; }\n try {\n await access(input);\n saPath = input;\n } catch {\n console.log(` File not found: ${input}`);\n }\n }\n\n // Step 3: optional profile name\n const profileName = await askQuestion(rl, \"\\nProfile name (optional, press Enter to skip): \");\n\n // Step 4: default package name\n const packageName = await askQuestion(rl, \"Default package name (optional, e.g. com.example.app): \");\n\n // Apply settings\n const { loadServiceAccountKey: loadKey } = await import(\"@gpc-cli/auth\");\n const key = await loadKey(saPath);\n\n if (profileName) {\n const { setProfileConfig } = await import(\"@gpc-cli/config\");\n await setProfileConfig(profileName, { auth: { serviceAccount: saPath }, ...(packageName && { app: packageName }) });\n console.log(`\\nProfile \"${profileName}\" configured with ${key.client_email}`);\n } else {\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"auth.serviceAccount\", saPath);\n if (packageName) await setConfigValue(\"app\", packageName);\n console.log(`\\nAuthenticated as ${key.client_email}`);\n }\n console.log(`Project: ${key.project_id}`);\n console.log(\"\\nRun 'gpc doctor' to verify your setup.\");\n } finally {\n rl.close();\n }\n}\n\nexport function registerAuthCommands(program: Command): void {\n const auth = program.command(\"auth\").description(\"Manage authentication\");\n\n auth\n .command(\"login\")\n .description(\"Authenticate with Google Play Developer API\")\n .option(\"--service-account <path>\", \"Path to service account JSON key file\")\n .option(\"--adc\", \"Use Application Default Credentials\")\n .option(\"--profile <name>\", \"Store credentials under a named profile\")\n .action(async (options: { serviceAccount?: string; adc?: boolean; profile?: string }) => {\n try {\n if (options.serviceAccount) {\n const key = await loadServiceAccountKey(options.serviceAccount);\n\n if (options.profile) {\n const { setProfileConfig } = await import(\"@gpc-cli/config\");\n await setProfileConfig(options.profile, {\n auth: { serviceAccount: options.serviceAccount },\n });\n console.log(`Profile \"${options.profile}\" configured with ${key.client_email}`);\n } else {\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"auth.serviceAccount\", options.serviceAccount);\n console.log(`Authenticated as ${key.client_email}`);\n }\n console.log(`Project: ${key.project_id}`);\n } else if (options.adc) {\n const client = await resolveAuth();\n console.log(`Authenticated via Application Default Credentials`);\n console.log(`Account: ${client.getClientEmail()}`);\n } else {\n // Interactive wizard when no flags provided and in interactive mode\n const opts = program.opts();\n const interactive = opts[\"interactive\"] !== false && opts[\"ci\"] !== true && process.stdin.isTTY;\n if (interactive) {\n await runLoginWizard();\n } else {\n console.log(\"Usage: gpc auth login --service-account <path>\");\n console.log(\"\");\n console.log(\"Authentication methods:\");\n console.log(\" --service-account <path> Service account JSON key file\");\n console.log(\" --adc Application Default Credentials\");\n console.log(\"\");\n console.log(\"Options:\");\n console.log(\" --profile <name> Store under a named profile\");\n }\n }\n } catch (error) {\n if (error instanceof AuthError) {\n console.error(`Error: ${error.message}`);\n if (error.suggestion) console.error(`Suggestion: ${error.suggestion}`);\n process.exit(3);\n }\n throw error;\n }\n });\n\n auth\n .command(\"status\")\n .description(\"Show current authentication status\")\n .action(async () => {\n const config = await loadConfig();\n try {\n const client = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\n const format = getOutputFormat(program, config);\n const data = {\n authenticated: true,\n account: client.getClientEmail(),\n project: client.getProjectId(),\n ...(config.profile && { profile: config.profile }),\n };\n console.log(formatOutput(data, format));\n } catch (error) {\n if (error instanceof AuthError) {\n const format = getOutputFormat(program, config);\n const data = {\n authenticated: false,\n error: error.message,\n suggestion: error.suggestion,\n };\n console.log(formatOutput(data, format));\n process.exit(3);\n }\n throw error;\n }\n });\n\n auth\n .command(\"logout\")\n .description(\"Clear stored credentials and token cache\")\n .action(async () => {\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"auth.serviceAccount\", \"\");\n await clearTokenCache(getCacheDir());\n console.log(\"Credentials and token cache cleared.\");\n });\n\n auth\n .command(\"whoami\")\n .description(\"Show current authenticated identity\")\n .action(async () => {\n try {\n const config = await loadConfig();\n const client = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\n console.log(client.getClientEmail());\n } catch {\n console.error(\"Not authenticated. Run: gpc auth login\");\n process.exit(3);\n }\n });\n\n auth\n .command(\"switch <profile>\")\n .description(\"Switch to a named profile\")\n .action(async (profile: string) => {\n try {\n // Verify profile exists\n const config = await loadConfig({ profile });\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"profile\", profile);\n console.log(`Switched to profile \"${profile}\"`);\n if (config.auth?.serviceAccount) {\n console.log(`Service account: ${config.auth.serviceAccount}`);\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(2);\n }\n });\n\n auth\n .command(\"token\")\n .description(\"Print the current access token (useful for manual API calls)\")\n .action(async () => {\n try {\n const config = await loadConfig();\n const authClient = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\n const token = await authClient.getAccessToken();\n console.log(token);\n } catch (error) {\n if (error instanceof AuthError) {\n console.error(`Error: ${error.message}`);\n process.exit(3);\n }\n throw error;\n }\n });\n\n auth\n .command(\"setup-gcp\")\n .description(\"Step-by-step guide to create a Google Cloud service account\")\n .action(() => {\n console.log(\"\\nGPC — Google Cloud Service Account Setup\");\n console.log(\"═══════════════════════════════════════════\");\n console.log(\"\\nStep 1: Open the Google Cloud Console\");\n console.log(\" https://console.cloud.google.com/iam-admin/serviceaccounts\");\n console.log(\"\\nStep 2: Create a service account\");\n console.log(\" • Click 'Create Service Account'\");\n console.log(\" • Name it: gpc-deploy (or any name you like)\");\n console.log(\" • Description: GPC Google Play Console access\");\n console.log(\"\\nStep 3: Grant roles\");\n console.log(\" No GCP roles needed — permissions are managed in Google Play Console.\");\n console.log(\"\\nStep 4: Download the JSON key\");\n console.log(\" • Click your new service account → Keys → Add Key → Create new key → JSON\");\n console.log(\" • Save as: ~/gpc-service-account.json\");\n console.log(\"\\nStep 5: Add to Google Play Console\");\n console.log(\" https://play.google.com/console/developers\");\n console.log(\" • Users and Permissions → Invite new users\");\n console.log(\" • Paste the service account email (ends with @...gserviceaccount.com)\");\n console.log(\" • Grant: Release manager + View app info + Reply to reviews\");\n console.log(\"\\nStep 6: Authenticate\");\n console.log(\" gpc auth login --service-account ~/gpc-service-account.json\");\n console.log(\"\\nStep 7: Verify\");\n console.log(\" gpc doctor\");\n console.log(\"\\nSee full docs: https://yasserstudio.github.io/gpc/guide/authentication\");\n });\n\n auth\n .command(\"profiles\")\n .description(\"List configured profiles\")\n .action(async () => {\n const { listProfiles } = await import(\"@gpc-cli/config\");\n const config = await loadConfig();\n const profiles = await listProfiles();\n const format = getOutputFormat(program, config);\n\n if (profiles.length === 0) {\n console.log(\n \"No profiles configured. Use: gpc auth login --service-account <path> --profile <name>\",\n );\n return;\n }\n\n const data = profiles.map((name) => ({\n name,\n active: name === config.profile,\n }));\n console.log(formatOutput(data, format));\n });\n}\n"],"mappings":"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","names":[]}
package/dist/bin.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createProgram,
4
4
  handleCliError,
5
5
  loadPlugins
6
- } from "./chunk-5CSWPQO6.js";
6
+ } from "./chunk-DDTPDKTB.js";
7
7
  import {
8
8
  checkForUpdate,
9
9
  formatUpdateNotification
@@ -44,7 +44,7 @@ if (!_isJsonMode && !_isQuiet && !existsSync(getUserConfigPath())) {
44
44
  }
45
45
  await setupNetworking();
46
46
  initAudit(getConfigDir());
47
- var currentVersion = process.env["__GPC_VERSION"] || "0.0.0";
47
+ var currentVersion = "0.9.35";
48
48
  var isUpdateCommand = process.argv[2] === "update";
49
49
  var updateCheckPromise = isUpdateCommand ? Promise.resolve(null) : checkForUpdate(currentVersion);
50
50
  if (process.argv.includes("--ci")) {
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin.ts","../src/networking.ts"],"sourcesContent":["if (process.env[\"GPC_NO_COLOR\"] === \"1\") process.env[\"NO_COLOR\"] = \"1\";\nif (process.argv.includes(\"--no-color\")) {\n process.env[\"NO_COLOR\"] = \"1\";\n}\nimport { existsSync } from \"node:fs\";\nimport { setupNetworking } from \"./networking.js\";\nimport { createProgram } from \"./program.js\";\nimport { loadPlugins } from \"./plugins.js\";\nimport { handleCliError } from \"./error-handler.js\";\nimport { initAudit, sendWebhook } from \"@gpc-cli/core\";\nimport type { WebhookPayload } from \"@gpc-cli/core\";\nimport { getConfigDir, loadConfig, getUserConfigPath } from \"@gpc-cli/config\";\nimport { checkForUpdate, formatUpdateNotification } from \"./update-check.js\";\n\n// First-run banner\nconst _isJsonMode =\n process.argv.includes(\"--json\") ||\n process.argv.includes(\"-j\") ||\n process.argv.includes(\"--ci\") ||\n (process.argv.includes(\"--output\") &&\n process.argv[process.argv.indexOf(\"--output\") + 1] === \"json\") ||\n (process.argv.includes(\"-o\") &&\n process.argv[process.argv.indexOf(\"-o\") + 1] === \"json\");\nconst _isQuiet = process.argv.includes(\"--quiet\") || process.argv.includes(\"-q\");\n\nif (!_isJsonMode && !_isQuiet && !existsSync(getUserConfigPath())) {\n process.stderr.write(\"✦ First time? Run gpc config init to get set up.\\n\\n\");\n}\n\nawait setupNetworking();\ninitAudit(getConfigDir());\n\nconst currentVersion = process.env[\"__GPC_VERSION\"] || \"0.0.0\";\n\n// Skip passive update check when the user is explicitly running `gpc update` —\n// that command does its own check against the GitHub Releases API.\nconst isUpdateCommand = process.argv[2] === \"update\";\n\n// Start update check before command execution (non-blocking)\nconst updateCheckPromise = isUpdateCommand ? Promise.resolve(null) : checkForUpdate(currentVersion);\n\n// Handle --ci and --json flags early (before command parsing)\nif (process.argv.includes(\"--ci\")) {\n process.env[\"CI\"] = \"1\";\n // --ci implies --output json --no-interactive --no-color\n if (!process.argv.some((a) => a.startsWith(\"--output\") || a.startsWith(\"-o\"))) {\n process.argv.push(\"--output\", \"json\");\n }\n if (!process.argv.includes(\"--no-interactive\")) {\n process.argv.push(\"--no-interactive\");\n }\n if (!process.argv.includes(\"--no-color\")) {\n process.argv.push(\"--no-color\");\n }\n}\nif (process.argv.includes(\"--json\") || process.argv.includes(\"-j\")) {\n if (!process.argv.some((a) => a.startsWith(\"--output\") || a.startsWith(\"-o\"))) {\n process.argv.push(\"--output\", \"json\");\n }\n}\n\nconst pluginManager = await loadPlugins();\nconst program = await createProgram(pluginManager);\n\n// GPC_DEBUG=1 enables verbose mode without mutating process.argv\nif (process.env[\"GPC_DEBUG\"] === \"1\") {\n program.setOptionValueWithSource(\"verbose\", true, \"env\");\n}\n\nconst startTime = Date.now();\nlet commandSuccess = true;\nlet commandError: string | undefined;\n\nawait program.parseAsync(process.argv).catch((error: unknown) => {\n commandSuccess = false;\n commandError = error instanceof Error ? error.message : String(error);\n const exitCode = handleCliError(error);\n process.exit(exitCode);\n});\n\n// Send webhook notification if --notify was set\nconst notifyOpt = program.opts()[\"notify\"] as string | boolean | undefined;\nif (notifyOpt !== undefined && notifyOpt !== false) {\n try {\n const config = await loadConfig();\n if (config.webhooks) {\n const commandName = process.argv.slice(2).filter((a) => !a.startsWith(\"--notify\")).join(\" \");\n const payload: WebhookPayload = {\n command: commandName || \"unknown\",\n success: commandSuccess,\n duration: Date.now() - startTime,\n app: program.opts()[\"app\"] as string | undefined,\n error: commandError,\n };\n\n const target = typeof notifyOpt === \"string\" ? notifyOpt : undefined;\n // Fire-and-forget — do not block exit\n sendWebhook(config.webhooks, payload, target).catch(() => {});\n }\n } catch {\n // Never let webhook logic break the CLI\n }\n}\n\n// After command completes, show update notification if available\n// isUpdateCommand is declared above — update check was skipped for this command\ntry {\n const result = await Promise.race([\n updateCheckPromise,\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 3000)),\n ]);\n\n if (\n result &&\n result.updateAvailable &&\n !isUpdateCommand &&\n process.stdout.isTTY &&\n !process.argv.includes(\"--json\") &&\n program.opts()[\"output\"] !== \"json\"\n ) {\n process.stderr.write(`\\n${formatUpdateNotification(result)}\\n`);\n }\n} catch {\n // Silently ignore update check failures\n}\n","/**\n * Set up proxy and custom CA certificate support.\n * Must be called before any fetch() calls.\n */\nexport async function setupNetworking(): Promise<void> {\n // Map GPC_CA_CERT to NODE_EXTRA_CA_CERTS (works in both Node and Bun)\n const caCert = process.env[\"GPC_CA_CERT\"];\n if (caCert && !process.env[\"NODE_EXTRA_CA_CERTS\"]) {\n process.env[\"NODE_EXTRA_CA_CERTS\"] = caCert;\n }\n\n // In standalone binary mode, Bun handles HTTPS_PROXY/HTTP_PROXY natively\n if (process.env[\"__GPC_BINARY\"] === \"1\") return;\n\n const proxyUrl =\n process.env[\"HTTPS_PROXY\"] ||\n process.env[\"https_proxy\"] ||\n process.env[\"HTTP_PROXY\"] ||\n process.env[\"http_proxy\"];\n if (proxyUrl) {\n try {\n // @ts-expect-error undici types not available in all environments\n const { ProxyAgent, setGlobalDispatcher } = await import(\"undici\");\n setGlobalDispatcher(new ProxyAgent(proxyUrl));\n } catch {\n console.error(\"Warning: Proxy support requires Node.js 20+. HTTPS_PROXY will be ignored.\");\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;AAIA,SAAS,kBAAkB;;;ACA3B,eAAsB,kBAAiC;AAErD,QAAM,SAAS,QAAQ,IAAI,aAAa;AACxC,MAAI,UAAU,CAAC,QAAQ,IAAI,qBAAqB,GAAG;AACjD,YAAQ,IAAI,qBAAqB,IAAI;AAAA,EACvC;AAGA,MAAI,QAAQ,IAAI,cAAc,MAAM,IAAK;AAEzC,QAAM,WACJ,QAAQ,IAAI,aAAa,KACzB,QAAQ,IAAI,aAAa,KACzB,QAAQ,IAAI,YAAY,KACxB,QAAQ,IAAI,YAAY;AAC1B,MAAI,UAAU;AACZ,QAAI;AAEF,YAAM,EAAE,YAAY,oBAAoB,IAAI,MAAM,OAAO,QAAQ;AACjE,0BAAoB,IAAI,WAAW,QAAQ,CAAC;AAAA,IAC9C,QAAQ;AACN,cAAQ,MAAM,2EAA2E;AAAA,IAC3F;AAAA,EACF;AACF;;;ADnBA,SAAS,WAAW,mBAAmB;AAEvC,SAAS,cAAc,YAAY,yBAAyB;AAX5D,IAAI,QAAQ,IAAI,cAAc,MAAM,IAAK,SAAQ,IAAI,UAAU,IAAI;AACnE,IAAI,QAAQ,KAAK,SAAS,YAAY,GAAG;AACvC,UAAQ,IAAI,UAAU,IAAI;AAC5B;AAYA,IAAM,cACJ,QAAQ,KAAK,SAAS,QAAQ,KAC9B,QAAQ,KAAK,SAAS,IAAI,KAC1B,QAAQ,KAAK,SAAS,MAAM,KAC3B,QAAQ,KAAK,SAAS,UAAU,KAC/B,QAAQ,KAAK,QAAQ,KAAK,QAAQ,UAAU,IAAI,CAAC,MAAM,UACxD,QAAQ,KAAK,SAAS,IAAI,KACzB,QAAQ,KAAK,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM;AACrD,IAAM,WAAW,QAAQ,KAAK,SAAS,SAAS,KAAK,QAAQ,KAAK,SAAS,IAAI;AAE/E,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,WAAW,kBAAkB,CAAC,GAAG;AACjE,UAAQ,OAAO,MAAM,2DAAsD;AAC7E;AAEA,MAAM,gBAAgB;AACtB,UAAU,aAAa,CAAC;AAExB,IAAM,iBAAiB,QAAQ,IAAI,eAAe,KAAK;AAIvD,IAAM,kBAAkB,QAAQ,KAAK,CAAC,MAAM;AAG5C,IAAM,qBAAqB,kBAAkB,QAAQ,QAAQ,IAAI,IAAI,eAAe,cAAc;AAGlG,IAAI,QAAQ,KAAK,SAAS,MAAM,GAAG;AACjC,UAAQ,IAAI,IAAI,IAAI;AAEpB,MAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,UAAU,KAAK,EAAE,WAAW,IAAI,CAAC,GAAG;AAC7E,YAAQ,KAAK,KAAK,YAAY,MAAM;AAAA,EACtC;AACA,MAAI,CAAC,QAAQ,KAAK,SAAS,kBAAkB,GAAG;AAC9C,YAAQ,KAAK,KAAK,kBAAkB;AAAA,EACtC;AACA,MAAI,CAAC,QAAQ,KAAK,SAAS,YAAY,GAAG;AACxC,YAAQ,KAAK,KAAK,YAAY;AAAA,EAChC;AACF;AACA,IAAI,QAAQ,KAAK,SAAS,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG;AAClE,MAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,UAAU,KAAK,EAAE,WAAW,IAAI,CAAC,GAAG;AAC7E,YAAQ,KAAK,KAAK,YAAY,MAAM;AAAA,EACtC;AACF;AAEA,IAAM,gBAAgB,MAAM,YAAY;AACxC,IAAM,UAAU,MAAM,cAAc,aAAa;AAGjD,IAAI,QAAQ,IAAI,WAAW,MAAM,KAAK;AACpC,UAAQ,yBAAyB,WAAW,MAAM,KAAK;AACzD;AAEA,IAAM,YAAY,KAAK,IAAI;AAC3B,IAAI,iBAAiB;AACrB,IAAI;AAEJ,MAAM,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,UAAmB;AAC/D,mBAAiB;AACjB,iBAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,QAAM,WAAW,eAAe,KAAK;AACrC,UAAQ,KAAK,QAAQ;AACvB,CAAC;AAGD,IAAM,YAAY,QAAQ,KAAK,EAAE,QAAQ;AACzC,IAAI,cAAc,UAAa,cAAc,OAAO;AAClD,MAAI;AACF,UAAM,SAAS,MAAM,WAAW;AAChC,QAAI,OAAO,UAAU;AACnB,YAAM,cAAc,QAAQ,KAAK,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,UAAU,CAAC,EAAE,KAAK,GAAG;AAC3F,YAAM,UAA0B;AAAA,QAC9B,SAAS,eAAe;AAAA,QACxB,SAAS;AAAA,QACT,UAAU,KAAK,IAAI,IAAI;AAAA,QACvB,KAAK,QAAQ,KAAK,EAAE,KAAK;AAAA,QACzB,OAAO;AAAA,MACT;AAEA,YAAM,SAAS,OAAO,cAAc,WAAW,YAAY;AAE3D,kBAAY,OAAO,UAAU,SAAS,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC9D;AAAA,EACF,QAAQ;AAAA,EAER;AACF;AAIA,IAAI;AACF,QAAM,SAAS,MAAM,QAAQ,KAAK;AAAA,IAChC;AAAA,IACA,IAAI,QAAc,CAAC,YAAY,WAAW,MAAM,QAAQ,IAAI,GAAG,GAAI,CAAC;AAAA,EACtE,CAAC;AAED,MACE,UACA,OAAO,mBACP,CAAC,mBACD,QAAQ,OAAO,SACf,CAAC,QAAQ,KAAK,SAAS,QAAQ,KAC/B,QAAQ,KAAK,EAAE,QAAQ,MAAM,QAC7B;AACA,YAAQ,OAAO,MAAM;AAAA,EAAK,yBAAyB,MAAM,CAAC;AAAA,CAAI;AAAA,EAChE;AACF,QAAQ;AAER;","names":[]}
1
+ {"version":3,"sources":["../src/bin.ts","../src/networking.ts"],"sourcesContent":["if (process.env[\"GPC_NO_COLOR\"] === \"1\") process.env[\"NO_COLOR\"] = \"1\";\nif (process.argv.includes(\"--no-color\")) {\n process.env[\"NO_COLOR\"] = \"1\";\n}\nimport { existsSync } from \"node:fs\";\nimport { setupNetworking } from \"./networking.js\";\nimport { createProgram } from \"./program.js\";\nimport { loadPlugins } from \"./plugins.js\";\nimport { handleCliError } from \"./error-handler.js\";\nimport { initAudit, sendWebhook } from \"@gpc-cli/core\";\nimport type { WebhookPayload } from \"@gpc-cli/core\";\nimport { getConfigDir, loadConfig, getUserConfigPath } from \"@gpc-cli/config\";\nimport { checkForUpdate, formatUpdateNotification } from \"./update-check.js\";\n\n// First-run banner\nconst _isJsonMode =\n process.argv.includes(\"--json\") ||\n process.argv.includes(\"-j\") ||\n process.argv.includes(\"--ci\") ||\n (process.argv.includes(\"--output\") &&\n process.argv[process.argv.indexOf(\"--output\") + 1] === \"json\") ||\n (process.argv.includes(\"-o\") &&\n process.argv[process.argv.indexOf(\"-o\") + 1] === \"json\");\nconst _isQuiet = process.argv.includes(\"--quiet\") || process.argv.includes(\"-q\");\n\nif (!_isJsonMode && !_isQuiet && !existsSync(getUserConfigPath())) {\n process.stderr.write(\"✦ First time? Run gpc config init to get set up.\\n\\n\");\n}\n\nawait setupNetworking();\ninitAudit(getConfigDir());\n\nconst currentVersion = process.env[\"__GPC_VERSION\"] || \"0.0.0\";\n\n// Skip passive update check when the user is explicitly running `gpc update` —\n// that command does its own check against the GitHub Releases API.\nconst isUpdateCommand = process.argv[2] === \"update\";\n\n// Start update check before command execution (non-blocking)\nconst updateCheckPromise = isUpdateCommand ? Promise.resolve(null) : checkForUpdate(currentVersion);\n\n// Handle --ci and --json flags early (before command parsing)\nif (process.argv.includes(\"--ci\")) {\n process.env[\"CI\"] = \"1\";\n // --ci implies --output json --no-interactive --no-color\n if (!process.argv.some((a) => a.startsWith(\"--output\") || a.startsWith(\"-o\"))) {\n process.argv.push(\"--output\", \"json\");\n }\n if (!process.argv.includes(\"--no-interactive\")) {\n process.argv.push(\"--no-interactive\");\n }\n if (!process.argv.includes(\"--no-color\")) {\n process.argv.push(\"--no-color\");\n }\n}\nif (process.argv.includes(\"--json\") || process.argv.includes(\"-j\")) {\n if (!process.argv.some((a) => a.startsWith(\"--output\") || a.startsWith(\"-o\"))) {\n process.argv.push(\"--output\", \"json\");\n }\n}\n\nconst pluginManager = await loadPlugins();\nconst program = await createProgram(pluginManager);\n\n// GPC_DEBUG=1 enables verbose mode without mutating process.argv\nif (process.env[\"GPC_DEBUG\"] === \"1\") {\n program.setOptionValueWithSource(\"verbose\", true, \"env\");\n}\n\nconst startTime = Date.now();\nlet commandSuccess = true;\nlet commandError: string | undefined;\n\nawait program.parseAsync(process.argv).catch((error: unknown) => {\n commandSuccess = false;\n commandError = error instanceof Error ? error.message : String(error);\n const exitCode = handleCliError(error);\n process.exit(exitCode);\n});\n\n// Send webhook notification if --notify was set\nconst notifyOpt = program.opts()[\"notify\"] as string | boolean | undefined;\nif (notifyOpt !== undefined && notifyOpt !== false) {\n try {\n const config = await loadConfig();\n if (config.webhooks) {\n const commandName = process.argv.slice(2).filter((a) => !a.startsWith(\"--notify\")).join(\" \");\n const payload: WebhookPayload = {\n command: commandName || \"unknown\",\n success: commandSuccess,\n duration: Date.now() - startTime,\n app: program.opts()[\"app\"] as string | undefined,\n error: commandError,\n };\n\n const target = typeof notifyOpt === \"string\" ? notifyOpt : undefined;\n // Fire-and-forget — do not block exit\n sendWebhook(config.webhooks, payload, target).catch(() => {});\n }\n } catch {\n // Never let webhook logic break the CLI\n }\n}\n\n// After command completes, show update notification if available\n// isUpdateCommand is declared above — update check was skipped for this command\ntry {\n const result = await Promise.race([\n updateCheckPromise,\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 3000)),\n ]);\n\n if (\n result &&\n result.updateAvailable &&\n !isUpdateCommand &&\n process.stdout.isTTY &&\n !process.argv.includes(\"--json\") &&\n program.opts()[\"output\"] !== \"json\"\n ) {\n process.stderr.write(`\\n${formatUpdateNotification(result)}\\n`);\n }\n} catch {\n // Silently ignore update check failures\n}\n","/**\n * Set up proxy and custom CA certificate support.\n * Must be called before any fetch() calls.\n */\nexport async function setupNetworking(): Promise<void> {\n // Map GPC_CA_CERT to NODE_EXTRA_CA_CERTS (works in both Node and Bun)\n const caCert = process.env[\"GPC_CA_CERT\"];\n if (caCert && !process.env[\"NODE_EXTRA_CA_CERTS\"]) {\n process.env[\"NODE_EXTRA_CA_CERTS\"] = caCert;\n }\n\n // In standalone binary mode, Bun handles HTTPS_PROXY/HTTP_PROXY natively\n if (process.env[\"__GPC_BINARY\"] === \"1\") return;\n\n const proxyUrl =\n process.env[\"HTTPS_PROXY\"] ||\n process.env[\"https_proxy\"] ||\n process.env[\"HTTP_PROXY\"] ||\n process.env[\"http_proxy\"];\n if (proxyUrl) {\n try {\n // @ts-expect-error undici types not available in all environments\n const { ProxyAgent, setGlobalDispatcher } = await import(\"undici\");\n setGlobalDispatcher(new ProxyAgent(proxyUrl));\n } catch {\n console.error(\"Warning: Proxy support requires Node.js 20+. HTTPS_PROXY will be ignored.\");\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -7,6 +7,8 @@ import {
7
7
  import {
8
8
  analyzeBundle,
9
9
  compareBundles,
10
+ topFiles,
11
+ checkBundleSize,
10
12
  formatOutput
11
13
  } from "@gpc-cli/core";
12
14
  function formatSize(bytes) {
@@ -22,7 +24,7 @@ function formatDelta(delta) {
22
24
  }
23
25
  function registerBundleCommands(program) {
24
26
  const bundle = program.command("bundle").description("Analyze app bundles and APKs");
25
- bundle.command("analyze <file>").description("Analyze size breakdown of an AAB or APK").option("--threshold <mb>", "Fail if compressed size exceeds threshold (MB)", parseFloat).action(async (file, opts) => {
27
+ bundle.command("analyze <file>").description("Analyze size breakdown of an AAB or APK").option("--threshold <mb>", "Fail if compressed size exceeds threshold (MB)", parseFloat).option("--top <n>", "Show top N largest files", (v) => parseInt(v, 10)).option("--config <file>", "Check against .bundlesize.json thresholds").action(async (file, opts) => {
26
28
  const format = getOutputFormat(program, await getConfig());
27
29
  try {
28
30
  const analysis = await analyzeBundle(file);
@@ -82,6 +84,29 @@ File: ${analysis.filePath}`);
82
84
  console.log("\nCategories:");
83
85
  console.log(formatOutput(categoryRows, "table"));
84
86
  }
87
+ if (opts.top !== void 0) {
88
+ const largest = topFiles(analysis, opts.top);
89
+ const topRows = largest.map((e) => ({
90
+ path: e.path,
91
+ compressed: formatSize(e.compressedSize),
92
+ uncompressed: formatSize(e.uncompressedSize),
93
+ category: e.category
94
+ }));
95
+ console.log(`
96
+ Top ${opts.top} files:`);
97
+ console.log(formatOutput(topRows, format === "json" ? "table" : format));
98
+ }
99
+ if (opts.config) {
100
+ const check = await checkBundleSize(analysis, opts.config);
101
+ if (!check.passed) {
102
+ console.error(`
103
+ Bundle size check failed:`);
104
+ for (const v of check.violations) {
105
+ console.error(` ${v.subject}: ${formatSize(v.actual)} > max ${formatSize(v.max)}`);
106
+ }
107
+ process.exit(6);
108
+ }
109
+ }
85
110
  if (opts.threshold !== void 0) {
86
111
  const thresholdBytes = opts.threshold * 1024 * 1024;
87
112
  if (analysis.totalCompressed > thresholdBytes) {
@@ -181,4 +206,4 @@ async function getConfig() {
181
206
  export {
182
207
  registerBundleCommands
183
208
  };
184
- //# sourceMappingURL=bundle-7IF5FIB4.js.map
209
+ //# sourceMappingURL=bundle-7XYHNVNF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/bundle.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport {\n analyzeBundle,\n compareBundles,\n topFiles,\n checkBundleSize,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\nfunction formatSize(bytes: number): string {\n const abs = Math.abs(bytes);\n const sign = bytes < 0 ? \"-\" : \"\";\n if (abs < 1024) return `${sign}${abs} B`;\n if (abs < 1024 * 1024) return `${sign}${(abs / 1024).toFixed(1)} KB`;\n return `${sign}${(abs / (1024 * 1024)).toFixed(2)} MB`;\n}\n\nfunction formatDelta(delta: number): string {\n const prefix = delta > 0 ? \"+\" : \"\";\n return `${prefix}${formatSize(delta)}`;\n}\n\nexport function registerBundleCommands(program: Command): void {\n const bundle = program.command(\"bundle\").description(\"Analyze app bundles and APKs\");\n\n bundle\n .command(\"analyze <file>\")\n .description(\"Analyze size breakdown of an AAB or APK\")\n .option(\"--threshold <mb>\", \"Fail if compressed size exceeds threshold (MB)\", parseFloat)\n .option(\"--top <n>\", \"Show top N largest files\", (v) => parseInt(v, 10))\n .option(\"--config <file>\", \"Check against .bundlesize.json thresholds\")\n .action(async (file: string, opts: { threshold?: number; top?: number; config?: string }) => {\n const format = getOutputFormat(program, await getConfig());\n\n try {\n const analysis = await analyzeBundle(file);\n\n if (format === \"json\") {\n console.log(formatOutput(analysis, format));\n } else if (format === \"markdown\") {\n const moduleRows = analysis.modules.map((m) => ({\n module: m.name,\n compressed: formatSize(m.compressedSize),\n uncompressed: formatSize(m.uncompressedSize),\n entries: m.entries,\n }));\n const categoryRows = analysis.categories.map((c) => ({\n category: c.name,\n compressed: formatSize(c.compressedSize),\n uncompressed: formatSize(c.uncompressedSize),\n entries: c.entries,\n }));\n console.log(`## Bundle Analysis: \\`${analysis.filePath}\\``);\n console.log();\n console.log(`| Property | Value |`);\n console.log(`| --- | --- |`);\n console.log(`| Type | ${analysis.fileType.toUpperCase()} |`);\n console.log(`| Total compressed | ${formatSize(analysis.totalCompressed)} |`);\n console.log(`| Total uncompressed | ${formatSize(analysis.totalUncompressed)} |`);\n console.log(`| Entries | ${analysis.entryCount} |`);\n console.log();\n console.log(`### Modules`);\n console.log();\n console.log(formatOutput(moduleRows, \"markdown\"));\n console.log();\n console.log(`### Categories`);\n console.log();\n console.log(formatOutput(categoryRows, \"markdown\"));\n } else {\n console.log(`\\nFile: ${analysis.filePath}`);\n console.log(`Type: ${analysis.fileType.toUpperCase()}`);\n console.log(`Total compressed: ${formatSize(analysis.totalCompressed)}`);\n console.log(`Total uncompressed: ${formatSize(analysis.totalUncompressed)}`);\n console.log(`Entries: ${analysis.entryCount}\\n`);\n\n // Modules table\n const moduleRows = analysis.modules.map((m) => ({\n module: m.name,\n compressed: formatSize(m.compressedSize),\n uncompressed: formatSize(m.uncompressedSize),\n entries: m.entries,\n }));\n console.log(\"Modules:\");\n console.log(formatOutput(moduleRows, \"table\"));\n\n // Categories table\n const categoryRows = analysis.categories.map((c) => ({\n category: c.name,\n compressed: formatSize(c.compressedSize),\n uncompressed: formatSize(c.uncompressedSize),\n entries: c.entries,\n }));\n console.log(\"\\nCategories:\");\n console.log(formatOutput(categoryRows, \"table\"));\n }\n\n // Top N files\n if (opts.top !== undefined) {\n const largest = topFiles(analysis, opts.top);\n const topRows = largest.map((e) => ({\n path: e.path,\n compressed: formatSize(e.compressedSize),\n uncompressed: formatSize(e.uncompressedSize),\n category: e.category,\n }));\n console.log(`\\nTop ${opts.top} files:`);\n console.log(formatOutput(topRows, format === \"json\" ? \"table\" : format));\n }\n\n // .bundlesize.json config check\n if (opts.config) {\n const check = await checkBundleSize(analysis, opts.config);\n if (!check.passed) {\n console.error(`\\nBundle size check failed:`);\n for (const v of check.violations) {\n console.error(` ${v.subject}: ${formatSize(v.actual)} > max ${formatSize(v.max)}`);\n }\n process.exit(6);\n }\n }\n\n // Legacy --threshold check\n if (opts.threshold !== undefined) {\n const thresholdBytes = opts.threshold * 1024 * 1024;\n if (analysis.totalCompressed > thresholdBytes) {\n console.error(\n `\\nThreshold breached: ${formatSize(analysis.totalCompressed)} > ${opts.threshold} MB`,\n );\n process.exit(6);\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n\n bundle\n .command(\"compare <file1> <file2>\")\n .description(\"Compare size differences between two bundles or APKs\")\n .action(async (file1: string, file2: string) => {\n const format = getOutputFormat(program, await getConfig());\n\n try {\n const [before, after] = await Promise.all([\n analyzeBundle(file1),\n analyzeBundle(file2),\n ]);\n const comparison = compareBundles(before, after);\n\n if (format === \"json\") {\n console.log(formatOutput(comparison, format));\n } else if (format === \"markdown\") {\n const sign = comparison.sizeDelta >= 0 ? \"+\" : \"\";\n const moduleRows = comparison.moduleDeltas\n .filter((m) => m.delta !== 0)\n .map((m) => ({\n module: m.module,\n before: formatSize(m.before),\n after: formatSize(m.after),\n delta: formatDelta(m.delta),\n }));\n const categoryRows = comparison.categoryDeltas\n .filter((c) => c.delta !== 0)\n .map((c) => ({\n category: c.category,\n before: formatSize(c.before),\n after: formatSize(c.after),\n delta: formatDelta(c.delta),\n }));\n console.log(`## Bundle Comparison`);\n console.log();\n console.log(`| | Path | Size |`);\n console.log(`| --- | --- | --- |`);\n console.log(`| Before | \\`${comparison.before.path}\\` | ${formatSize(comparison.before.totalCompressed)} |`);\n console.log(`| After | \\`${comparison.after.path}\\` | ${formatSize(comparison.after.totalCompressed)} |`);\n console.log(`| **Delta** | | **${sign}${formatSize(comparison.sizeDelta)} (${sign}${comparison.sizeDeltaPercent}%)** |`);\n if (moduleRows.length > 0) {\n console.log();\n console.log(`### Module Changes`);\n console.log();\n console.log(formatOutput(moduleRows, \"markdown\"));\n }\n if (categoryRows.length > 0) {\n console.log();\n console.log(`### Category Changes`);\n console.log();\n console.log(formatOutput(categoryRows, \"markdown\"));\n }\n } else {\n const sign = comparison.sizeDelta >= 0 ? \"+\" : \"\";\n console.log(`\\nBefore: ${comparison.before.path} (${formatSize(comparison.before.totalCompressed)})`);\n console.log(`After: ${comparison.after.path} (${formatSize(comparison.after.totalCompressed)})`);\n console.log(`Delta: ${sign}${formatSize(comparison.sizeDelta)} (${sign}${comparison.sizeDeltaPercent}%)\\n`);\n\n // Module deltas\n const moduleRows = comparison.moduleDeltas\n .filter((m) => m.delta !== 0)\n .map((m) => ({\n module: m.module,\n before: formatSize(m.before),\n after: formatSize(m.after),\n delta: formatDelta(m.delta),\n }));\n if (moduleRows.length > 0) {\n console.log(\"Module changes:\");\n console.log(formatOutput(moduleRows, \"table\"));\n }\n\n // Category deltas\n const categoryRows = comparison.categoryDeltas\n .filter((c) => c.delta !== 0)\n .map((c) => ({\n category: c.category,\n before: formatSize(c.before),\n after: formatSize(c.after),\n delta: formatDelta(c.delta),\n }));\n if (categoryRows.length > 0) {\n console.log(\"\\nCategory changes:\");\n console.log(formatOutput(categoryRows, \"table\"));\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n });\n}\n\nasync function getConfig() {\n const { loadConfig } = await import(\"@gpc-cli/config\");\n return loadConfig();\n}\n"],"mappings":"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","names":[]}
@@ -111,4 +111,4 @@ function registerCacheCommand(program) {
111
111
  export {
112
112
  registerCacheCommand
113
113
  };
114
- //# sourceMappingURL=cache-SHWAVON6.js.map
114
+ //# sourceMappingURL=cache-K23N6GJR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/cache.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { readdir, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { getCacheDir } from \"@gpc-cli/config\";\n\nconst FILE_TYPES: Record<string, (name: string) => boolean> = {\n status: (name) => name.startsWith(\"status-\") && name.endsWith(\".json\"),\n token: (name) => name === \"token-cache.json\",\n update: (name) => name === \"update-check.json\",\n};\n\nasync function getCacheFiles(cacheDir: string): Promise<{ name: string; path: string; size: number; mtime: Date }[]> {\n let entries: string[];\n try {\n entries = await readdir(cacheDir);\n } catch {\n return [];\n }\n\n const files: { name: string; path: string; size: number; mtime: Date }[] = [];\n for (const entry of entries) {\n if (!entry.endsWith(\".json\")) continue;\n const filePath = join(cacheDir, entry);\n try {\n const info = await stat(filePath);\n if (info.isFile()) {\n files.push({ name: entry, path: filePath, size: info.size, mtime: info.mtime });\n }\n } catch { /* ignore */ }\n }\n return files;\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction fileType(name: string): string {\n for (const [type, matcher] of Object.entries(FILE_TYPES)) {\n if (matcher(name)) return type;\n }\n return \"other\";\n}\n\nexport function registerCacheCommand(program: Command): void {\n const cache = program.command(\"cache\").description(\"Manage local cache files\");\n\n cache\n .command(\"info\")\n .description(\"Show cache directory and total size\")\n .action(async () => {\n const cacheDir = getCacheDir();\n const files = await getCacheFiles(cacheDir);\n const totalSize = files.reduce((sum, f) => sum + f.size, 0);\n console.log(`Cache directory: ${cacheDir}`);\n console.log(`Files: ${files.length}`);\n console.log(`Total size: ${formatBytes(totalSize)}`);\n });\n\n cache\n .command(\"list\")\n .description(\"List all cache files with size and age\")\n .action(async () => {\n const cacheDir = getCacheDir();\n const files = await getCacheFiles(cacheDir);\n if (files.length === 0) {\n console.log(\"No cache files found.\");\n return;\n }\n const now = Date.now();\n for (const f of files) {\n const ageMs = now - f.mtime.getTime();\n const ageMins = Math.floor(ageMs / 60000);\n const ageStr = ageMins < 60\n ? `${ageMins}m ago`\n : ageMins < 1440\n ? `${Math.floor(ageMins / 60)}h ago`\n : `${Math.floor(ageMins / 1440)}d ago`;\n const type = fileType(f.name);\n console.log(` ${f.name} [${type}] ${formatBytes(f.size)} ${ageStr}`);\n }\n });\n\n cache\n .command(\"clear\")\n .description(\"Remove cache files\")\n .option(\"--force\", \"Skip confirmation prompt\")\n .option(\"--type <type>\", \"Remove only files of this type (status|token|update)\")\n .action(async (opts) => {\n const cacheDir = getCacheDir();\n const allFiles = await getCacheFiles(cacheDir);\n\n let toDelete = allFiles;\n if (opts.type) {\n const matcher = FILE_TYPES[opts.type];\n if (!matcher) {\n console.error(`Error: Unknown cache type \"${opts.type}\". Valid types: ${Object.keys(FILE_TYPES).join(\", \")}`);\n process.exit(2);\n }\n toDelete = allFiles.filter((f) => matcher(f.name));\n }\n\n if (toDelete.length === 0) {\n console.log(\"No cache files to remove.\");\n return;\n }\n\n if (!opts.force) {\n console.log(`About to remove ${toDelete.length} file(s) from ${cacheDir}:`);\n for (const f of toDelete) {\n console.log(` ${f.name} (${formatBytes(f.size)})`);\n }\n const { createInterface } = await import(\"node:readline\");\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => rl.question(\"Proceed? [y/N] \", resolve));\n rl.close();\n if (answer.toLowerCase() !== \"y\") {\n console.log(\"Aborted.\");\n return;\n }\n }\n\n let removed = 0;\n for (const f of toDelete) {\n try {\n await unlink(f.path);\n removed++;\n } catch { /* ignore */ }\n }\n console.log(`Removed ${removed} file(s).`);\n });\n}\n"],"mappings":"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","names":[]}
@@ -197,10 +197,10 @@ async function sha256File(filePath) {
197
197
  if (size === 0) return hash.digest("hex");
198
198
  const { createReadStream } = await import("fs");
199
199
  const stream = createReadStream(filePath);
200
- await pipeline(stream, async function* (source) {
201
- for await (const chunk of source) {
202
- hash.update(chunk);
203
- }
200
+ await new Promise((resolve, reject) => {
201
+ stream.on("data", (chunk) => hash.update(chunk));
202
+ stream.on("end", resolve);
203
+ stream.on("error", reject);
204
204
  });
205
205
  return hash.digest("hex");
206
206
  }
@@ -311,4 +311,4 @@ export {
311
311
  updateViaBrew,
312
312
  updateBinaryInPlace
313
313
  };
314
- //# sourceMappingURL=chunk-UH3TMIAL.js.map
314
+ //# sourceMappingURL=chunk-43SH6XEJ.js.map