@gpc-cli/cli 0.9.46 → 0.9.48

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 (52) hide show
  1. package/README.md +36 -15
  2. package/dist/{anomalies-UDE4NGHJ.js → anomalies-V3AFS4LD.js} +20 -3
  3. package/dist/anomalies-V3AFS4LD.js.map +1 -0
  4. package/dist/{audit-JASSHRWN.js → audit-VTWXTXC6.js} +5 -4
  5. package/dist/audit-VTWXTXC6.js.map +1 -0
  6. package/dist/{auth-OTA3SV3J.js → auth-BA4FE2PO.js} +85 -24
  7. package/dist/auth-BA4FE2PO.js.map +1 -0
  8. package/dist/bin.js +2 -2
  9. package/dist/{changelog-7COFZO7Q.js → changelog-QLDFG5TV.js} +5 -5
  10. package/dist/changelog-QLDFG5TV.js.map +1 -0
  11. package/dist/{chunk-6OWN6S6X.js → chunk-XBH2V2XK.js} +21 -18
  12. package/dist/chunk-XBH2V2XK.js.map +1 -0
  13. package/dist/{config-2FTCYEGD.js → config-NQQF4522.js} +2 -2
  14. package/dist/{doctor-H4X7Q57B.js → doctor-KGYUWHL5.js} +36 -3
  15. package/dist/doctor-KGYUWHL5.js.map +1 -0
  16. package/dist/{feedback-XP765TOO.js → feedback-RMLYHTAH.js} +2 -2
  17. package/dist/index.js +1 -1
  18. package/dist/{install-skills-6QDUXI5F.js → install-skills-JKPYZHYS.js} +2 -2
  19. package/dist/{install-skills-6QDUXI5F.js.map → install-skills-JKPYZHYS.js.map} +1 -1
  20. package/dist/{purchases-DAWTMXP6.js → purchases-UBFLNYZC.js} +16 -3
  21. package/dist/purchases-UBFLNYZC.js.map +1 -0
  22. package/dist/{releases-2I3WBULC.js → releases-OUJ65774.js} +10 -7
  23. package/dist/releases-OUJ65774.js.map +1 -0
  24. package/dist/{reviews-BCCXIQ6C.js → reviews-YCBBM656.js} +15 -4
  25. package/dist/reviews-YCBBM656.js.map +1 -0
  26. package/dist/rtdn-LID2B7XZ.js +87 -0
  27. package/dist/rtdn-LID2B7XZ.js.map +1 -0
  28. package/dist/{subscriptions-DZP3Y7O7.js → subscriptions-LURZFPGJ.js} +5 -4
  29. package/dist/subscriptions-LURZFPGJ.js.map +1 -0
  30. package/dist/{tracks-YHMO2A6B.js → tracks-DO7C5OSE.js} +3 -3
  31. package/dist/tracks-DO7C5OSE.js.map +1 -0
  32. package/dist/{update-OMALGIBR.js → update-QUQ7N7QJ.js} +2 -2
  33. package/dist/{version-NCSNXNVN.js → version-WGE5Q7QH.js} +2 -2
  34. package/dist/{vitals-C23L2Y2E.js → vitals-PJEQUUAK.js} +35 -7
  35. package/dist/vitals-PJEQUUAK.js.map +1 -0
  36. package/package.json +5 -5
  37. package/dist/anomalies-UDE4NGHJ.js.map +0 -1
  38. package/dist/audit-JASSHRWN.js.map +0 -1
  39. package/dist/auth-OTA3SV3J.js.map +0 -1
  40. package/dist/changelog-7COFZO7Q.js.map +0 -1
  41. package/dist/chunk-6OWN6S6X.js.map +0 -1
  42. package/dist/doctor-H4X7Q57B.js.map +0 -1
  43. package/dist/purchases-DAWTMXP6.js.map +0 -1
  44. package/dist/releases-2I3WBULC.js.map +0 -1
  45. package/dist/reviews-BCCXIQ6C.js.map +0 -1
  46. package/dist/subscriptions-DZP3Y7O7.js.map +0 -1
  47. package/dist/tracks-YHMO2A6B.js.map +0 -1
  48. package/dist/vitals-C23L2Y2E.js.map +0 -1
  49. /package/dist/{config-2FTCYEGD.js.map → config-NQQF4522.js.map} +0 -0
  50. /package/dist/{feedback-XP765TOO.js.map → feedback-RMLYHTAH.js.map} +0 -0
  51. /package/dist/{update-OMALGIBR.js.map → update-QUQ7N7QJ.js.map} +0 -0
  52. /package/dist/{version-NCSNXNVN.js.map → version-WGE5Q7QH.js.map} +0 -0
package/README.md CHANGED
@@ -3,14 +3,14 @@
3
3
  <p align="center"><strong>Ship Android apps from your terminal.</strong></p>
4
4
 
5
5
  <p align="center">
6
- The complete CLI for Google Play — 187 API endpoints, one tool.<br>
6
+ The complete CLI for Google Play — 204 API endpoints, one tool.<br>
7
7
  Releases, rollouts, metadata, vitals, reviews, subscriptions, reports, and more.
8
8
  </p>
9
9
 
10
10
  <p align="center">
11
11
  <a href="https://www.npmjs.com/package/@gpc-cli/cli"><img src="https://img.shields.io/npm/v/@gpc-cli/cli?color=00D26A" alt="npm version"></a>
12
12
  <a href="https://github.com/yasserstudio/gpc"><img src="https://img.shields.io/github/stars/yasserstudio/gpc" alt="GitHub Stars"></a>
13
- <img src="https://img.shields.io/badge/Tests-1504_passing-00D26A" alt="Tests">
13
+ <img src="https://img.shields.io/badge/Tests-1845_passing-00D26A" alt="Tests">
14
14
  <img src="https://img.shields.io/badge/License-MIT-yellow" alt="License">
15
15
  </p>
16
16
 
@@ -23,8 +23,11 @@ npm install -g @gpc-cli/cli
23
23
  # Homebrew (macOS/Linux)
24
24
  brew install yasserstudio/tap/gpc
25
25
 
26
- # Standalone binary (no Node.js required)
26
+ # Standalone binary — macOS/Linux (no Node.js required)
27
27
  curl -fsSL https://raw.githubusercontent.com/yasserstudio/gpc/main/scripts/install.sh | sh
28
+
29
+ # Standalone binary — Windows (PowerShell)
30
+ iwr -useb https://raw.githubusercontent.com/yasserstudio/gpc/main/scripts/install.ps1 | iex
28
31
  ```
29
32
 
30
33
  Free. Open-source. No account required beyond your existing Google Play service account.
@@ -35,13 +38,13 @@ Free. Open-source. No account required beyond your existing Google Play service
35
38
  # Authenticate
36
39
  gpc auth login --service-account path/to/key.json
37
40
 
38
- # Verify your setup
41
+ # Verify your setup (20 automated checks)
39
42
  gpc doctor
40
43
 
41
44
  # App health at a glance — releases, vitals, and reviews in one command
42
45
  gpc status
43
46
 
44
- # Upload and release
47
+ # Upload and release (AAB or APK)
45
48
  gpc releases upload app.aab --track internal
46
49
 
47
50
  # Promote to production
@@ -75,25 +78,42 @@ REVIEWS (last 30 days)
75
78
 
76
79
  ## What You Get
77
80
 
78
- 187 API endpoints across these command groups:
81
+ 204 API endpoints across these command groups:
79
82
 
80
83
  | Group | What you can do |
81
84
  | ----------------- | -------------------------------------------------------------------------------------- |
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 |
85
+ | **Releases** | Upload AAB/APK, promote, rollout increase/halt/resume, draft releases, `publish` |
86
+ | **Preflight** | 9 offline AAB policy scannerscatches rejections before upload |
87
+ | **Listings** | Pull and push store listings, upload screenshots Fastlane metadata compatible |
88
+ | **Reviews** | Filter by stars, reply (350-char validated), auto-paginate, export to CSV |
89
+ | **Vitals** | Crash rates, ANR, startup, rendering, battery, memory — with CI threshold gates |
90
+ | **Status** | Releases + vitals + reviews in one command, `--watch`, `--since-last` diff |
86
91
  | **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 |
92
+ | **Subscriptions** | Base plans, offers, pricing, batch operations, RTDN notification decoding |
93
+ | **IAP / OTP** | One-time products, purchase options, batch get/update/delete |
94
+ | **Purchases** | Verify, acknowledge, cancel, refund, voided (with `--type` subscription filter) |
95
+ | **Reports** | Financial and stats report downloads |
91
96
  | **Testers** | Add, remove, import from CSV |
92
97
  | **Users** | Invite, update, remove, manage per-app grants |
98
+ | **Doctor** | 20 automated setup checks — config, auth, connectivity, app access, key age |
99
+ | **Anomalies** | Auto-detect vitals quality spikes from Reporting API |
100
+ | **More** | Init, diff, changelog, quota, train, cache, feedback, enterprise, games |
101
+
102
+ ## Exit Codes
103
+
104
+ | Code | Meaning |
105
+ | ---- | ------------------------------------- |
106
+ | `0` | Success |
107
+ | `1` | General error |
108
+ | `2` | Usage error (bad arguments) |
109
+ | `3` | Authentication error |
110
+ | `4` | API error (rate limit, permission) |
111
+ | `5` | Network error |
112
+ | `6` | Threshold breach (vitals CI alerting) |
93
113
 
94
114
  ## CI/CD Ready
95
115
 
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`.
116
+ JSON output when piped. Formatted tables in your terminal. Semantic exit codes (0-6) your CI can react to. Every write operation supports `--dry-run`.
97
117
 
98
118
  ```yaml
99
119
  - name: Upload
@@ -102,6 +122,7 @@ JSON output when piped. Formatted tables in your terminal. Semantic exit codes (
102
122
  GPC_APP: com.example.myapp
103
123
  run: |
104
124
  npm install -g @gpc-cli/cli
125
+ gpc preflight app.aab --fail-on error
105
126
  gpc releases upload app.aab --track internal
106
127
  ```
107
128
 
@@ -2,6 +2,9 @@
2
2
  import {
3
3
  resolvePackageName
4
4
  } from "./chunk-NQH4G7BI.js";
5
+ import {
6
+ yellow
7
+ } from "./chunk-FAN4ZITI.js";
5
8
  import {
6
9
  getOutputFormat
7
10
  } from "./chunk-ELXAK7GI.js";
@@ -9,7 +12,7 @@ import {
9
12
  // src/commands/anomalies.ts
10
13
  import { loadConfig } from "@gpc-cli/config";
11
14
  import { resolveAuth } from "@gpc-cli/auth";
12
- import { createReportingClient } from "@gpc-cli/api";
15
+ import { createReportingClient, PlayApiError } from "@gpc-cli/api";
13
16
  import { getVitalsAnomalies, formatOutput } from "@gpc-cli/core";
14
17
  async function getReportingClient(config) {
15
18
  const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
@@ -22,7 +25,21 @@ function registerAnomaliesCommands(program) {
22
25
  const packageName = resolvePackageName(program.opts()["app"], config);
23
26
  const reporting = await getReportingClient(config);
24
27
  const format = getOutputFormat(program, config);
25
- const result = await getVitalsAnomalies(reporting, packageName);
28
+ let result;
29
+ try {
30
+ result = await getVitalsAnomalies(reporting, packageName);
31
+ } catch (err) {
32
+ if (err instanceof PlayApiError && err.statusCode === 403) {
33
+ if (format === "json") {
34
+ console.log(formatOutput({ anomalies: [], message: "Reporting API not enabled or insufficient permissions" }, format));
35
+ } else {
36
+ console.log(`${yellow("\u26A0")} No anomaly data available. The Reporting API may not be enabled for this project.`);
37
+ console.log(` Enable it at: https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com`);
38
+ }
39
+ return;
40
+ }
41
+ throw err;
42
+ }
26
43
  const items = result["anomalies"];
27
44
  if (format !== "json") {
28
45
  if (!items || items.length === 0) {
@@ -46,4 +63,4 @@ function registerAnomaliesCommands(program) {
46
63
  export {
47
64
  registerAnomaliesCommands
48
65
  };
49
- //# sourceMappingURL=anomalies-UDE4NGHJ.js.map
66
+ //# sourceMappingURL=anomalies-V3AFS4LD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/anomalies.ts"],"sourcesContent":["import { resolvePackageName } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createReportingClient, PlayApiError } from \"@gpc-cli/api\";\nimport { getVitalsAnomalies, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { yellow } from \"../colors.js\";\n\n\nasync function getReportingClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createReportingClient({ auth });\n}\n\nexport function registerAnomaliesCommands(program: Command): void {\n const anomalies = program.command(\"anomalies\").description(\"Detect and list vitals anomalies\");\n\n anomalies\n .command(\"list\")\n .description(\"List detected vitals anomalies\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = getOutputFormat(program, config);\n\n let result;\n try {\n result = await getVitalsAnomalies(reporting, packageName);\n } catch (err) {\n if (err instanceof PlayApiError && err.statusCode === 403) {\n if (format === \"json\") {\n console.log(formatOutput({ anomalies: [], message: \"Reporting API not enabled or insufficient permissions\" }, format));\n } else {\n console.log(`${yellow(\"⚠\")} No anomaly data available. The Reporting API may not be enabled for this project.`);\n console.log(` Enable it at: https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com`);\n }\n return;\n }\n throw err;\n }\n const items = (result as unknown as Record<string, unknown>)[\"anomalies\"] as\n | unknown[]\n | undefined;\n\n if (format !== \"json\") {\n if (!items || items.length === 0) {\n console.log(\"No anomalies detected.\");\n return;\n }\n const rows = items.map((item) => {\n const a = item as Record<string, unknown>;\n return {\n name: String(a[\"name\"] ?? \"-\"),\n metricSet: String(a[\"metricSet\"] ?? \"-\"),\n aggregationPeriod: String(a[\"aggregationPeriod\"] ?? \"-\"),\n };\n });\n console.log(formatOutput(rows, format));\n } else {\n console.log(formatOutput(result, format));\n }\n });\n}\n"],"mappings":";;;;;;;;;;;;AAGA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB,oBAAoB;AACpD,SAAS,oBAAoB,oBAAoB;AAKjD,eAAe,mBAAmB,QAAmB;AACnD,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,sBAAsB,EAAE,KAAK,CAAC;AACvC;AAEO,SAAS,0BAA0B,SAAwB;AAChE,QAAM,YAAY,QAAQ,QAAQ,WAAW,EAAE,YAAY,kCAAkC;AAE7F,YACG,QAAQ,MAAM,EACd,YAAY,gCAAgC,EAC5C,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,YAAY,MAAM,mBAAmB,MAAM;AACjD,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,mBAAmB,WAAW,WAAW;AAAA,IAC1D,SAAS,KAAK;AACZ,UAAI,eAAe,gBAAgB,IAAI,eAAe,KAAK;AACzD,YAAI,WAAW,QAAQ;AACrB,kBAAQ,IAAI,aAAa,EAAE,WAAW,CAAC,GAAG,SAAS,wDAAwD,GAAG,MAAM,CAAC;AAAA,QACvH,OAAO;AACL,kBAAQ,IAAI,GAAG,OAAO,QAAG,CAAC,oFAAoF;AAC9G,kBAAQ,IAAI,qGAAqG;AAAA,QACnH;AACA;AAAA,MACF;AACA,YAAM;AAAA,IACR;AACA,UAAM,QAAS,OAA8C,WAAW;AAIxE,QAAI,WAAW,QAAQ;AACrB,UAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,gBAAQ,IAAI,wBAAwB;AACpC;AAAA,MACF;AACA,YAAM,OAAO,MAAM,IAAI,CAAC,SAAS;AAC/B,cAAM,IAAI;AACV,eAAO;AAAA,UACL,MAAM,OAAO,EAAE,MAAM,KAAK,GAAG;AAAA,UAC7B,WAAW,OAAO,EAAE,WAAW,KAAK,GAAG;AAAA,UACvC,mBAAmB,OAAO,EAAE,mBAAmB,KAAK,GAAG;AAAA,QACzD;AAAA,MACF,CAAC;AACD,cAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AAAA,IACxC,OAAO;AACL,cAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,IAC1C;AAAA,EACF,CAAC;AACL;","names":[]}
@@ -17,7 +17,8 @@ import {
17
17
  listAuditEvents,
18
18
  searchAuditEvents,
19
19
  clearAuditLog,
20
- formatOutput
20
+ formatOutput,
21
+ maybePaginate
21
22
  } from "@gpc-cli/core";
22
23
  function formatAuditTimestamp(iso) {
23
24
  const date = new Date(iso);
@@ -72,9 +73,9 @@ function registerAuditCommands(program) {
72
73
  success: e.success !== void 0 ? String(e.success) : "-",
73
74
  durationMs: e.durationMs ?? "-"
74
75
  }));
75
- console.log(formatOutput(rows, format));
76
+ await maybePaginate(formatOutput(rows, format));
76
77
  } else {
77
- console.log(formatOutput(events, format));
78
+ await maybePaginate(formatOutput(events, format));
78
79
  }
79
80
  });
80
81
  audit.command("search <query>").description("Search audit events by keyword").action(async (query) => {
@@ -121,4 +122,4 @@ function registerAuditCommands(program) {
121
122
  export {
122
123
  registerAuditCommands
123
124
  };
124
- //# sourceMappingURL=audit-JASSHRWN.js.map
125
+ //# sourceMappingURL=audit-VTWXTXC6.js.map
@@ -0,0 +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 maybePaginate,\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)\n 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 = [\n \"Jan\",\n \"Feb\",\n \"Mar\",\n \"Apr\",\n \"May\",\n \"Jun\",\n \"Jul\",\n \"Aug\",\n \"Sep\",\n \"Oct\",\n \"Nov\",\n \"Dec\",\n ];\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 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 await maybePaginate(formatOutput(rows, format));\n } else {\n await maybePaginate(formatOutput(events, format));\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 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 });\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 const result = await clearAuditLog({\n before: options.before,\n dryRun,\n });\n if (dryRun) {\n console.log(\n `[dry-run] Would delete ${result.deleted} entries, ${result.remaining} would remain.`,\n );\n } else {\n console.log(`Deleted ${result.deleted} entries. ${result.remaining} remaining.`);\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -242,30 +242,91 @@ function registerAuthCommands(program) {
242
242
  const token = await authClient.getAccessToken();
243
243
  console.log(token);
244
244
  });
245
- auth.command("setup-gcp").description("Step-by-step guide to create a Google Cloud service account").action(() => {
245
+ auth.command("setup-gcp").description("Step-by-step guide to create a Google Cloud service account").option("--key <path>", "Path to an already-downloaded service account JSON key").action(async (options) => {
246
+ const { existsSync, readFileSync } = await import("fs");
247
+ const { resolve: resolve2 } = await import("path");
246
248
  console.log("\nGPC \u2014 Google Cloud Service Account Setup");
247
- 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");
248
- console.log("\nStep 1: Open the Google Cloud Console");
249
- console.log(" https://console.cloud.google.com/iam-admin/serviceaccounts");
250
- console.log("\nStep 2: Create a service account");
251
- console.log(" \u2022 Click 'Create Service Account'");
252
- console.log(" \u2022 Name it: gpc-deploy (or any name you like)");
253
- console.log(" \u2022 Description: GPC Google Play Console access");
254
- console.log("\nStep 3: Grant roles");
255
- console.log(" No GCP roles needed \u2014 permissions are managed in Google Play Console.");
256
- console.log("\nStep 4: Download the JSON key");
257
- console.log(" \u2022 Click your new service account \u2192 Keys \u2192 Add Key \u2192 Create new key \u2192 JSON");
258
- console.log(" \u2022 Save as: ~/gpc-service-account.json");
259
- console.log("\nStep 5: Add to Google Play Console");
260
- console.log(" https://play.google.com/console/developers");
261
- console.log(" \u2022 Users and Permissions \u2192 Invite new users");
262
- console.log(" \u2022 Paste the service account email (ends with @...gserviceaccount.com)");
263
- console.log(" \u2022 Grant: Release manager + View app info + Reply to reviews");
264
- console.log("\nStep 6: Authenticate");
265
- console.log(" gpc auth login --service-account ~/gpc-service-account.json");
266
- console.log("\nStep 7: Verify");
267
- console.log(" gpc doctor");
268
- console.log("\nSee full docs: https://yasserstudio.github.io/gpc/guide/authentication");
249
+ console.log("\u2550".repeat(50));
250
+ let keyPath = options.key;
251
+ if (!keyPath) {
252
+ console.log("\nStep 1: Open the Google Cloud Console");
253
+ console.log(" https://console.cloud.google.com/iam-admin/serviceaccounts");
254
+ console.log("\nStep 2: Create a service account");
255
+ console.log(" \u2022 Click 'Create Service Account'");
256
+ console.log(" \u2022 Name it: gpc-deploy (or any name you like)");
257
+ console.log(" \u2022 Description: GPC Google Play Console access");
258
+ console.log("\nStep 3: Grant roles");
259
+ console.log(" No GCP roles needed \u2014 permissions are managed in Google Play Console.");
260
+ console.log("\nStep 4: Download the JSON key");
261
+ console.log(" \u2022 Click your new service account \u2192 Keys \u2192 Add Key \u2192 Create new key \u2192 JSON");
262
+ console.log(" \u2022 Save as: ~/gpc-service-account.json");
263
+ console.log("\nStep 5: Add to Google Play Console");
264
+ console.log(" https://play.google.com/console/developers");
265
+ console.log(" \u2022 Users and Permissions \u2192 Invite new users");
266
+ console.log(" \u2022 Paste the service account email (ends with @...gserviceaccount.com)");
267
+ console.log(" \u2022 Grant: Release manager + View app info + Reply to reviews");
268
+ const commonPaths = [
269
+ "~/gpc-service-account.json",
270
+ "./service-account.json",
271
+ "./gpc-service-account.json",
272
+ "~/.config/gpc/service-account.json"
273
+ ].map((p) => resolve2(p.replace("~", process.env["HOME"] || "")));
274
+ for (const p of commonPaths) {
275
+ if (existsSync(p)) {
276
+ console.log(`
277
+ \u2713 Found key file: ${p}`);
278
+ keyPath = p;
279
+ break;
280
+ }
281
+ }
282
+ if (!keyPath) {
283
+ console.log("\nOnce you've downloaded the key, run:");
284
+ console.log(" gpc auth setup-gcp --key <path/to/key.json>");
285
+ console.log("\nOr authenticate directly:");
286
+ console.log(" gpc auth login --service-account <path/to/key.json>");
287
+ console.log("\nSee full docs: https://yasserstudio.github.io/gpc/guide/authentication");
288
+ return;
289
+ }
290
+ }
291
+ const absPath = resolve2(keyPath.replace("~", process.env["HOME"] || ""));
292
+ if (!existsSync(absPath)) {
293
+ console.error(`
294
+ \u2717 File not found: ${absPath}`);
295
+ return;
296
+ }
297
+ try {
298
+ const content = JSON.parse(readFileSync(absPath, "utf-8"));
299
+ if (content.type !== "service_account") {
300
+ console.error(`
301
+ \u2717 Not a service account key (type: ${content.type})`);
302
+ return;
303
+ }
304
+ console.log(`
305
+ \u2713 Valid service account key`);
306
+ console.log(` Email: ${content.client_email}`);
307
+ console.log(` Project: ${content.project_id}`);
308
+ } catch {
309
+ console.error(`
310
+ \u2717 Invalid JSON file: ${absPath}`);
311
+ return;
312
+ }
313
+ console.log(`
314
+ Step 6: Authenticating...`);
315
+ try {
316
+ const auth2 = await resolveAuth({ serviceAccountPath: absPath });
317
+ await auth2.getAccessToken();
318
+ const { setConfigValue: setConfigValue2 } = await import("@gpc-cli/config");
319
+ await setConfigValue2("auth.serviceAccount", absPath);
320
+ console.log(`\u2713 Authenticated and saved to config`);
321
+ } catch (err) {
322
+ console.error(`\u2717 Authentication failed: ${err instanceof Error ? err.message : String(err)}`);
323
+ console.log(`
324
+ Try manually: gpc auth login --service-account ${absPath}`);
325
+ return;
326
+ }
327
+ console.log(`
328
+ Step 7: Verifying setup...`);
329
+ console.log(` Run: gpc doctor`);
269
330
  });
270
331
  auth.command("profiles").description("List configured profiles").action(async () => {
271
332
  const { listProfiles } = await import("@gpc-cli/config");
@@ -288,4 +349,4 @@ function registerAuthCommands(program) {
288
349
  export {
289
350
  registerAuthCommands
290
351
  };
291
- //# sourceMappingURL=auth-OTA3SV3J.js.map
352
+ //# sourceMappingURL=auth-BA4FE2PO.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 { resolve } from \"node:path\";\nimport { resolveAuth, loadServiceAccountKey, clearTokenCache, AuthError } from \"@gpc-cli/auth\";\nimport { loadConfig, getCacheDir, deleteConfigValue, setConfigValue } from \"@gpc-cli/config\";\nimport { formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function askQuestion(\n rl: ReturnType<typeof createInterface>,\n question: string,\n): Promise<string> {\n return new Promise((resolve) => {\n rl.question(question, (answer) => resolve(answer.trim()));\n });\n}\n\n/** Resolve a path to absolute (prevents CWD-dependent config). */\nfunction toAbsolutePath(pathStr: string): string {\n return resolve(pathStr);\n}\n\n/** Verify that the saved credentials can acquire a token. */\nasync function verifyToken(serviceAccountPath?: string): Promise<{ email: string; ok: boolean; error?: string }> {\n try {\n const client = await resolveAuth({ serviceAccountPath });\n const email = client.getClientEmail();\n await client.getAccessToken();\n return { email, ok: true };\n } catch (err) {\n const email = \"unknown\";\n const msg = err instanceof Error ? err.message : String(err);\n return { email, ok: false, error: msg };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Interactive login wizard\n// ---------------------------------------------------------------------------\n\nasync function runLoginWizard(program: Command): Promise<void> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n\n try {\n console.log(\"\\nGPC Authentication Setup\");\n 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\");\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 client = await resolveAuth();\n const email = client.getClientEmail();\n // Verify token works\n await client.getAccessToken();\n outputLoginResult(program, { account: email, method: \"adc\", verified: true });\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) {\n console.log(\" Path is required.\");\n continue;\n }\n try {\n await access(input);\n saPath = toAbsolutePath(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(\n rl,\n \"Default package name (optional, e.g. com.example.app): \",\n );\n\n // Apply settings\n const key = await loadServiceAccountKey(saPath);\n\n if (profileName) {\n const { setProfileConfig } = await import(\"@gpc-cli/config\");\n await setProfileConfig(profileName, {\n auth: { serviceAccount: saPath },\n ...(packageName && { app: packageName }),\n });\n } else {\n await setConfigValue(\"auth.serviceAccount\", saPath);\n if (packageName) await setConfigValue(\"app\", packageName);\n }\n\n // Verify token\n const verification = await verifyToken(saPath);\n\n outputLoginResult(program, {\n account: key.client_email,\n project: key.project_id,\n method: \"service-account\",\n profile: profileName || undefined,\n verified: verification.ok,\n verifyError: verification.error,\n });\n } finally {\n rl.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Structured login output\n// ---------------------------------------------------------------------------\n\ninterface LoginResult {\n account: string;\n project?: string;\n method: string;\n profile?: string;\n verified: boolean;\n verifyError?: string;\n}\n\nfunction outputLoginResult(program: Command, result: LoginResult): void {\n const parentOpts = program.opts() ?? {};\n const jsonMode = !!(parentOpts[\"json\"] || parentOpts[\"output\"] === \"json\");\n\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n account: result.account,\n project: result.project,\n method: result.method,\n profile: result.profile,\n verified: result.verified,\n ...(result.verifyError && { verifyError: result.verifyError }),\n }),\n );\n return;\n }\n\n if (result.profile) {\n console.log(`\\nProfile \"${result.profile}\" configured with ${result.account}`);\n } else if (result.method === \"adc\") {\n console.log(`\\nAuthenticated via Application Default Credentials`);\n console.log(`Account: ${result.account}`);\n } else {\n console.log(`\\nAuthenticated as ${result.account}`);\n }\n if (result.project) console.log(`Project: ${result.project}`);\n\n if (result.verified) {\n console.log(\"Verified: token acquired successfully\");\n } else if (result.verifyError) {\n console.log(`Warning: token verification failed: ${result.verifyError}`);\n console.log(\"Credentials saved, but check your setup with: gpc doctor\");\n }\n\n if (!result.verifyError) {\n console.log(\"\\nRun 'gpc doctor' to verify your full setup.\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Command registration\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 if (options.serviceAccount) {\n const absolutePath = toAbsolutePath(options.serviceAccount);\n const key = await loadServiceAccountKey(absolutePath);\n\n if (options.profile) {\n const { setProfileConfig } = await import(\"@gpc-cli/config\");\n await setProfileConfig(options.profile, {\n auth: { serviceAccount: absolutePath },\n });\n } else {\n await setConfigValue(\"auth.serviceAccount\", absolutePath);\n }\n\n // Verify token works\n const verification = await verifyToken(absolutePath);\n\n outputLoginResult(program, {\n account: key.client_email,\n project: key.project_id,\n method: \"service-account\",\n profile: options.profile,\n verified: verification.ok,\n verifyError: verification.error,\n });\n } else if (options.adc) {\n const client = await resolveAuth();\n const email = client.getClientEmail();\n await client.getAccessToken();\n outputLoginResult(program, { account: email, method: \"adc\", verified: true });\n } else {\n // Interactive wizard when no flags provided and in interactive mode\n const opts = program.opts();\n const interactive =\n opts[\"interactive\"] !== false && opts[\"ci\"] !== true && process.stdin.isTTY;\n if (interactive) {\n await runLoginWizard(program);\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 });\n\n auth\n .command(\"status\")\n .description(\"Show current authentication status\")\n .action(async () => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n try {\n const client = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\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 data = {\n authenticated: false,\n error: error.message,\n suggestion: error.suggestion,\n };\n console.log(formatOutput(data, format));\n }\n throw error; // Let error handler set exit code 3\n }\n });\n\n auth\n .command(\"logout\")\n .description(\"Clear stored credentials and token cache\")\n .option(\"--profile <name>\", \"Clear credentials for a specific profile\")\n .action(async (options: { profile?: string }) => {\n if (options.profile) {\n const { deleteProfile } = await import(\"@gpc-cli/config\");\n const deleted = await deleteProfile(options.profile);\n if (deleted) {\n console.log(`Profile \"${options.profile}\" removed.`);\n } else {\n console.log(`Profile \"${options.profile}\" not found.`);\n }\n } else {\n await deleteConfigValue(\"auth.serviceAccount\");\n console.log(\"Credentials cleared.\");\n }\n await clearTokenCache(getCacheDir());\n console.log(\"Token cache cleared.\");\n });\n\n auth\n .command(\"whoami\")\n .description(\"Show current authenticated identity\")\n .action(async () => {\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 });\n\n auth\n .command(\"switch <profile>\")\n .description(\"Switch to a named profile\")\n .action(async (profile: string) => {\n // loadConfig with the profile will throw ConfigError if profile doesn't exist\n const config = await loadConfig({ profile });\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 });\n\n auth\n .command(\"token\")\n .description(\"Print the current access token (useful for manual API calls)\")\n .action(async () => {\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 });\n\n auth\n .command(\"setup-gcp\")\n .description(\"Step-by-step guide to create a Google Cloud service account\")\n .option(\"--key <path>\", \"Path to an already-downloaded service account JSON key\")\n .action(async (options: { key?: string }) => {\n const { existsSync, readFileSync } = await import(\"node:fs\");\n const { resolve } = await import(\"node:path\");\n\n console.log(\"\\nGPC \\u2014 Google Cloud Service Account Setup\");\n console.log(\"\\u2550\".repeat(50));\n\n // If key path provided or user already has one, skip to validation\n let keyPath = options.key;\n\n if (!keyPath) {\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(\" \\u2022 Click 'Create Service Account'\");\n console.log(\" \\u2022 Name it: gpc-deploy (or any name you like)\");\n console.log(\" \\u2022 Description: GPC Google Play Console access\");\n console.log(\"\\nStep 3: Grant roles\");\n console.log(\" No GCP roles needed \\u2014 permissions are managed in Google Play Console.\");\n console.log(\"\\nStep 4: Download the JSON key\");\n console.log(\" \\u2022 Click your new service account \\u2192 Keys \\u2192 Add Key \\u2192 Create new key \\u2192 JSON\");\n console.log(\" \\u2022 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(\" \\u2022 Users and Permissions \\u2192 Invite new users\");\n console.log(\" \\u2022 Paste the service account email (ends with @...gserviceaccount.com)\");\n console.log(\" \\u2022 Grant: Release manager + View app info + Reply to reviews\");\n\n // Try to auto-detect a key file\n const commonPaths = [\n \"~/gpc-service-account.json\",\n \"./service-account.json\",\n \"./gpc-service-account.json\",\n \"~/.config/gpc/service-account.json\",\n ].map((p) => resolve(p.replace(\"~\", process.env[\"HOME\"] || \"\")));\n\n for (const p of commonPaths) {\n if (existsSync(p)) {\n console.log(`\\n\\u2713 Found key file: ${p}`);\n keyPath = p;\n break;\n }\n }\n\n if (!keyPath) {\n console.log(\"\\nOnce you've downloaded the key, run:\");\n console.log(\" gpc auth setup-gcp --key <path/to/key.json>\");\n console.log(\"\\nOr authenticate directly:\");\n console.log(\" gpc auth login --service-account <path/to/key.json>\");\n console.log(\"\\nSee full docs: https://yasserstudio.github.io/gpc/guide/authentication\");\n return;\n }\n }\n\n // Validate the key file\n const absPath = resolve(keyPath.replace(\"~\", process.env[\"HOME\"] || \"\"));\n if (!existsSync(absPath)) {\n console.error(`\\n\\u2717 File not found: ${absPath}`);\n return;\n }\n\n try {\n const content = JSON.parse(readFileSync(absPath, \"utf-8\"));\n if (content.type !== \"service_account\") {\n console.error(`\\n\\u2717 Not a service account key (type: ${content.type})`);\n return;\n }\n console.log(`\\n\\u2713 Valid service account key`);\n console.log(` Email: ${content.client_email}`);\n console.log(` Project: ${content.project_id}`);\n } catch {\n console.error(`\\n\\u2717 Invalid JSON file: ${absPath}`);\n return;\n }\n\n // Auto-login\n console.log(`\\nStep 6: Authenticating...`);\n try {\n const auth = await resolveAuth({ serviceAccountPath: absPath });\n await auth.getAccessToken();\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"auth.serviceAccount\", absPath);\n console.log(`\\u2713 Authenticated and saved to config`);\n } catch (err) {\n console.error(`\\u2717 Authentication failed: ${err instanceof Error ? err.message : String(err)}`);\n console.log(`\\nTry manually: gpc auth login --service-account ${absPath}`);\n return;\n }\n\n // Auto-run doctor\n console.log(`\\nStep 7: Verifying setup...`);\n console.log(` Run: gpc doctor`);\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":["resolve","auth","setConfigValue"]}
package/dist/bin.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createProgram,
4
4
  handleCliError,
5
5
  loadPlugins
6
- } from "./chunk-6OWN6S6X.js";
6
+ } from "./chunk-XBH2V2XK.js";
7
7
  import {
8
8
  checkForUpdate,
9
9
  formatUpdateNotification
@@ -46,7 +46,7 @@ if (!_isJsonMode && !_isQuiet && !_isSetupCommand && !existsSync(getUserConfigPa
46
46
  }
47
47
  await setupNetworking();
48
48
  initAudit(getConfigDir());
49
- var currentVersion = "0.9.45";
49
+ var currentVersion = "0.9.48";
50
50
  var isUpdateCommand = process.argv[2] === "update";
51
51
  var updateCheckPromise = isUpdateCommand ? Promise.resolve(null) : checkForUpdate(currentVersion);
52
52
  if (process.argv.includes("--ci")) {
@@ -8,12 +8,12 @@ import { fetchChangelog, formatChangelogEntry } from "@gpc-cli/core";
8
8
  import { formatOutput } from "@gpc-cli/core";
9
9
  import { loadConfig } from "@gpc-cli/config";
10
10
  function registerChangelogCommand(program) {
11
- program.command("changelog").description("Show release history").option("-n, --limit <count>", "Number of releases to show", parseInt, 5).option("--version <tag>", "Show a specific version (e.g., v0.9.43)").option("--all", "Show all releases").action(async (opts) => {
11
+ program.command("changelog").description("Show release history").option("-n, --limit <count>", "Number of releases to show", parseInt, 5).option("--tag <tag>", "Show a specific release (e.g., v0.9.43)").option("--all", "Show all releases").action(async (opts) => {
12
12
  const config = await loadConfig();
13
13
  const format = getOutputFormat(program, config);
14
14
  const entries = await fetchChangelog({
15
15
  limit: opts.all ? 100 : opts.limit,
16
- version: opts.version
16
+ version: opts.tag
17
17
  });
18
18
  if (entries.length === 0) {
19
19
  console.log("No releases found.");
@@ -23,7 +23,7 @@ function registerChangelogCommand(program) {
23
23
  console.log(formatOutput(entries, "json"));
24
24
  return;
25
25
  }
26
- if (opts.version || entries.length === 1) {
26
+ if (opts.tag || entries.length === 1) {
27
27
  console.log(formatChangelogEntry(entries[0]));
28
28
  return;
29
29
  }
@@ -38,11 +38,11 @@ function registerChangelogCommand(program) {
38
38
  }
39
39
  console.log("");
40
40
  console.log(
41
- `Showing ${entries.length} releases. Use --version <tag> for details, or --all for full history.`
41
+ `Showing ${entries.length} releases. Use --tag <tag> for details, or --all for full history.`
42
42
  );
43
43
  });
44
44
  }
45
45
  export {
46
46
  registerChangelogCommand
47
47
  };
48
- //# sourceMappingURL=changelog-7COFZO7Q.js.map
48
+ //# sourceMappingURL=changelog-QLDFG5TV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/changelog.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { fetchChangelog, formatChangelogEntry } from \"@gpc-cli/core\";\nimport { formatOutput } from \"@gpc-cli/core\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { getOutputFormat } from \"../format.js\";\n\nexport function registerChangelogCommand(program: Command): void {\n program\n .command(\"changelog\")\n .description(\"Show release history\")\n .option(\"-n, --limit <count>\", \"Number of releases to show\", parseInt, 5)\n .option(\"--tag <tag>\", \"Show a specific release (e.g., v0.9.43)\")\n .option(\"--all\", \"Show all releases\")\n .action(async (opts: { limit: number; tag?: string; all?: boolean }) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n\n const entries = await fetchChangelog({\n limit: opts.all ? 100 : opts.limit,\n version: opts.tag,\n });\n\n if (entries.length === 0) {\n console.log(\"No releases found.\");\n return;\n }\n\n if (format === \"json\") {\n console.log(formatOutput(entries, \"json\"));\n return;\n }\n\n // Single version — show full details\n if (opts.tag || entries.length === 1) {\n console.log(formatChangelogEntry(entries[0]!));\n return;\n }\n\n // Multiple versions — table summary\n const header = \"VERSION DATE TITLE\";\n const separator = \"─\".repeat(header.length);\n console.log(header);\n console.log(separator);\n for (const entry of entries) {\n const version = entry.version.padEnd(12);\n const date = entry.date.padEnd(12);\n console.log(`${version} ${date} ${entry.title}`);\n }\n console.log(\"\");\n console.log(\n `Showing ${entries.length} releases. Use --tag <tag> for details, or --all for full history.`,\n );\n });\n}\n"],"mappings":";;;;;;AACA,SAAS,gBAAgB,4BAA4B;AACrD,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAGpB,SAAS,yBAAyB,SAAwB;AAC/D,UACG,QAAQ,WAAW,EACnB,YAAY,sBAAsB,EAClC,OAAO,uBAAuB,8BAA8B,UAAU,CAAC,EACvE,OAAO,eAAe,yCAAyC,EAC/D,OAAO,SAAS,mBAAmB,EACnC,OAAO,OAAO,SAAyD;AACtE,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,UAAM,UAAU,MAAM,eAAe;AAAA,MACnC,OAAO,KAAK,MAAM,MAAM,KAAK;AAAA,MAC7B,SAAS,KAAK;AAAA,IAChB,CAAC;AAED,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,IAAI,oBAAoB;AAChC;AAAA,IACF;AAEA,QAAI,WAAW,QAAQ;AACrB,cAAQ,IAAI,aAAa,SAAS,MAAM,CAAC;AACzC;AAAA,IACF;AAGA,QAAI,KAAK,OAAO,QAAQ,WAAW,GAAG;AACpC,cAAQ,IAAI,qBAAqB,QAAQ,CAAC,CAAE,CAAC;AAC7C;AAAA,IACF;AAGA,UAAM,SAAS;AACf,UAAM,YAAY,SAAI,OAAO,OAAO,MAAM;AAC1C,YAAQ,IAAI,MAAM;AAClB,YAAQ,IAAI,SAAS;AACrB,eAAW,SAAS,SAAS;AAC3B,YAAM,UAAU,MAAM,QAAQ,OAAO,EAAE;AACvC,YAAM,OAAO,MAAM,KAAK,OAAO,EAAE;AACjC,cAAQ,IAAI,GAAG,OAAO,IAAI,IAAI,IAAI,MAAM,KAAK,EAAE;AAAA,IACjD;AACA,YAAQ,IAAI,EAAE;AACd,YAAQ;AAAA,MACN,WAAW,QAAQ,MAAM;AAAA,IAC3B;AAAA,EACF,CAAC;AACL;","names":[]}
@@ -67,25 +67,25 @@ function registerPluginCommands(program, manager) {
67
67
  import { Command } from "commander";
68
68
  async function createProgram(pluginManager) {
69
69
  const program = new Command();
70
- program.name("gpc").description("GPC \u2014 Google Play Console CLI").version("0.9.45", "-V, --version").option("-o, --output <format>", "Output format: table, json, yaml, markdown, junit").option("-v, --verbose", "Enable debug logging").option("-q, --quiet", "Suppress non-essential output").option("-a, --app <package>", "App package name").option("-p, --profile <name>", "Auth profile name").option("--no-color", "Disable colored output").option("--no-interactive", "Disable interactive prompts").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Preview changes without executing").option("--notify [target]", "Send webhook notification on completion (slack, discord, custom)").option("--ci", "Force CI mode (JSON output, no prompts, strict exit codes)").option("-j, --json", "Shorthand for --output json").option("--apps <csv>", "Comma-separated package names for multi-app operations").showSuggestionAfterError(false);
70
+ program.name("gpc").description("GPC \u2014 Google Play Console CLI").version("0.9.48", "-V, --version").option("-o, --output <format>", "Output format: table, json, yaml, markdown, junit").option("-v, --verbose", "Enable debug logging").option("-q, --quiet", "Suppress non-essential output").option("-a, --app <package>", "App package name").option("-p, --profile <name>", "Auth profile name").option("--no-color", "Disable colored output").option("--no-interactive", "Disable interactive prompts").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Preview changes without executing").option("--notify [target]", "Send webhook notification on completion (slack, discord, custom)").option("--ci", "Force CI mode (JSON output, no prompts, strict exit codes)").option("-j, --json", "Shorthand for --output json").option("--apps <csv>", "Comma-separated package names for multi-app operations").showSuggestionAfterError(false);
71
71
  const commandLoaders = {
72
72
  auth: async () => {
73
- (await import("./auth-OTA3SV3J.js")).registerAuthCommands(program);
73
+ (await import("./auth-BA4FE2PO.js")).registerAuthCommands(program);
74
74
  },
75
75
  config: async () => {
76
- (await import("./config-2FTCYEGD.js")).registerConfigCommands(program);
76
+ (await import("./config-NQQF4522.js")).registerConfigCommands(program);
77
77
  },
78
78
  doctor: async () => {
79
- (await import("./doctor-H4X7Q57B.js")).registerDoctorCommand(program);
79
+ (await import("./doctor-KGYUWHL5.js")).registerDoctorCommand(program);
80
80
  },
81
81
  update: async () => {
82
- (await import("./update-OMALGIBR.js")).registerUpdateCommand(program);
82
+ (await import("./update-QUQ7N7QJ.js")).registerUpdateCommand(program);
83
83
  },
84
84
  docs: async () => {
85
85
  (await import("./docs-4D2SJ4LY.js")).registerDocsCommand(program);
86
86
  },
87
87
  changelog: async () => {
88
- (await import("./changelog-7COFZO7Q.js")).registerChangelogCommand(program);
88
+ (await import("./changelog-QLDFG5TV.js")).registerChangelogCommand(program);
89
89
  },
90
90
  completion: async () => {
91
91
  (await import("./completion-BCHRJSAT.js")).registerCompletionCommand(program);
@@ -94,10 +94,10 @@ async function createProgram(pluginManager) {
94
94
  (await import("./apps-FKD3ZG5X.js")).registerAppsCommands(program);
95
95
  },
96
96
  releases: async () => {
97
- (await import("./releases-2I3WBULC.js")).registerReleasesCommands(program);
97
+ (await import("./releases-OUJ65774.js")).registerReleasesCommands(program);
98
98
  },
99
99
  tracks: async () => {
100
- (await import("./tracks-YHMO2A6B.js")).registerTracksCommands(program);
100
+ (await import("./tracks-DO7C5OSE.js")).registerTracksCommands(program);
101
101
  },
102
102
  status: async () => {
103
103
  (await import("./status-6LH5W4FU.js")).registerStatusCommand(program);
@@ -106,19 +106,19 @@ async function createProgram(pluginManager) {
106
106
  (await import("./listings-7SGQ4SRX.js")).registerListingsCommands(program);
107
107
  },
108
108
  reviews: async () => {
109
- (await import("./reviews-BCCXIQ6C.js")).registerReviewsCommands(program);
109
+ (await import("./reviews-YCBBM656.js")).registerReviewsCommands(program);
110
110
  },
111
111
  vitals: async () => {
112
- (await import("./vitals-C23L2Y2E.js")).registerVitalsCommands(program);
112
+ (await import("./vitals-PJEQUUAK.js")).registerVitalsCommands(program);
113
113
  },
114
114
  subscriptions: async () => {
115
- (await import("./subscriptions-DZP3Y7O7.js")).registerSubscriptionsCommands(program);
115
+ (await import("./subscriptions-LURZFPGJ.js")).registerSubscriptionsCommands(program);
116
116
  },
117
117
  iap: async () => {
118
118
  (await import("./iap-OUI5YYN4.js")).registerIapCommands(program);
119
119
  },
120
120
  purchases: async () => {
121
- (await import("./purchases-DAWTMXP6.js")).registerPurchasesCommands(program);
121
+ (await import("./purchases-UBFLNYZC.js")).registerPurchasesCommands(program);
122
122
  },
123
123
  pricing: async () => {
124
124
  (await import("./pricing-JJZFICFL.js")).registerPricingCommands(program);
@@ -168,25 +168,25 @@ async function createProgram(pluginManager) {
168
168
  (await import("./bundle-F7MUVC5J.js")).registerBundleCommands(program);
169
169
  },
170
170
  audit: async () => {
171
- (await import("./audit-JASSHRWN.js")).registerAuditCommands(program);
171
+ (await import("./audit-VTWXTXC6.js")).registerAuditCommands(program);
172
172
  },
173
173
  migrate: async () => {
174
174
  (await import("./migrate-ZQCJGQQS.js")).registerMigrateCommands(program);
175
175
  },
176
176
  anomalies: async () => {
177
- (await import("./anomalies-UDE4NGHJ.js")).registerAnomaliesCommands(program);
177
+ (await import("./anomalies-V3AFS4LD.js")).registerAnomaliesCommands(program);
178
178
  },
179
179
  "install-skills": async () => {
180
- (await import("./install-skills-6QDUXI5F.js")).registerInstallSkillsCommand(program);
180
+ (await import("./install-skills-JKPYZHYS.js")).registerInstallSkillsCommand(program);
181
181
  },
182
182
  version: async () => {
183
- (await import("./version-NCSNXNVN.js")).registerVersionCommand(program);
183
+ (await import("./version-WGE5Q7QH.js")).registerVersionCommand(program);
184
184
  },
185
185
  cache: async () => {
186
186
  (await import("./cache-XKPLZYEB.js")).registerCacheCommand(program);
187
187
  },
188
188
  feedback: async () => {
189
- (await import("./feedback-XP765TOO.js")).registerFeedbackCommand(program);
189
+ (await import("./feedback-RMLYHTAH.js")).registerFeedbackCommand(program);
190
190
  },
191
191
  quickstart: async () => {
192
192
  (await import("./quickstart-Z5Y3FYJU.js")).registerQuickstartCommand(program);
@@ -217,6 +217,9 @@ async function createProgram(pluginManager) {
217
217
  },
218
218
  plugins: async () => {
219
219
  registerPluginsCommand(program, pluginManager);
220
+ },
221
+ rtdn: async () => {
222
+ (await import("./rtdn-LID2B7XZ.js")).registerRtdnCommands(program);
220
223
  }
221
224
  };
222
225
  function levenshtein(a, b) {
@@ -451,4 +454,4 @@ export {
451
454
  createProgram,
452
455
  handleCliError
453
456
  };
454
- //# sourceMappingURL=chunk-6OWN6S6X.js.map
457
+ //# sourceMappingURL=chunk-XBH2V2XK.js.map