@gpc-cli/cli 0.1.2 → 0.1.4

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 (73) hide show
  1. package/README.md +96 -0
  2. package/dist/{apps-BBYNHB2H.js → apps-TZG5GEDW.js} +9 -7
  3. package/dist/apps-TZG5GEDW.js.map +1 -0
  4. package/dist/{auth-T7IDSMVX.js → auth-CIITFC3C.js} +4 -2
  5. package/dist/auth-CIITFC3C.js.map +1 -0
  6. package/dist/bin.js +1 -1
  7. package/dist/bin.js.map +1 -1
  8. package/dist/{chunk-IVVT73IP.js → chunk-22DW4R5W.js} +31 -26
  9. package/dist/chunk-22DW4R5W.js.map +1 -0
  10. package/dist/{chunk-4QV4WD3F.js → chunk-Q7KVGI46.js} +9 -7
  11. package/dist/chunk-Q7KVGI46.js.map +1 -0
  12. package/dist/{chunk-QMKZYXDJ.js → chunk-Y3QZDAKS.js} +2 -2
  13. package/dist/chunk-Y3QZDAKS.js.map +1 -0
  14. package/dist/{completion-U44CGHRH.js → completion-IHVLP7OK.js} +1 -1
  15. package/dist/completion-IHVLP7OK.js.map +1 -0
  16. package/dist/{config-K7UJKIXT.js → config-7QKUVNZZ.js} +8 -4
  17. package/dist/config-7QKUVNZZ.js.map +1 -0
  18. package/dist/{doctor-VDDUPTIM.js → doctor-KVP7PGZU.js} +5 -3
  19. package/dist/doctor-KVP7PGZU.js.map +1 -0
  20. package/dist/{iap-QIV4CXKZ.js → iap-Z365AMDD.js} +37 -25
  21. package/dist/iap-Z365AMDD.js.map +1 -0
  22. package/dist/index.js +1 -1
  23. package/dist/{listings-PF5FDXKQ.js → listings-U3T6NFVH.js} +128 -68
  24. package/dist/listings-U3T6NFVH.js.map +1 -0
  25. package/dist/{pricing-S4SB5FXJ.js → pricing-LXIRB4R7.js} +21 -15
  26. package/dist/pricing-LXIRB4R7.js.map +1 -0
  27. package/dist/{prompt-VP5LURRP.js → prompt-ASDQX6LZ.js} +2 -2
  28. package/dist/{publish-3BAIN4NQ.js → publish-HKOJVZ23.js} +27 -16
  29. package/dist/publish-HKOJVZ23.js.map +1 -0
  30. package/dist/{purchases-E6A2T5WQ.js → purchases-ZQ7FXEZQ.js} +84 -49
  31. package/dist/purchases-ZQ7FXEZQ.js.map +1 -0
  32. package/dist/{releases-464IMEEF.js → releases-IZJJYTNZ.js} +103 -51
  33. package/dist/releases-IZJJYTNZ.js.map +1 -0
  34. package/dist/{reports-3YAD4U4F.js → reports-43OVCCU3.js} +83 -29
  35. package/dist/reports-43OVCCU3.js.map +1 -0
  36. package/dist/{reviews-2CLM53E3.js → reviews-T3SRAZLW.js} +25 -16
  37. package/dist/reviews-T3SRAZLW.js.map +1 -0
  38. package/dist/{status-M7U3YNMU.js → status-TBPVS7YR.js} +5 -3
  39. package/dist/status-TBPVS7YR.js.map +1 -0
  40. package/dist/{subscriptions-PUHH4FBB.js → subscriptions-UJUX3ELS.js} +201 -130
  41. package/dist/subscriptions-UJUX3ELS.js.map +1 -0
  42. package/dist/{testers-WWZMLB7J.js → testers-YNOGFHUR.js} +81 -44
  43. package/dist/testers-YNOGFHUR.js.map +1 -0
  44. package/dist/{tracks-427E34S3.js → tracks-HMJ3F55N.js} +5 -3
  45. package/dist/tracks-HMJ3F55N.js.map +1 -0
  46. package/dist/{users-E5Y5HI6K.js → users-GRQTY6HY.js} +48 -28
  47. package/dist/users-GRQTY6HY.js.map +1 -0
  48. package/dist/{vitals-YMZMUPNA.js → vitals-VP2GKG3G.js} +23 -9
  49. package/dist/vitals-VP2GKG3G.js.map +1 -0
  50. package/package.json +6 -6
  51. package/dist/apps-BBYNHB2H.js.map +0 -1
  52. package/dist/auth-T7IDSMVX.js.map +0 -1
  53. package/dist/chunk-4QV4WD3F.js.map +0 -1
  54. package/dist/chunk-IVVT73IP.js.map +0 -1
  55. package/dist/chunk-QMKZYXDJ.js.map +0 -1
  56. package/dist/completion-U44CGHRH.js.map +0 -1
  57. package/dist/config-K7UJKIXT.js.map +0 -1
  58. package/dist/doctor-VDDUPTIM.js.map +0 -1
  59. package/dist/iap-QIV4CXKZ.js.map +0 -1
  60. package/dist/listings-PF5FDXKQ.js.map +0 -1
  61. package/dist/pricing-S4SB5FXJ.js.map +0 -1
  62. package/dist/publish-3BAIN4NQ.js.map +0 -1
  63. package/dist/purchases-E6A2T5WQ.js.map +0 -1
  64. package/dist/releases-464IMEEF.js.map +0 -1
  65. package/dist/reports-3YAD4U4F.js.map +0 -1
  66. package/dist/reviews-2CLM53E3.js.map +0 -1
  67. package/dist/status-M7U3YNMU.js.map +0 -1
  68. package/dist/subscriptions-PUHH4FBB.js.map +0 -1
  69. package/dist/testers-WWZMLB7J.js.map +0 -1
  70. package/dist/tracks-427E34S3.js.map +0 -1
  71. package/dist/users-E5Y5HI6K.js.map +0 -1
  72. package/dist/vitals-YMZMUPNA.js.map +0 -1
  73. /package/dist/{prompt-VP5LURRP.js.map → prompt-ASDQX6LZ.js.map} +0 -0
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  isDryRun,
4
4
  printDryRun
5
- } from "./chunk-QMKZYXDJ.js";
5
+ } from "./chunk-Y3QZDAKS.js";
6
6
  import {
7
7
  isInteractive,
8
8
  requireConfirm,
9
9
  requireOption
10
- } from "./chunk-4QV4WD3F.js";
10
+ } from "./chunk-Q7KVGI46.js";
11
11
 
12
12
  // src/commands/testers.ts
13
13
  import { loadConfig } from "@gpc-cli/config";
@@ -37,12 +37,17 @@ function registerTestersCommands(program) {
37
37
  const testers = program.command("testers").description("Manage testers and tester groups");
38
38
  testers.command("list").description("List testers for a track").option("--track <track>", "Track name (e.g., internal, alpha, beta)").action(async (options) => {
39
39
  const config = await loadConfig();
40
- const packageName = resolvePackageName(program.opts().app, config);
40
+ const packageName = resolvePackageName(program.opts()["app"], config);
41
41
  const interactive = isInteractive(program);
42
- options.track = await requireOption("track", options.track, {
43
- message: "Track:",
44
- choices: ["internal", "alpha", "beta"]
45
- }, interactive);
42
+ options.track = await requireOption(
43
+ "track",
44
+ options.track,
45
+ {
46
+ message: "Track:",
47
+ choices: ["internal", "alpha", "beta"]
48
+ },
49
+ interactive
50
+ );
46
51
  const client = await getClient(config);
47
52
  const format = detectOutputFormat();
48
53
  try {
@@ -55,20 +60,29 @@ function registerTestersCommands(program) {
55
60
  });
56
61
  testers.command("add <emails...>").description("Add testers (Google Group emails) to a track").option("--track <track>", "Track name (e.g., internal, alpha, beta)").action(async (emails, options) => {
57
62
  const config = await loadConfig();
58
- const packageName = resolvePackageName(program.opts().app, config);
63
+ const packageName = resolvePackageName(program.opts()["app"], config);
59
64
  const format = detectOutputFormat();
60
65
  const interactive = isInteractive(program);
61
- options.track = await requireOption("track", options.track, {
62
- message: "Track:",
63
- choices: ["internal", "alpha", "beta"]
64
- }, interactive);
66
+ options.track = await requireOption(
67
+ "track",
68
+ options.track,
69
+ {
70
+ message: "Track:",
71
+ choices: ["internal", "alpha", "beta"]
72
+ },
73
+ interactive
74
+ );
65
75
  if (isDryRun(program)) {
66
- printDryRun({
67
- command: "testers add",
68
- action: "add testers to",
69
- target: options.track,
70
- details: { emails }
71
- }, format, formatOutput);
76
+ printDryRun(
77
+ {
78
+ command: "testers add",
79
+ action: "add testers to",
80
+ target: options.track,
81
+ details: { emails }
82
+ },
83
+ format,
84
+ formatOutput
85
+ );
72
86
  return;
73
87
  }
74
88
  const client = await getClient(config);
@@ -82,21 +96,30 @@ function registerTestersCommands(program) {
82
96
  });
83
97
  testers.command("remove <emails...>").description("Remove testers (Google Group emails) from a track").option("--track <track>", "Track name (e.g., internal, alpha, beta)").action(async (emails, options) => {
84
98
  const config = await loadConfig();
85
- const packageName = resolvePackageName(program.opts().app, config);
99
+ const packageName = resolvePackageName(program.opts()["app"], config);
86
100
  const format = detectOutputFormat();
87
101
  const interactive = isInteractive(program);
88
- options.track = await requireOption("track", options.track, {
89
- message: "Track:",
90
- choices: ["internal", "alpha", "beta"]
91
- }, interactive);
102
+ options.track = await requireOption(
103
+ "track",
104
+ options.track,
105
+ {
106
+ message: "Track:",
107
+ choices: ["internal", "alpha", "beta"]
108
+ },
109
+ interactive
110
+ );
92
111
  await requireConfirm(`Remove ${emails.length} tester(s) from ${options.track}?`, program);
93
112
  if (isDryRun(program)) {
94
- printDryRun({
95
- command: "testers remove",
96
- action: "remove testers from",
97
- target: options.track,
98
- details: { emails }
99
- }, format, formatOutput);
113
+ printDryRun(
114
+ {
115
+ command: "testers remove",
116
+ action: "remove testers from",
117
+ target: options.track,
118
+ details: { emails }
119
+ },
120
+ format,
121
+ formatOutput
122
+ );
100
123
  return;
101
124
  }
102
125
  const client = await getClient(config);
@@ -110,23 +133,37 @@ function registerTestersCommands(program) {
110
133
  });
111
134
  testers.command("import").description("Import testers from a CSV file").option("--track <track>", "Track name (e.g., internal, alpha, beta)").option("--file <path>", "CSV file with email addresses").action(async (options) => {
112
135
  const config = await loadConfig();
113
- const packageName = resolvePackageName(program.opts().app, config);
136
+ const packageName = resolvePackageName(program.opts()["app"], config);
114
137
  const format = detectOutputFormat();
115
138
  const interactive = isInteractive(program);
116
- options.track = await requireOption("track", options.track, {
117
- message: "Track:",
118
- choices: ["internal", "alpha", "beta"]
119
- }, interactive);
120
- options.file = await requireOption("file", options.file, {
121
- message: "CSV file path:"
122
- }, interactive);
139
+ options.track = await requireOption(
140
+ "track",
141
+ options.track,
142
+ {
143
+ message: "Track:",
144
+ choices: ["internal", "alpha", "beta"]
145
+ },
146
+ interactive
147
+ );
148
+ options.file = await requireOption(
149
+ "file",
150
+ options.file,
151
+ {
152
+ message: "CSV file path:"
153
+ },
154
+ interactive
155
+ );
123
156
  if (isDryRun(program)) {
124
- printDryRun({
125
- command: "testers import",
126
- action: "import testers to",
127
- target: options.track,
128
- details: { file: options.file }
129
- }, format, formatOutput);
157
+ printDryRun(
158
+ {
159
+ command: "testers import",
160
+ action: "import testers to",
161
+ target: options.track,
162
+ details: { file: options.file }
163
+ },
164
+ format,
165
+ formatOutput
166
+ );
130
167
  return;
131
168
  }
132
169
  const client = await getClient(config);
@@ -142,4 +179,4 @@ function registerTestersCommands(program) {
142
179
  export {
143
180
  registerTestersCommands
144
181
  };
145
- //# sourceMappingURL=testers-WWZMLB7J.js.map
182
+ //# sourceMappingURL=testers-YNOGFHUR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/testers.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport {\n listTesters,\n addTesters,\n removeTesters,\n importTestersFromCsv,\n detectOutputFormat,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, requireOption, requireConfirm } from \"../prompt.js\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createApiClient({ auth });\n}\n\nexport function registerTestersCommands(program: Command): void {\n const testers = program.command(\"testers\").description(\"Manage testers and tester groups\");\n\n testers\n .command(\"list\")\n .description(\"List testers for a track\")\n .option(\"--track <track>\", \"Track name (e.g., internal, alpha, beta)\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const interactive = isInteractive(program);\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: [\"internal\", \"alpha\", \"beta\"],\n },\n interactive,\n );\n\n const client = await getClient(config);\n const format = detectOutputFormat();\n\n try {\n const result = await listTesters(client, packageName, options.track);\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 testers\n .command(\"add <emails...>\")\n .description(\"Add testers (Google Group emails) to a track\")\n .option(\"--track <track>\", \"Track name (e.g., internal, alpha, beta)\")\n .action(async (emails: string[], options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = detectOutputFormat();\n const interactive = isInteractive(program);\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: [\"internal\", \"alpha\", \"beta\"],\n },\n interactive,\n );\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"testers add\",\n action: \"add testers to\",\n target: options.track,\n details: { emails },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await addTesters(client, packageName, options.track, emails);\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 testers\n .command(\"remove <emails...>\")\n .description(\"Remove testers (Google Group emails) from a track\")\n .option(\"--track <track>\", \"Track name (e.g., internal, alpha, beta)\")\n .action(async (emails: string[], options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = detectOutputFormat();\n const interactive = isInteractive(program);\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: [\"internal\", \"alpha\", \"beta\"],\n },\n interactive,\n );\n\n await requireConfirm(`Remove ${emails.length} tester(s) from ${options.track}?`, program);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"testers remove\",\n action: \"remove testers from\",\n target: options.track,\n details: { emails },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await removeTesters(client, packageName, options.track, emails);\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 testers\n .command(\"import\")\n .description(\"Import testers from a CSV file\")\n .option(\"--track <track>\", \"Track name (e.g., internal, alpha, beta)\")\n .option(\"--file <path>\", \"CSV file with email addresses\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = detectOutputFormat();\n const interactive = isInteractive(program);\n\n options.track = await requireOption(\n \"track\",\n options.track,\n {\n message: \"Track:\",\n choices: [\"internal\", \"alpha\", \"beta\"],\n },\n interactive,\n );\n\n options.file = await requireOption(\n \"file\",\n options.file,\n {\n message: \"CSV file path:\",\n },\n interactive,\n );\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"testers import\",\n action: \"import testers to\",\n target: options.track,\n details: { file: options.file },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n try {\n const result = await importTestersFromCsv(client, packageName, options.track, options.file);\n console.log(formatOutput({ added: result.added, testers: result.testers }, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -10,9 +10,11 @@ function registerTracksCommands(program) {
10
10
  const tracks = program.command("tracks").description("Manage tracks");
11
11
  tracks.command("list").description("List all tracks").action(async () => {
12
12
  const config = await loadConfig();
13
- const packageName = program.opts().app || config.app;
13
+ const packageName = program.opts()["app"] || config.app;
14
14
  if (!packageName) {
15
- console.error("Error: No package name. Use --app <package> or gpc config set app <package>");
15
+ console.error(
16
+ "Error: No package name. Use --app <package> or gpc config set app <package>"
17
+ );
16
18
  process.exit(2);
17
19
  }
18
20
  try {
@@ -36,4 +38,4 @@ function registerTracksCommands(program) {
36
38
  export {
37
39
  registerTracksCommands
38
40
  };
39
- //# sourceMappingURL=tracks-427E34S3.js.map
41
+ //# sourceMappingURL=tracks-HMJ3F55N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/tracks.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 { listTracks } from \"@gpc-cli/core\";\nimport { detectOutputFormat, formatOutput } from \"@gpc-cli/core\";\n\nexport function registerTracksCommands(program: Command): void {\n const tracks = program.command(\"tracks\").description(\"Manage tracks\");\n\n tracks\n .command(\"list\")\n .description(\"List all tracks\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n console.error(\n \"Error: No package name. Use --app <package> or gpc config set app <package>\",\n );\n process.exit(2);\n }\n\n try {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const trackList = await listTracks(client, packageName);\n const format = detectOutputFormat();\n\n const summary = trackList.map((t) => ({\n track: t.track,\n releases: t.releases?.length || 0,\n latestStatus: t.releases?.[0]?.status || \"none\",\n latestVersion: t.releases?.[0]?.versionCodes?.[0] || \"-\",\n }));\n\n console.log(formatOutput(summary, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":";;;AACA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB,oBAAoB;AAE1C,SAAS,uBAAuB,SAAwB;AAC7D,QAAM,SAAS,QAAQ,QAAQ,QAAQ,EAAE,YAAY,eAAe;AAEpE,SACG,QAAQ,MAAM,EACd,YAAY,iBAAiB,EAC7B,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,QAAQ,KAAK,EAAE,KAAK,KAAK,OAAO;AACpD,QAAI,CAAC,aAAa;AAChB,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI;AACF,YAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,YAAM,SAAS,gBAAgB,EAAE,KAAK,CAAC;AACvC,YAAM,YAAY,MAAM,WAAW,QAAQ,WAAW;AACtD,YAAM,SAAS,mBAAmB;AAElC,YAAM,UAAU,UAAU,IAAI,CAAC,OAAO;AAAA,QACpC,OAAO,EAAE;AAAA,QACT,UAAU,EAAE,UAAU,UAAU;AAAA,QAChC,cAAc,EAAE,WAAW,CAAC,GAAG,UAAU;AAAA,QACzC,eAAe,EAAE,WAAW,CAAC,GAAG,eAAe,CAAC,KAAK;AAAA,MACvD,EAAE;AAEF,cAAQ,IAAI,aAAa,SAAS,MAAM,CAAC;AAAA,IAC3C,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;","names":[]}
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  isDryRun,
4
4
  printDryRun
5
- } from "./chunk-QMKZYXDJ.js";
5
+ } from "./chunk-Y3QZDAKS.js";
6
6
  import {
7
7
  requireConfirm
8
- } from "./chunk-4QV4WD3F.js";
8
+ } from "./chunk-Q7KVGI46.js";
9
9
 
10
10
  // src/commands/users.ts
11
11
  import { loadConfig } from "@gpc-cli/config";
@@ -25,7 +25,9 @@ import {
25
25
  function resolveDeveloperId(devIdArg, config) {
26
26
  const id = devIdArg || config.developerId;
27
27
  if (!id) {
28
- console.error("Error: No developer ID. Use --developer-id <id> or gpc config set developerId <id>");
28
+ console.error(
29
+ "Error: No developer ID. Use --developer-id <id> or gpc config set developerId <id>"
30
+ );
29
31
  process.exit(2);
30
32
  }
31
33
  return id;
@@ -38,7 +40,7 @@ function registerUsersCommands(program) {
38
40
  const users = program.command("users").description("Manage developer account users and permissions").option("--developer-id <id>", "Developer account ID");
39
41
  users.command("list").description("List all users in the developer account").option("--limit <n>", "Maximum total results", parseInt).option("--next-page <token>", "Resume from page token").action(async (options) => {
40
42
  const config = await loadConfig();
41
- const developerId = resolveDeveloperId(users.opts().developerId, config);
43
+ const developerId = resolveDeveloperId(users.opts()["developerId"], config);
42
44
  const client = await getUsersClient(config);
43
45
  const format = detectOutputFormat();
44
46
  try {
@@ -54,7 +56,7 @@ function registerUsersCommands(program) {
54
56
  });
55
57
  users.command("get <email>").description("Get user details").action(async (email) => {
56
58
  const config = await loadConfig();
57
- const developerId = resolveDeveloperId(users.opts().developerId, config);
59
+ const developerId = resolveDeveloperId(users.opts()["developerId"], config);
58
60
  const client = await getUsersClient(config);
59
61
  const format = detectOutputFormat();
60
62
  try {
@@ -65,17 +67,24 @@ function registerUsersCommands(program) {
65
67
  process.exit(4);
66
68
  }
67
69
  });
68
- users.command("invite <email>").description("Invite a user to the developer account").option("--role <permissions...>", "Developer-level permissions").option("--grant <grants...>", "Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)").action(async (email, options) => {
70
+ users.command("invite <email>").description("Invite a user to the developer account").option("--role <permissions...>", "Developer-level permissions").option(
71
+ "--grant <grants...>",
72
+ "Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)"
73
+ ).action(async (email, options) => {
69
74
  const config = await loadConfig();
70
- const developerId = resolveDeveloperId(users.opts().developerId, config);
75
+ const developerId = resolveDeveloperId(users.opts()["developerId"], config);
71
76
  const format = detectOutputFormat();
72
77
  if (isDryRun(program)) {
73
- printDryRun({
74
- command: "users invite",
75
- action: "invite",
76
- target: email,
77
- details: { role: options.role, grant: options.grant }
78
- }, format, formatOutput);
78
+ printDryRun(
79
+ {
80
+ command: "users invite",
81
+ action: "invite",
82
+ target: email,
83
+ details: { role: options.role, grant: options.grant }
84
+ },
85
+ format,
86
+ formatOutput
87
+ );
79
88
  return;
80
89
  }
81
90
  const client = await getUsersClient(config);
@@ -90,17 +99,24 @@ function registerUsersCommands(program) {
90
99
  process.exit(4);
91
100
  }
92
101
  });
93
- users.command("update <email>").description("Update user permissions").option("--role <permissions...>", "Developer-level permissions").option("--grant <grants...>", "Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)").action(async (email, options) => {
102
+ users.command("update <email>").description("Update user permissions").option("--role <permissions...>", "Developer-level permissions").option(
103
+ "--grant <grants...>",
104
+ "Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)"
105
+ ).action(async (email, options) => {
94
106
  const config = await loadConfig();
95
- const developerId = resolveDeveloperId(users.opts().developerId, config);
107
+ const developerId = resolveDeveloperId(users.opts()["developerId"], config);
96
108
  const format = detectOutputFormat();
97
109
  if (isDryRun(program)) {
98
- printDryRun({
99
- command: "users update",
100
- action: "update",
101
- target: email,
102
- details: { role: options.role, grant: options.grant }
103
- }, format, formatOutput);
110
+ printDryRun(
111
+ {
112
+ command: "users update",
113
+ action: "update",
114
+ target: email,
115
+ details: { role: options.role, grant: options.grant }
116
+ },
117
+ format,
118
+ formatOutput
119
+ );
104
120
  return;
105
121
  }
106
122
  const client = await getUsersClient(config);
@@ -117,15 +133,19 @@ function registerUsersCommands(program) {
117
133
  });
118
134
  users.command("remove <email>").description("Remove a user from the developer account").action(async (email) => {
119
135
  const config = await loadConfig();
120
- const developerId = resolveDeveloperId(users.opts().developerId, config);
136
+ const developerId = resolveDeveloperId(users.opts()["developerId"], config);
121
137
  await requireConfirm(`Remove user "${email}" from developer account?`, program);
122
138
  if (isDryRun(program)) {
123
139
  const format = detectOutputFormat();
124
- printDryRun({
125
- command: "users remove",
126
- action: "remove",
127
- target: email
128
- }, format, formatOutput);
140
+ printDryRun(
141
+ {
142
+ command: "users remove",
143
+ action: "remove",
144
+ target: email
145
+ },
146
+ format,
147
+ formatOutput
148
+ );
129
149
  return;
130
150
  }
131
151
  const client = await getUsersClient(config);
@@ -142,4 +162,4 @@ function registerUsersCommands(program) {
142
162
  export {
143
163
  registerUsersCommands
144
164
  };
145
- //# sourceMappingURL=users-E5Y5HI6K.js.map
165
+ //# sourceMappingURL=users-GRQTY6HY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/users.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createUsersClient } from \"@gpc-cli/api\";\nimport type { DeveloperPermission } from \"@gpc-cli/api\";\nimport {\n listUsers,\n getUser,\n inviteUser,\n updateUser,\n removeUser,\n parseGrantArg,\n PERMISSION_PROPAGATION_WARNING,\n detectOutputFormat,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { requireConfirm } from \"../prompt.js\";\n\nfunction resolveDeveloperId(devIdArg: string | undefined, config: GpcConfig): string {\n const id = devIdArg || config.developerId;\n if (!id) {\n console.error(\n \"Error: No developer ID. Use --developer-id <id> or gpc config set developerId <id>\",\n );\n process.exit(2);\n }\n return id;\n}\n\nasync function getUsersClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createUsersClient({ auth });\n}\n\nexport function registerUsersCommands(program: Command): void {\n const users = program\n .command(\"users\")\n .description(\"Manage developer account users and permissions\")\n .option(\"--developer-id <id>\", \"Developer account ID\");\n\n users\n .command(\"list\")\n .description(\"List all users in the developer account\")\n .option(\"--limit <n>\", \"Maximum total results\", parseInt)\n .option(\"--next-page <token>\", \"Resume from page token\")\n .action(async (options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const client = await getUsersClient(config);\n const format = detectOutputFormat();\n\n try {\n const result = await listUsers(client, developerId, {\n limit: options.limit,\n nextPage: options.nextPage,\n });\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n users\n .command(\"get <email>\")\n .description(\"Get user details\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const client = await getUsersClient(config);\n const format = detectOutputFormat();\n\n try {\n const result = await getUser(client, developerId, email);\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 users\n .command(\"invite <email>\")\n .description(\"Invite a user to the developer account\")\n .option(\"--role <permissions...>\", \"Developer-level permissions\")\n .option(\n \"--grant <grants...>\",\n \"Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const format = detectOutputFormat();\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"users invite\",\n action: \"invite\",\n target: email,\n details: { role: options.role, grant: options.grant },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n try {\n const permissions = options.role as DeveloperPermission[] | undefined;\n const grants = options.grant?.map((g: string) => parseGrantArg(g));\n const result = await inviteUser(client, developerId, email, permissions, grants);\n console.log(formatOutput(result, format));\n console.error(PERMISSION_PROPAGATION_WARNING);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n users\n .command(\"update <email>\")\n .description(\"Update user permissions\")\n .option(\"--role <permissions...>\", \"Developer-level permissions\")\n .option(\n \"--grant <grants...>\",\n \"Per-app grants (format: com.example.app:PERMISSION1,PERMISSION2)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n const format = detectOutputFormat();\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"users update\",\n action: \"update\",\n target: email,\n details: { role: options.role, grant: options.grant },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n try {\n const permissions = options.role as DeveloperPermission[] | undefined;\n const grants = options.grant?.map((g: string) => parseGrantArg(g));\n const result = await updateUser(client, developerId, email, permissions, grants);\n console.log(formatOutput(result, format));\n console.error(PERMISSION_PROPAGATION_WARNING);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n users\n .command(\"remove <email>\")\n .description(\"Remove a user from the developer account\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(users.opts()[\"developerId\"], config);\n\n await requireConfirm(`Remove user \"${email}\" from developer account?`, program);\n\n if (isDryRun(program)) {\n const format = detectOutputFormat();\n printDryRun(\n {\n command: \"users remove\",\n action: \"remove\",\n target: email,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getUsersClient(config);\n\n try {\n await removeUser(client, developerId, email);\n console.log(`User ${email} removed.`);\n console.error(PERMISSION_PROPAGATION_WARNING);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -56,7 +56,7 @@ function validateDimension(dim) {
56
56
  function registerMetricCommand(parent, name, description, fn, program) {
57
57
  parent.command(name).description(description).option("--dim <dimension>", "Group by dimension").option("--days <n>", "Number of days to query", parseInt).option("--threshold <value>", "Threshold value for CI alerting", parseFloat).action(async (options) => {
58
58
  const config = await loadConfig();
59
- const packageName = resolvePackageName(program.opts().app, config);
59
+ const packageName = resolvePackageName(program.opts()["app"], config);
60
60
  const reporting = await getReportingClient(config);
61
61
  const format = detectOutputFormat();
62
62
  try {
@@ -86,7 +86,7 @@ function registerVitalsCommands(program) {
86
86
  const vitals = program.command("vitals").description("Monitor app vitals, crash rates, and performance metrics");
87
87
  vitals.command("overview").description("Dashboard summary of all vital metrics").action(async () => {
88
88
  const config = await loadConfig();
89
- const packageName = resolvePackageName(program.opts().app, config);
89
+ const packageName = resolvePackageName(program.opts()["app"], config);
90
90
  const reporting = await getReportingClient(config);
91
91
  const format = detectOutputFormat();
92
92
  try {
@@ -100,12 +100,24 @@ function registerVitalsCommands(program) {
100
100
  registerMetricCommand(vitals, "crashes", "Query crash rate metrics", getVitalsCrashes, program);
101
101
  registerMetricCommand(vitals, "anr", "Query ANR rate metrics", getVitalsAnr, program);
102
102
  registerMetricCommand(vitals, "startup", "Query slow startup metrics", getVitalsStartup, program);
103
- registerMetricCommand(vitals, "rendering", "Query slow rendering metrics", getVitalsRendering, program);
104
- registerMetricCommand(vitals, "battery", "Query excessive wakeup metrics", getVitalsBattery, program);
103
+ registerMetricCommand(
104
+ vitals,
105
+ "rendering",
106
+ "Query slow rendering metrics",
107
+ getVitalsRendering,
108
+ program
109
+ );
110
+ registerMetricCommand(
111
+ vitals,
112
+ "battery",
113
+ "Query excessive wakeup metrics",
114
+ getVitalsBattery,
115
+ program
116
+ );
105
117
  registerMetricCommand(vitals, "memory", "Query stuck wakelock metrics", getVitalsMemory, program);
106
118
  vitals.command("anomalies").description("Detect anomalies in app vitals").action(async () => {
107
119
  const config = await loadConfig();
108
- const packageName = resolvePackageName(program.opts().app, config);
120
+ const packageName = resolvePackageName(program.opts()["app"], config);
109
121
  const reporting = await getReportingClient(config);
110
122
  const format = detectOutputFormat();
111
123
  try {
@@ -119,7 +131,7 @@ function registerVitalsCommands(program) {
119
131
  const errors = vitals.command("errors").description("Search and view error issues");
120
132
  errors.command("search").description("Search error issues").option("--filter <text>", "Filter expression").option("--max <n>", "Maximum results", parseInt).action(async (options) => {
121
133
  const config = await loadConfig();
122
- const packageName = resolvePackageName(program.opts().app, config);
134
+ const packageName = resolvePackageName(program.opts()["app"], config);
123
135
  const reporting = await getReportingClient(config);
124
136
  const format = detectOutputFormat();
125
137
  try {
@@ -144,11 +156,13 @@ function registerVitalsCommands(program) {
144
156
  vitals.command("compare <metric>").description("Compare metric trend: this period vs previous period").option("--days <n>", "Period length in days", parseInt, 7).action(async (metric, options) => {
145
157
  const metricSet = METRIC_MAP[metric];
146
158
  if (!metricSet) {
147
- console.error(`Error: Unknown metric "${metric}". Use: ${Object.keys(METRIC_MAP).join(", ")}`);
159
+ console.error(
160
+ `Error: Unknown metric "${metric}". Use: ${Object.keys(METRIC_MAP).join(", ")}`
161
+ );
148
162
  process.exit(2);
149
163
  }
150
164
  const config = await loadConfig();
151
- const packageName = resolvePackageName(program.opts().app, config);
165
+ const packageName = resolvePackageName(program.opts()["app"], config);
152
166
  const reporting = await getReportingClient(config);
153
167
  const format = detectOutputFormat();
154
168
  try {
@@ -163,4 +177,4 @@ function registerVitalsCommands(program) {
163
177
  export {
164
178
  registerVitalsCommands
165
179
  };
166
- //# sourceMappingURL=vitals-YMZMUPNA.js.map
180
+ //# sourceMappingURL=vitals-VP2GKG3G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/vitals.ts"],"sourcesContent":["import 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 } from \"@gpc-cli/api\";\nimport type { ReportingDimension } from \"@gpc-cli/api\";\nimport type { VitalsMetricSet } from \"@gpc-cli/api\";\nimport {\n getVitalsOverview,\n getVitalsCrashes,\n getVitalsAnr,\n getVitalsStartup,\n getVitalsRendering,\n getVitalsBattery,\n getVitalsMemory,\n getVitalsAnomalies,\n searchVitalsErrors,\n compareVitalsTrend,\n checkThreshold,\n detectOutputFormat,\n formatOutput,\n} from \"@gpc-cli/core\";\n\nfunction resolvePackageName(packageArg: string | undefined, config: GpcConfig): string {\n const name = packageArg || config.app;\n if (!name) {\n console.error(\"Error: No package name. Use --app <package> or gpc config set app <package>\");\n process.exit(2);\n }\n return name;\n}\n\nasync function getReportingClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createReportingClient({ auth });\n}\n\nconst VALID_DIMENSIONS: ReportingDimension[] = [\n \"apiLevel\",\n \"versionCode\",\n \"deviceModel\",\n \"deviceType\",\n \"countryCode\",\n \"deviceRamBucket\",\n \"deviceSocName\",\n \"deviceCpuMakeModel\",\n \"deviceGlEsVersion\",\n \"deviceVulkanVersion\",\n \"deviceOpenGlVersion\",\n \"deviceBrand\",\n];\n\nfunction validateDimension(dim: string): ReportingDimension {\n if (!VALID_DIMENSIONS.includes(dim as ReportingDimension)) {\n console.error(`Error: Invalid dimension \"${dim}\".`);\n console.error(`Valid dimensions: ${VALID_DIMENSIONS.join(\", \")}`);\n process.exit(2);\n }\n return dim as ReportingDimension;\n}\n\ntype MetricFn = typeof getVitalsCrashes;\n\nfunction registerMetricCommand(\n parent: Command,\n name: string,\n description: string,\n fn: MetricFn,\n program: Command,\n): void {\n parent\n .command(name)\n .description(description)\n .option(\"--dim <dimension>\", \"Group by dimension\")\n .option(\"--days <n>\", \"Number of days to query\", parseInt)\n .option(\"--threshold <value>\", \"Threshold value for CI alerting\", parseFloat)\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = detectOutputFormat();\n\n try {\n const result = await fn(reporting, packageName, {\n dimension: options.dim ? validateDimension(options.dim) : undefined,\n days: options.days,\n });\n console.log(formatOutput(result, format));\n\n if (options.threshold !== undefined) {\n const latestRow = result.rows?.[result.rows.length - 1];\n const metricKeys = latestRow?.metrics ? Object.keys(latestRow.metrics) : [];\n const firstMetric = metricKeys[0];\n const value = firstMetric\n ? Number(latestRow?.metrics[firstMetric]?.decimalValue?.value)\n : undefined;\n const check = checkThreshold(value, options.threshold);\n if (check.breached) {\n console.error(`Threshold breached: ${check.value} > ${check.threshold}`);\n process.exit(6);\n }\n }\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n}\n\nexport function registerVitalsCommands(program: Command): void {\n const vitals = program\n .command(\"vitals\")\n .description(\"Monitor app vitals, crash rates, and performance metrics\");\n\n vitals\n .command(\"overview\")\n .description(\"Dashboard summary of all vital metrics\")\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 = detectOutputFormat();\n\n try {\n const result = await getVitalsOverview(reporting, packageName);\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 registerMetricCommand(vitals, \"crashes\", \"Query crash rate metrics\", getVitalsCrashes, program);\n registerMetricCommand(vitals, \"anr\", \"Query ANR rate metrics\", getVitalsAnr, program);\n registerMetricCommand(vitals, \"startup\", \"Query slow startup metrics\", getVitalsStartup, program);\n registerMetricCommand(\n vitals,\n \"rendering\",\n \"Query slow rendering metrics\",\n getVitalsRendering,\n program,\n );\n registerMetricCommand(\n vitals,\n \"battery\",\n \"Query excessive wakeup metrics\",\n getVitalsBattery,\n program,\n );\n registerMetricCommand(vitals, \"memory\", \"Query stuck wakelock metrics\", getVitalsMemory, program);\n\n vitals\n .command(\"anomalies\")\n .description(\"Detect anomalies in app vitals\")\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 = detectOutputFormat();\n\n try {\n const result = await getVitalsAnomalies(reporting, packageName);\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 const errors = vitals.command(\"errors\").description(\"Search and view error issues\");\n\n errors\n .command(\"search\")\n .description(\"Search error issues\")\n .option(\"--filter <text>\", \"Filter expression\")\n .option(\"--max <n>\", \"Maximum results\", parseInt)\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = detectOutputFormat();\n\n try {\n const result = await searchVitalsErrors(reporting, packageName, {\n filter: options.filter,\n maxResults: options.max,\n });\n console.log(formatOutput(result, format));\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n const METRIC_MAP: Record<string, VitalsMetricSet> = {\n crashes: \"vitals.crashrate\",\n anr: \"vitals.anrrate\",\n startup: \"vitals.slowstartrate\",\n rendering: \"vitals.slowrenderingrate\",\n battery: \"vitals.excessivewakeuprate\",\n memory: \"vitals.stuckbackgroundwakelockrate\",\n };\n\n vitals\n .command(\"compare <metric>\")\n .description(\"Compare metric trend: this period vs previous period\")\n .option(\"--days <n>\", \"Period length in days\", parseInt, 7)\n .action(async (metric: string, options) => {\n const metricSet = METRIC_MAP[metric];\n if (!metricSet) {\n console.error(\n `Error: Unknown metric \"${metric}\". Use: ${Object.keys(METRIC_MAP).join(\", \")}`,\n );\n process.exit(2);\n }\n\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const reporting = await getReportingClient(config);\n const format = detectOutputFormat();\n\n try {\n const result = await compareVitalsTrend(reporting, packageName, metricSet, options.days);\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"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gpc-cli/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "The complete Google Play CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,11 +19,11 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "commander": "^14.0.3",
22
- "@gpc-cli/api": "1.0.1",
23
- "@gpc-cli/auth": "^0.1.1",
24
- "@gpc-cli/config": "0.1.1",
25
- "@gpc-cli/core": "0.1.1",
26
- "@gpc-cli/plugin-sdk": "0.1.1"
22
+ "@gpc-cli/api": "1.0.3",
23
+ "@gpc-cli/auth": "^0.1.3",
24
+ "@gpc-cli/config": "0.1.3",
25
+ "@gpc-cli/core": "0.1.3",
26
+ "@gpc-cli/plugin-sdk": "0.1.2"
27
27
  },
28
28
  "keywords": [
29
29
  "google-play",
@@ -1 +0,0 @@
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 { detectOutputFormat, formatOutput } from \"@gpc-cli/core\";\n\nexport function registerAppsCommands(program: Command): void {\n const apps = program\n .command(\"apps\")\n .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 = detectOutputFormat();\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(\"Error: Provide at least one field to update (--email, --phone, --website, --default-lang).\");\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 result = await updateAppDetails(client, packageName, data);\n const format = detectOutputFormat();\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 .action(async () => {\n const config = await loadConfig();\n const format = detectOutputFormat();\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 +0,0 @@
1
- {"version":3,"sources":["../src/commands/auth.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { resolveAuth, loadServiceAccountKey, clearTokenCache, AuthError } from \"@gpc-cli/auth\";\nimport { loadConfig, getCacheDir } from \"@gpc-cli/config\";\nimport { detectOutputFormat, formatOutput } from \"@gpc-cli/core\";\n\nexport function registerAuthCommands(program: Command): void {\n const auth = program\n .command(\"auth\")\n .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 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 } 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 try {\n const config = await loadConfig();\n const client = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n cachePath: getCacheDir(),\n });\n const format = detectOutputFormat();\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 = detectOutputFormat();\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(\"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 = detectOutputFormat();\n\n if (profiles.length === 0) {\n console.log(\"No profiles configured. Use: gpc auth login --service-account <path> --profile <name>\");\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":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/prompt.ts"],"sourcesContent":["import { createInterface } from \"node:readline\";\n\n/**\n * Check if interactive prompts are allowed.\n * Disabled by --no-interactive flag, GPC_NO_INTERACTIVE env, or non-TTY stdin.\n */\nexport function isInteractive(program?: { opts(): Record<string, unknown> }): boolean {\n // Commander's --no-interactive sets interactive = false\n if (program) {\n let root = program as any;\n while (root.parent) root = root.parent;\n if (root.opts().interactive === false) return false;\n }\n\n if (process.env[\"GPC_NO_INTERACTIVE\"] === \"1\" || process.env[\"GPC_NO_INTERACTIVE\"] === \"true\") {\n return false;\n }\n\n if (process.env[\"CI\"] === \"true\" || process.env[\"CI\"] === \"1\") {\n return false;\n }\n\n return Boolean(process.stdin.isTTY);\n}\n\n/**\n * Check if --yes flag is set (skip confirmation prompts).\n */\nexport function skipConfirm(program?: { opts(): Record<string, unknown> }): boolean {\n if (!program) return false;\n let root = program as any;\n while (root.parent) root = root.parent;\n return root.opts().yes === true;\n}\n\n/**\n * Require an option value: return existing value, prompt interactively, or exit with error.\n */\nexport async function requireOption(\n name: string,\n value: string | undefined,\n prompt: { message: string; choices?: string[]; default?: string },\n interactive: boolean,\n): Promise<string> {\n if (value) return value;\n if (interactive) {\n return prompt.choices\n ? promptSelect(prompt.message, prompt.choices, prompt.default)\n : promptInput(prompt.message, prompt.default);\n }\n process.stderr.write(`Error: Missing required option --${name}\\n`);\n process.stderr.write(`Suggestion: Provide --${name} or run interactively (remove --no-interactive)\\n`);\n process.exit(2);\n}\n\n/**\n * Require confirmation for destructive operations.\n * Returns true if confirmed (or --yes flag is set / non-interactive).\n * Exits with code 0 if denied.\n */\nexport async function requireConfirm(\n message: string,\n program?: { opts(): Record<string, unknown> },\n): Promise<void> {\n if (skipConfirm(program)) return;\n if (!isInteractive(program)) return;\n const confirmed = await promptConfirm(message, false);\n if (!confirmed) {\n console.log(\"Aborted.\");\n process.exit(0);\n }\n}\n\n/**\n * Prompt for text input.\n */\nexport async function promptInput(message: string, defaultValue?: string): Promise<string> {\n const suffix = defaultValue ? ` (${defaultValue})` : \"\";\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n\n return new Promise((resolve) => {\n rl.question(`${message}${suffix}: `, (answer) => {\n rl.close();\n resolve(answer.trim() || defaultValue || \"\");\n });\n });\n}\n\n/**\n * Prompt for selection from a list of choices.\n */\nexport async function promptSelect(message: string, choices: string[], defaultValue?: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n\n process.stderr.write(`${message}\\n`);\n for (let i = 0; i < choices.length; i++) {\n const marker = choices[i] === defaultValue ? \" (default)\" : \"\";\n process.stderr.write(` ${i + 1}) ${choices[i]}${marker}\\n`);\n }\n\n return new Promise((resolve) => {\n rl.question(\"Choice: \", (answer) => {\n rl.close();\n const trimmed = answer.trim();\n\n // Accept number\n const num = Number(trimmed);\n if (num >= 1 && num <= choices.length) {\n resolve(choices[num - 1]!);\n return;\n }\n\n // Accept exact match\n if (choices.includes(trimmed)) {\n resolve(trimmed);\n return;\n }\n\n // Default\n resolve(defaultValue || choices[0]!);\n });\n });\n}\n\n/**\n * Prompt for yes/no confirmation.\n */\nexport async function promptConfirm(message: string, defaultValue = true): Promise<boolean> {\n const hint = defaultValue ? \"Y/n\" : \"y/N\";\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n\n return new Promise((resolve) => {\n rl.question(`${message} [${hint}]: `, (answer) => {\n rl.close();\n const trimmed = answer.trim().toLowerCase();\n if (trimmed === \"\") resolve(defaultValue);\n else resolve(trimmed === \"y\" || trimmed === \"yes\");\n });\n });\n}\n"],"mappings":";;;AAAA,SAAS,uBAAuB;AAMzB,SAAS,cAAc,SAAwD;AAEpF,MAAI,SAAS;AACX,QAAI,OAAO;AACX,WAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,QAAI,KAAK,KAAK,EAAE,gBAAgB,MAAO,QAAO;AAAA,EAChD;AAEA,MAAI,QAAQ,IAAI,oBAAoB,MAAM,OAAO,QAAQ,IAAI,oBAAoB,MAAM,QAAQ;AAC7F,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,IAAI,IAAI,MAAM,UAAU,QAAQ,IAAI,IAAI,MAAM,KAAK;AAC7D,WAAO;AAAA,EACT;AAEA,SAAO,QAAQ,QAAQ,MAAM,KAAK;AACpC;AAKO,SAAS,YAAY,SAAwD;AAClF,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,OAAO;AACX,SAAO,KAAK,OAAQ,QAAO,KAAK;AAChC,SAAO,KAAK,KAAK,EAAE,QAAQ;AAC7B;AAKA,eAAsB,cACpB,MACA,OACA,QACA,aACiB;AACjB,MAAI,MAAO,QAAO;AAClB,MAAI,aAAa;AACf,WAAO,OAAO,UACV,aAAa,OAAO,SAAS,OAAO,SAAS,OAAO,OAAO,IAC3D,YAAY,OAAO,SAAS,OAAO,OAAO;AAAA,EAChD;AACA,UAAQ,OAAO,MAAM,oCAAoC,IAAI;AAAA,CAAI;AACjE,UAAQ,OAAO,MAAM,yBAAyB,IAAI;AAAA,CAAmD;AACrG,UAAQ,KAAK,CAAC;AAChB;AAOA,eAAsB,eACpB,SACA,SACe;AACf,MAAI,YAAY,OAAO,EAAG;AAC1B,MAAI,CAAC,cAAc,OAAO,EAAG;AAC7B,QAAM,YAAY,MAAM,cAAc,SAAS,KAAK;AACpD,MAAI,CAAC,WAAW;AACd,YAAQ,IAAI,UAAU;AACtB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAKA,eAAsB,YAAY,SAAiB,cAAwC;AACzF,QAAM,SAAS,eAAe,KAAK,YAAY,MAAM;AACrD,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAE3E,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,GAAG,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW;AAC/C,SAAG,MAAM;AACT,cAAQ,OAAO,KAAK,KAAK,gBAAgB,EAAE;AAAA,IAC7C,CAAC;AAAA,EACH,CAAC;AACH;AAKA,eAAsB,aAAa,SAAiB,SAAmB,cAAwC;AAC7G,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAE3E,UAAQ,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AACnC,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,SAAS,QAAQ,CAAC,MAAM,eAAe,eAAe;AAC5D,YAAQ,OAAO,MAAM,KAAK,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC,GAAG,MAAM;AAAA,CAAI;AAAA,EAC7D;AAEA,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,YAAY,CAAC,WAAW;AAClC,SAAG,MAAM;AACT,YAAM,UAAU,OAAO,KAAK;AAG5B,YAAM,MAAM,OAAO,OAAO;AAC1B,UAAI,OAAO,KAAK,OAAO,QAAQ,QAAQ;AACrC,gBAAQ,QAAQ,MAAM,CAAC,CAAE;AACzB;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,OAAO,GAAG;AAC7B,gBAAQ,OAAO;AACf;AAAA,MACF;AAGA,cAAQ,gBAAgB,QAAQ,CAAC,CAAE;AAAA,IACrC,CAAC;AAAA,EACH,CAAC;AACH;AAKA,eAAsB,cAAc,SAAiB,eAAe,MAAwB;AAC1F,QAAM,OAAO,eAAe,QAAQ;AACpC,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAE3E,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,OAAG,SAAS,GAAG,OAAO,KAAK,IAAI,OAAO,CAAC,WAAW;AAChD,SAAG,MAAM;AACT,YAAM,UAAU,OAAO,KAAK,EAAE,YAAY;AAC1C,UAAI,YAAY,GAAI,SAAQ,YAAY;AAAA,UACnC,SAAQ,YAAY,OAAO,YAAY,KAAK;AAAA,IACnD,CAAC;AAAA,EACH,CAAC;AACH;","names":[]}