@gpc-cli/cli 0.9.85 → 0.9.87

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 (30) hide show
  1. package/README.md +2 -2
  2. package/dist/bin.js +2 -2
  3. package/dist/{chunk-IAPAEPDL.js → chunk-E2NRW3TQ.js} +11 -11
  4. package/dist/{config-XOJX2NCA.js → config-7SLPBJI3.js} +2 -2
  5. package/dist/{doctor-PFLPGPM3.js → doctor-3MJZSIGX.js} +2 -2
  6. package/dist/{feedback-FF3CBERM.js → feedback-TXDXWK7N.js} +2 -2
  7. package/dist/games-7K5RKXCO.js +361 -0
  8. package/dist/games-7K5RKXCO.js.map +1 -0
  9. package/dist/generated/docs-bundle.json +1 -1
  10. package/dist/{grants-Q3FWJYGR.js → grants-ANDUST7O.js} +13 -9
  11. package/dist/grants-ANDUST7O.js.map +1 -0
  12. package/dist/index.js +1 -1
  13. package/dist/{testers-YQZ2XHI6.js → testers-OQNP43O6.js} +14 -4
  14. package/dist/testers-OQNP43O6.js.map +1 -0
  15. package/dist/{tracks-N7KPBVPC.js → tracks-E7RUNA3C.js} +16 -4
  16. package/dist/tracks-E7RUNA3C.js.map +1 -0
  17. package/dist/{update-JGLB2ELN.js → update-UMNA6KMP.js} +2 -2
  18. package/dist/{version-B4AE5NVE.js → version-PFYWZWJC.js} +2 -2
  19. package/package.json +5 -5
  20. package/dist/games-SVFN2YIS.js +0 -60
  21. package/dist/games-SVFN2YIS.js.map +0 -1
  22. package/dist/grants-Q3FWJYGR.js.map +0 -1
  23. package/dist/testers-YQZ2XHI6.js.map +0 -1
  24. package/dist/tracks-N7KPBVPC.js.map +0 -1
  25. /package/dist/{chunk-IAPAEPDL.js.map → chunk-E2NRW3TQ.js.map} +0 -0
  26. /package/dist/{config-XOJX2NCA.js.map → config-7SLPBJI3.js.map} +0 -0
  27. /package/dist/{doctor-PFLPGPM3.js.map → doctor-3MJZSIGX.js.map} +0 -0
  28. /package/dist/{feedback-FF3CBERM.js.map → feedback-TXDXWK7N.js.map} +0 -0
  29. /package/dist/{update-JGLB2ELN.js.map → update-UMNA6KMP.js.map} +0 -0
  30. /package/dist/{version-B4AE5NVE.js.map → version-PFYWZWJC.js.map} +0 -0
@@ -20,6 +20,7 @@ import {
20
20
  updateGrant,
21
21
  deleteGrant,
22
22
  formatOutput,
23
+ annotateListResult,
23
24
  GpcError
24
25
  } from "@gpc-cli/core";
25
26
  function resolveDeveloperId(devIdArg, config) {
@@ -46,15 +47,18 @@ function registerGrantsCommands(program) {
46
47
  const client = await getClient(config);
47
48
  const format = getOutputFormat(program, config);
48
49
  const result = await listGrants(client, developerId, email);
49
- if (result.length === 0) {
50
- if (format === "json") {
51
- console.log(formatOutput([], format));
52
- } else {
53
- console.log(`No grants found for ${email}.`);
54
- }
55
- return;
50
+ if (format === "json") {
51
+ console.log(
52
+ formatOutput(
53
+ annotateListResult({ grants: result }, "grants", `No grants found for ${email}.`),
54
+ format
55
+ )
56
+ );
57
+ } else if (result.length === 0) {
58
+ console.log(`No grants found for ${email}.`);
59
+ } else {
60
+ console.log(formatOutput(result, format));
56
61
  }
57
- console.log(formatOutput(result, format));
58
62
  });
59
63
  grants.command("create <email>").description("Grant app-level permissions to a user").requiredOption("--package <packageName>", "App package name").requiredOption(
60
64
  "--permissions <list>",
@@ -128,4 +132,4 @@ function registerGrantsCommands(program) {
128
132
  export {
129
133
  registerGrantsCommands
130
134
  };
131
- //# sourceMappingURL=grants-Q3FWJYGR.js.map
135
+ //# sourceMappingURL=grants-ANDUST7O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/grants.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 {\n listGrants,\n createGrant,\n updateGrant,\n deleteGrant,\n formatOutput,\n annotateListResult,\n GpcError,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\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 throw new GpcError(\n \"No developer ID. Use --developer-id <id> or gpc config set developerId <id>\",\n \"MISSING_DEVELOPER_ID\",\n 2,\n \"gpc config set developerId <id>\",\n );\n }\n return id;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createUsersClient({ auth });\n}\n\nexport function registerGrantsCommands(program: Command): void {\n const grants = program\n .command(\"grants\")\n .description(\"Manage per-app permission grants for developer account users\")\n .option(\"--developer-id <id>\", \"Developer account ID\");\n\n grants\n .command(\"list <email>\")\n .description(\"List all per-app grants for a user\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listGrants(client, developerId, email);\n if (format === \"json\") {\n console.log(\n formatOutput(\n annotateListResult({ grants: result }, \"grants\", `No grants found for ${email}.`),\n format,\n ),\n );\n } else if (result.length === 0) {\n console.log(`No grants found for ${email}.`);\n } else {\n console.log(formatOutput(result, format));\n }\n });\n\n grants\n .command(\"create <email>\")\n .description(\"Grant app-level permissions to a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .requiredOption(\n \"--permissions <list>\",\n \"Comma-separated permissions (e.g. CAN_MANAGE_RELEASES,VIEW_APP_INFORMATION)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n const perms = (options.permissions as string).split(\",\").map((p: string) => p.trim());\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants create\",\n action: \"grant permissions\",\n target: `${email}/${options.package}`,\n details: { permissions: perms },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const result = await createGrant(client, developerId, email, options.package, perms);\n console.log(formatOutput(result, format));\n });\n\n grants\n .command(\"update <email>\")\n .description(\"Update app-level permissions for a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .requiredOption(\"--permissions <list>\", \"New comma-separated permissions\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n const perms = (options.permissions as string).split(\",\").map((p: string) => p.trim());\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants update\",\n action: \"update permissions\",\n target: `${email}/${options.package}`,\n details: { permissions: perms },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const result = await updateGrant(client, developerId, email, options.package, perms);\n console.log(formatOutput(result, format));\n });\n\n grants\n .command(\"delete <email>\")\n .description(\"Remove a per-app grant from a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n\n await requireConfirm(`Remove grant for \"${email}\" on ${options.package}?`, program);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants delete\",\n action: \"remove grant\",\n target: `${email}/${options.package}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await deleteGrant(client, developerId, email, options.package);\n console.log(`Grant removed for ${email} on ${options.package}.`);\n });\n}\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createProgram,
4
4
  handleCliError
5
- } from "./chunk-IAPAEPDL.js";
5
+ } from "./chunk-E2NRW3TQ.js";
6
6
  export {
7
7
  createProgram,
8
8
  handleCliError
@@ -26,7 +26,8 @@ import {
26
26
  addTesters,
27
27
  removeTesters,
28
28
  importTestersFromCsv,
29
- formatOutput
29
+ formatOutput,
30
+ annotateListResult
30
31
  } from "@gpc-cli/core";
31
32
  function registerTestersCommands(program) {
32
33
  const testers = program.command("testers").description("Manage testers and tester groups");
@@ -58,10 +59,19 @@ function registerTestersCommands(program) {
58
59
  if (rows.length > 0) {
59
60
  console.log(formatOutput(rows, format));
60
61
  } else {
61
- console.log("No testers found.");
62
+ console.log(`No tester groups configured for ${options.track}.`);
62
63
  }
63
64
  } else {
64
- console.log(formatOutput(result, format));
65
+ console.log(
66
+ formatOutput(
67
+ annotateListResult(
68
+ { ...result, googleGroups: result.googleGroups ?? [] },
69
+ "googleGroups",
70
+ `No tester groups configured for ${options.track}.`
71
+ ),
72
+ format
73
+ )
74
+ );
65
75
  }
66
76
  });
67
77
  testers.command("add <emails...>").description("Add testers (Google Group emails) to a track").option("--track <track>", "Track name (e.g., internal, alpha, beta)").option("--changes-not-sent-for-review", "Commit changes without sending for review").option("--error-if-in-review", "Fail if changes are already in review").action(async (emails, options) => {
@@ -188,4 +198,4 @@ function registerTestersCommands(program) {
188
198
  export {
189
199
  registerTestersCommands
190
200
  };
191
- //# sourceMappingURL=testers-YQZ2XHI6.js.map
201
+ //# sourceMappingURL=testers-OQNP43O6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/testers.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport {\n listTesters,\n addTesters,\n removeTesters,\n importTestersFromCsv,\n formatOutput,\n annotateListResult,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, requireOption, requireConfirm } from \"../prompt.js\";\nimport { buildCommitOptions } from \"../commit-options.js\";\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 .option(\"--sort <field>\", \"Sort by field (prefix with - for descending, e.g., email or -email)\")\n .option(\"--limit <n>\", \"Maximum results to return\")\n .option(\"--next-page <token>\", \"Pagination token for next page\")\n .action(async (options) => {\n const config = await loadConfig();\n const 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 = getOutputFormat(program, config);\n\n const result = await listTesters(client, packageName, options.track);\n if (options.sort && result.googleGroups) {\n const descending = options.sort.startsWith(\"-\");\n result.googleGroups = [...result.googleGroups].sort((a: string, b: string) =>\n descending ? b.localeCompare(a) : a.localeCompare(b),\n );\n }\n if (format !== \"json\") {\n const groups = (result.googleGroups || []) as string[];\n const rows = groups.map((g: string) => ({ googleGroup: g }));\n if (rows.length > 0) {\n console.log(formatOutput(rows, format));\n } else {\n console.log(`No tester groups configured for ${options.track}.`);\n }\n } else {\n console.log(\n formatOutput(\n annotateListResult(\n { ...result, googleGroups: result.googleGroups ?? [] },\n \"googleGroups\",\n `No tester groups configured for ${options.track}.`,\n ),\n format,\n ),\n );\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (emails: string[], options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\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 const result = await addTesters(\n client,\n packageName,\n options.track,\n emails,\n buildCommitOptions(options),\n );\n console.log(formatOutput(result, format));\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (emails: string[], options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\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 const result = await removeTesters(\n client,\n packageName,\n options.track,\n emails,\n buildCommitOptions(options),\n );\n console.log(formatOutput(result, format));\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\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 const result = await importTestersFromCsv(\n client,\n packageName,\n options.track,\n options.file,\n buildCommitOptions(options),\n );\n console.log(formatOutput({ added: result.added, testers: result.testers }, format));\n });\n}\n"],"mappings":"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","names":[]}
@@ -16,10 +16,13 @@ import { loadConfig } from "@gpc-cli/config";
16
16
  import { resolveAuth } from "@gpc-cli/auth";
17
17
  import { createApiClient } from "@gpc-cli/api";
18
18
  import { listTracks, createTrack, updateTrackConfig, GpcError } from "@gpc-cli/core";
19
- import { formatOutput, maybePaginate } from "@gpc-cli/core";
19
+ import { formatOutput, maybePaginate, annotateListResult } from "@gpc-cli/core";
20
20
  function registerTracksCommands(program) {
21
21
  const tracks = program.command("tracks").description("Manage tracks");
22
- tracks.command("list").description("List all tracks").option("--limit <n>", "Maximum results to return").option("--next-page <token>", "Pagination token for next page").action(async (_options) => {
22
+ tracks.command("list").description("List all tracks").option("--limit <n>", "Accepted for consistency; tracks are returned in full (no pagination)").option(
23
+ "--next-page <token>",
24
+ "Accepted for consistency; tracks are returned in full (no pagination)"
25
+ ).action(async (_options) => {
23
26
  const config = await loadConfig();
24
27
  const packageName = program.opts()["app"] || config.app;
25
28
  if (!packageName) {
@@ -40,7 +43,16 @@ function registerTracksCommands(program) {
40
43
  latestStatus: t.releases?.[0]?.status || "none",
41
44
  latestVersion: t.releases?.[0]?.versionCodes?.[0] || "-"
42
45
  }));
43
- await maybePaginate(formatOutput(summary, format));
46
+ if (format === "json") {
47
+ console.log(
48
+ formatOutput(
49
+ annotateListResult({ tracks: summary }, "tracks", "No tracks found."),
50
+ format
51
+ )
52
+ );
53
+ } else {
54
+ await maybePaginate(formatOutput(summary, format));
55
+ }
44
56
  });
45
57
  tracks.command("create <name>").description("Create a custom track").option("--changes-not-sent-for-review", "Commit changes without sending for review").option("--error-if-in-review", "Fail if changes are already in review").action(async (name, options) => {
46
58
  const config = await loadConfig();
@@ -104,4 +116,4 @@ function registerTracksCommands(program) {
104
116
  export {
105
117
  registerTracksCommands
106
118
  };
107
- //# sourceMappingURL=tracks-N7KPBVPC.js.map
119
+ //# sourceMappingURL=tracks-E7RUNA3C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/tracks.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport { listTracks, createTrack, updateTrackConfig, GpcError } from \"@gpc-cli/core\";\nimport { formatOutput, maybePaginate, annotateListResult } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { buildCommitOptions } from \"../commit-options.js\";\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 .option(\"--limit <n>\", \"Accepted for consistency; tracks are returned in full (no pagination)\")\n .option(\n \"--next-page <token>\",\n \"Accepted for consistency; tracks are returned in full (no pagination)\",\n )\n .action(async (_options) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n throw new GpcError(\n \"No package name. Use --app <package> or gpc config set app <package>\",\n \"MISSING_PACKAGE\",\n 2,\n \"gpc config set app com.example.app\",\n );\n }\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const trackList = await listTracks(client, packageName);\n const format = getOutputFormat(program, config);\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 if (format === \"json\") {\n console.log(\n formatOutput(\n annotateListResult({ tracks: summary }, \"tracks\", \"No tracks found.\"),\n format,\n ),\n );\n } else {\n await maybePaginate(formatOutput(summary, format));\n }\n });\n\n tracks\n .command(\"create <name>\")\n .description(\"Create a custom track\")\n .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (name: string, options: Record<string, unknown>) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n throw new GpcError(\n \"No package name. Use --app <package> or gpc config set app <package>\",\n \"MISSING_PACKAGE\",\n 2,\n \"gpc config set app com.example.app\",\n );\n }\n\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"tracks create\", action: \"create custom track\", target: name },\n format,\n formatOutput,\n );\n return;\n }\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const track = await createTrack(client, packageName, name, buildCommitOptions(options));\n console.log(formatOutput(track, format));\n });\n\n tracks\n .command(\"update <name>\")\n .description(\"Update track configuration from a JSON file\")\n .requiredOption(\"--file <path>\", \"Path to JSON config file\")\n .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (name: string, options: { file: string } & Record<string, unknown>) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n throw new GpcError(\n \"No package name. Use --app <package> or gpc config set app <package>\",\n \"MISSING_PACKAGE\",\n 2,\n \"gpc config set app com.example.app\",\n );\n }\n\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"tracks update\", action: \"update track config from\", target: options.file },\n format,\n formatOutput,\n );\n return;\n }\n\n const raw = await readFile(options.file, \"utf-8\");\n const trackConfig = JSON.parse(raw) as Record<string, unknown>;\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const track = await updateTrackConfig(\n client,\n packageName,\n name,\n trackConfig,\n buildCommitOptions(options),\n );\n console.log(formatOutput(track, format));\n });\n}\n"],"mappings":"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","names":[]}
@@ -17,7 +17,7 @@ function registerUpdateCommand(program) {
17
17
  program.command("update").description("Update gpc to the latest version").option("--check", "Check for updates without installing (exits 0 always)").option("--force", "Update even if already on the latest version").action(async (opts, cmd) => {
18
18
  const parentOpts = cmd.parent?.opts() ?? {};
19
19
  const jsonMode = !!(parentOpts["json"] || parentOpts["output"] === "json");
20
- const currentVersion = "0.9.85";
20
+ const currentVersion = "0.9.87";
21
21
  if (currentVersion === "0.0.0") {
22
22
  if (jsonMode) {
23
23
  console.log(
@@ -172,4 +172,4 @@ Run: gpc update`);
172
172
  export {
173
173
  registerUpdateCommand
174
174
  };
175
- //# sourceMappingURL=update-JGLB2ELN.js.map
175
+ //# sourceMappingURL=update-UMNA6KMP.js.map
@@ -7,7 +7,7 @@ import "./chunk-3SJ6OXCZ.js";
7
7
  // src/commands/version.ts
8
8
  function registerVersionCommand(program) {
9
9
  program.command("version").description("Show version information").action(() => {
10
- const version = "0.9.85";
10
+ const version = "0.9.87";
11
11
  if (program.opts()["output"] === "json") {
12
12
  console.log(
13
13
  JSON.stringify({
@@ -25,4 +25,4 @@ function registerVersionCommand(program) {
25
25
  export {
26
26
  registerVersionCommand
27
27
  };
28
- //# sourceMappingURL=version-B4AE5NVE.js.map
28
+ //# sourceMappingURL=version-PFYWZWJC.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gpc-cli/cli",
3
- "version": "0.9.85",
4
- "description": "GPC — Google Play Console CLI. 217 API endpoints including Managed Google Play. Upload AABs, manage releases, monitor vitals, publish private enterprise apps. Fastlane alternative for Android.",
3
+ "version": "0.9.87",
4
+ "description": "GPC — Google Play Console CLI. 227 API endpoints including Managed Google Play. Upload AABs, manage releases, monitor vitals, publish private enterprise apps. Fastlane alternative for Android.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "gpc": "./dist/bin.js"
@@ -29,10 +29,10 @@
29
29
  "clean": "rm -rf dist"
30
30
  },
31
31
  "dependencies": {
32
- "@gpc-cli/api": "1.0.44",
32
+ "@gpc-cli/api": "1.0.45",
33
33
  "@gpc-cli/auth": "0.9.16",
34
- "@gpc-cli/config": "0.9.18",
35
- "@gpc-cli/core": "0.9.71",
34
+ "@gpc-cli/config": "0.9.19",
35
+ "@gpc-cli/core": "0.9.72",
36
36
  "@gpc-cli/plugin-sdk": "0.9.10",
37
37
  "commander": "^14.0.3"
38
38
  },
@@ -1,60 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- resolvePackageName
4
- } from "./chunk-JDRY7HK5.js";
5
- import {
6
- getOutputFormat
7
- } from "./chunk-ELXAK7GI.js";
8
-
9
- // src/commands/games.ts
10
- import { loadConfig } from "@gpc-cli/config";
11
- import { resolveAuth } from "@gpc-cli/auth";
12
- import { createGamesClient } from "@gpc-cli/api";
13
- import { listLeaderboards, listAchievements, listEvents, formatOutput } from "@gpc-cli/core";
14
- async function getGamesClient(config) {
15
- const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });
16
- return createGamesClient({ auth });
17
- }
18
- function registerGamesCommands(program) {
19
- const games = program.command("games").description("Manage Play Games Services \u2014 leaderboards, achievements, events");
20
- games.command("leaderboards").description("List leaderboards for the app").action(async () => {
21
- const config = await loadConfig();
22
- const packageName = resolvePackageName(program.opts()["app"], config);
23
- const client = await getGamesClient(config);
24
- const format = getOutputFormat(program, config);
25
- const result = await listLeaderboards(client, packageName);
26
- if (result.length === 0 && format !== "json") {
27
- console.log("No leaderboards found.");
28
- return;
29
- }
30
- console.log(formatOutput(result, format));
31
- });
32
- games.command("achievements").description("List achievements for the app").action(async () => {
33
- const config = await loadConfig();
34
- const packageName = resolvePackageName(program.opts()["app"], config);
35
- const client = await getGamesClient(config);
36
- const format = getOutputFormat(program, config);
37
- const result = await listAchievements(client, packageName);
38
- if (result.length === 0 && format !== "json") {
39
- console.log("No achievements found.");
40
- return;
41
- }
42
- console.log(formatOutput(result, format));
43
- });
44
- games.command("events").description("List events for the app").action(async () => {
45
- const config = await loadConfig();
46
- const packageName = resolvePackageName(program.opts()["app"], config);
47
- const client = await getGamesClient(config);
48
- const format = getOutputFormat(program, config);
49
- const result = await listEvents(client, packageName);
50
- if (result.length === 0 && format !== "json") {
51
- console.log("No events found.");
52
- return;
53
- }
54
- console.log(formatOutput(result, format));
55
- });
56
- }
57
- export {
58
- registerGamesCommands
59
- };
60
- //# sourceMappingURL=games-SVFN2YIS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/games.ts"],"sourcesContent":["import { resolvePackageName } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createGamesClient } from \"@gpc-cli/api\";\nimport { listLeaderboards, listAchievements, listEvents, formatOutput } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\n\nasync function getGamesClient(config: { auth?: { serviceAccount?: string } }) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createGamesClient({ auth });\n}\n\nexport function registerGamesCommands(program: Command): void {\n const games = program\n .command(\"games\")\n .description(\"Manage Play Games Services — leaderboards, achievements, events\");\n\n games\n .command(\"leaderboards\")\n .description(\"List leaderboards for the app\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getGamesClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listLeaderboards(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No leaderboards found.\");\n return;\n }\n console.log(formatOutput(result, format));\n });\n\n games\n .command(\"achievements\")\n .description(\"List achievements for the app\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getGamesClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listAchievements(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No achievements found.\");\n return;\n }\n console.log(formatOutput(result, format));\n });\n\n games\n .command(\"events\")\n .description(\"List events for the app\")\n .action(async () => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getGamesClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listEvents(client, packageName);\n if (result.length === 0 && format !== \"json\") {\n console.log(\"No events found.\");\n return;\n }\n console.log(formatOutput(result, format));\n });\n}\n"],"mappings":";;;;;;;;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,yBAAyB;AAClC,SAAS,kBAAkB,kBAAkB,YAAY,oBAAoB;AAG7E,eAAe,eAAe,QAAgD;AAC5E,QAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,SAAO,kBAAkB,EAAE,KAAK,CAAC;AACnC;AAEO,SAAS,sBAAsB,SAAwB;AAC5D,QAAM,QAAQ,QACX,QAAQ,OAAO,EACf,YAAY,sEAAiE;AAEhF,QACG,QAAQ,cAAc,EACtB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,eAAe,MAAM;AAC1C,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,UAAM,SAAS,MAAM,iBAAiB,QAAQ,WAAW;AACzD,QAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,cAAQ,IAAI,wBAAwB;AACpC;AAAA,IACF;AACA,YAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,EAC1C,CAAC;AAEH,QACG,QAAQ,cAAc,EACtB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,eAAe,MAAM;AAC1C,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,UAAM,SAAS,MAAM,iBAAiB,QAAQ,WAAW;AACzD,QAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,cAAQ,IAAI,wBAAwB;AACpC;AAAA,IACF;AACA,YAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,EAC1C,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,yBAAyB,EACrC,OAAO,YAAY;AAClB,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,mBAAmB,QAAQ,KAAK,EAAE,KAAK,GAAG,MAAM;AACpE,UAAM,SAAS,MAAM,eAAe,MAAM;AAC1C,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,UAAM,SAAS,MAAM,WAAW,QAAQ,WAAW;AACnD,QAAI,OAAO,WAAW,KAAK,WAAW,QAAQ;AAC5C,cAAQ,IAAI,kBAAkB;AAC9B;AAAA,IACF;AACA,YAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAAA,EAC1C,CAAC;AACL;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/grants.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 {\n listGrants,\n createGrant,\n updateGrant,\n deleteGrant,\n formatOutput,\n GpcError,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\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 throw new GpcError(\n \"No developer ID. Use --developer-id <id> or gpc config set developerId <id>\",\n \"MISSING_DEVELOPER_ID\",\n 2,\n \"gpc config set developerId <id>\",\n );\n }\n return id;\n}\n\nasync function getClient(config: GpcConfig) {\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n return createUsersClient({ auth });\n}\n\nexport function registerGrantsCommands(program: Command): void {\n const grants = program\n .command(\"grants\")\n .description(\"Manage per-app permission grants for developer account users\")\n .option(\"--developer-id <id>\", \"Developer account ID\");\n\n grants\n .command(\"list <email>\")\n .description(\"List all per-app grants for a user\")\n .action(async (email: string) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const client = await getClient(config);\n const format = getOutputFormat(program, config);\n\n const result = await listGrants(client, developerId, email);\n if (result.length === 0) {\n if (format === \"json\") {\n console.log(formatOutput([], format));\n } else {\n console.log(`No grants found for ${email}.`);\n }\n return;\n }\n console.log(formatOutput(result, format));\n });\n\n grants\n .command(\"create <email>\")\n .description(\"Grant app-level permissions to a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .requiredOption(\n \"--permissions <list>\",\n \"Comma-separated permissions (e.g. CAN_MANAGE_RELEASES,VIEW_APP_INFORMATION)\",\n )\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n const perms = (options.permissions as string).split(\",\").map((p: string) => p.trim());\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants create\",\n action: \"grant permissions\",\n target: `${email}/${options.package}`,\n details: { permissions: perms },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const result = await createGrant(client, developerId, email, options.package, perms);\n console.log(formatOutput(result, format));\n });\n\n grants\n .command(\"update <email>\")\n .description(\"Update app-level permissions for a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .requiredOption(\"--permissions <list>\", \"New comma-separated permissions\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n const perms = (options.permissions as string).split(\",\").map((p: string) => p.trim());\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants update\",\n action: \"update permissions\",\n target: `${email}/${options.package}`,\n details: { permissions: perms },\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n const result = await updateGrant(client, developerId, email, options.package, perms);\n console.log(formatOutput(result, format));\n });\n\n grants\n .command(\"delete <email>\")\n .description(\"Remove a per-app grant from a user\")\n .requiredOption(\"--package <packageName>\", \"App package name\")\n .action(async (email: string, options) => {\n const config = await loadConfig();\n const developerId = resolveDeveloperId(grants.opts()[\"developerId\"], config);\n const format = getOutputFormat(program, config);\n\n await requireConfirm(`Remove grant for \"${email}\" on ${options.package}?`, program);\n\n if (isDryRun(program)) {\n printDryRun(\n {\n command: \"grants delete\",\n action: \"remove grant\",\n target: `${email}/${options.package}`,\n },\n format,\n formatOutput,\n );\n return;\n }\n\n const client = await getClient(config);\n\n await deleteGrant(client, developerId, email, options.package);\n console.log(`Grant removed for ${email} on ${options.package}.`);\n });\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/testers.ts"],"sourcesContent":["import { resolvePackageName, getClient } from \"../resolve.js\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport {\n listTesters,\n addTesters,\n removeTesters,\n importTestersFromCsv,\n formatOutput,\n} from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { isInteractive, requireOption, requireConfirm } from \"../prompt.js\";\nimport { buildCommitOptions } from \"../commit-options.js\";\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 .option(\"--sort <field>\", \"Sort by field (prefix with - for descending, e.g., email or -email)\")\n .option(\"--limit <n>\", \"Maximum results to return\")\n .option(\"--next-page <token>\", \"Pagination token for next page\")\n .action(async (options) => {\n const config = await loadConfig();\n const 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 = getOutputFormat(program, config);\n\n const result = await listTesters(client, packageName, options.track);\n if (options.sort && result.googleGroups) {\n const descending = options.sort.startsWith(\"-\");\n result.googleGroups = [...result.googleGroups].sort((a: string, b: string) =>\n descending ? b.localeCompare(a) : a.localeCompare(b),\n );\n }\n if (format !== \"json\") {\n const groups = (result.googleGroups || []) as string[];\n const rows = groups.map((g: string) => ({ googleGroup: g }));\n if (rows.length > 0) {\n console.log(formatOutput(rows, format));\n } else {\n console.log(\"No testers found.\");\n }\n } else {\n console.log(formatOutput(result, format));\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (emails: string[], options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\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 const result = await addTesters(\n client,\n packageName,\n options.track,\n emails,\n buildCommitOptions(options),\n );\n console.log(formatOutput(result, format));\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (emails: string[], options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\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 const result = await removeTesters(\n client,\n packageName,\n options.track,\n emails,\n buildCommitOptions(options),\n );\n console.log(formatOutput(result, format));\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 .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (options) => {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const format = getOutputFormat(program, config);\n const interactive = isInteractive(program);\n\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 const result = await importTestersFromCsv(\n client,\n packageName,\n options.track,\n options.file,\n buildCommitOptions(options),\n );\n console.log(formatOutput({ added: result.added, testers: result.testers }, format));\n });\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/tracks.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport { listTracks, createTrack, updateTrackConfig, GpcError } from \"@gpc-cli/core\";\nimport { formatOutput, maybePaginate } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { isDryRun, printDryRun } from \"../dry-run.js\";\nimport { buildCommitOptions } from \"../commit-options.js\";\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 .option(\"--limit <n>\", \"Maximum results to return\")\n .option(\"--next-page <token>\", \"Pagination token for next page\")\n .action(async (_options) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n throw new GpcError(\n \"No package name. Use --app <package> or gpc config set app <package>\",\n \"MISSING_PACKAGE\",\n 2,\n \"gpc config set app com.example.app\",\n );\n }\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const trackList = await listTracks(client, packageName);\n const format = getOutputFormat(program, config);\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 await maybePaginate(formatOutput(summary, format));\n });\n\n tracks\n .command(\"create <name>\")\n .description(\"Create a custom track\")\n .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (name: string, options: Record<string, unknown>) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n throw new GpcError(\n \"No package name. Use --app <package> or gpc config set app <package>\",\n \"MISSING_PACKAGE\",\n 2,\n \"gpc config set app com.example.app\",\n );\n }\n\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"tracks create\", action: \"create custom track\", target: name },\n format,\n formatOutput,\n );\n return;\n }\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const track = await createTrack(client, packageName, name, buildCommitOptions(options));\n console.log(formatOutput(track, format));\n });\n\n tracks\n .command(\"update <name>\")\n .description(\"Update track configuration from a JSON file\")\n .requiredOption(\"--file <path>\", \"Path to JSON config file\")\n .option(\"--changes-not-sent-for-review\", \"Commit changes without sending for review\")\n .option(\"--error-if-in-review\", \"Fail if changes are already in review\")\n .action(async (name: string, options: { file: string } & Record<string, unknown>) => {\n const config = await loadConfig();\n const packageName = program.opts()[\"app\"] || config.app;\n if (!packageName) {\n throw new GpcError(\n \"No package name. Use --app <package> or gpc config set app <package>\",\n \"MISSING_PACKAGE\",\n 2,\n \"gpc config set app com.example.app\",\n );\n }\n\n const format = getOutputFormat(program, config);\n\n if (isDryRun(program)) {\n printDryRun(\n { command: \"tracks update\", action: \"update track config from\", target: options.file },\n format,\n formatOutput,\n );\n return;\n }\n\n const raw = await readFile(options.file, \"utf-8\");\n const trackConfig = JSON.parse(raw) as Record<string, unknown>;\n\n const auth = await resolveAuth({ serviceAccountPath: config.auth?.serviceAccount });\n const client = createApiClient({ auth });\n const track = await updateTrackConfig(\n client,\n packageName,\n name,\n trackConfig,\n buildCommitOptions(options),\n );\n console.log(formatOutput(track, format));\n });\n}\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,gBAAgB;AAEzB,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,YAAY,aAAa,mBAAmB,gBAAgB;AACrE,SAAS,cAAc,qBAAqB;AAKrC,SAAS,uBAAuB,SAAwB;AAC7D,QAAM,SAAS,QAAQ,QAAQ,QAAQ,EAAE,YAAY,eAAe;AAEpE,SACG,QAAQ,MAAM,EACd,YAAY,iBAAiB,EAC7B,OAAO,eAAe,2BAA2B,EACjD,OAAO,uBAAuB,gCAAgC,EAC9D,OAAO,OAAO,aAAa;AAC1B,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,QAAQ,KAAK,EAAE,KAAK,KAAK,OAAO;AACpD,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,UAAM,SAAS,gBAAgB,EAAE,KAAK,CAAC;AACvC,UAAM,YAAY,MAAM,WAAW,QAAQ,WAAW;AACtD,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,UAAM,UAAU,UAAU,IAAI,CAAC,OAAO;AAAA,MACpC,OAAO,EAAE;AAAA,MACT,UAAU,EAAE,UAAU,UAAU;AAAA,MAChC,cAAc,EAAE,WAAW,CAAC,GAAG,UAAU;AAAA,MACzC,eAAe,EAAE,WAAW,CAAC,GAAG,eAAe,CAAC,KAAK;AAAA,IACvD,EAAE;AAEF,UAAM,cAAc,aAAa,SAAS,MAAM,CAAC;AAAA,EACnD,CAAC;AAEH,SACG,QAAQ,eAAe,EACvB,YAAY,uBAAuB,EACnC,OAAO,iCAAiC,2CAA2C,EACnF,OAAO,wBAAwB,uCAAuC,EACtE,OAAO,OAAO,MAAc,YAAqC;AAChE,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,QAAQ,KAAK,EAAE,KAAK,KAAK,OAAO;AACpD,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI,SAAS,OAAO,GAAG;AACrB;AAAA,QACE,EAAE,SAAS,iBAAiB,QAAQ,uBAAuB,QAAQ,KAAK;AAAA,QACxE;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,UAAM,SAAS,gBAAgB,EAAE,KAAK,CAAC;AACvC,UAAM,QAAQ,MAAM,YAAY,QAAQ,aAAa,MAAM,mBAAmB,OAAO,CAAC;AACtF,YAAQ,IAAI,aAAa,OAAO,MAAM,CAAC;AAAA,EACzC,CAAC;AAEH,SACG,QAAQ,eAAe,EACvB,YAAY,6CAA6C,EACzD,eAAe,iBAAiB,0BAA0B,EAC1D,OAAO,iCAAiC,2CAA2C,EACnF,OAAO,wBAAwB,uCAAuC,EACtE,OAAO,OAAO,MAAc,YAAwD;AACnF,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,cAAc,QAAQ,KAAK,EAAE,KAAK,KAAK,OAAO;AACpD,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,gBAAgB,SAAS,MAAM;AAE9C,QAAI,SAAS,OAAO,GAAG;AACrB;AAAA,QACE,EAAE,SAAS,iBAAiB,QAAQ,4BAA4B,QAAQ,QAAQ,KAAK;AAAA,QACrF;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,MAAM,MAAM,SAAS,QAAQ,MAAM,OAAO;AAChD,UAAM,cAAc,KAAK,MAAM,GAAG;AAElC,UAAM,OAAO,MAAM,YAAY,EAAE,oBAAoB,OAAO,MAAM,eAAe,CAAC;AAClF,UAAM,SAAS,gBAAgB,EAAE,KAAK,CAAC;AACvC,UAAM,QAAQ,MAAM;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,OAAO;AAAA,IAC5B;AACA,YAAQ,IAAI,aAAa,OAAO,MAAM,CAAC;AAAA,EACzC,CAAC;AACL;","names":[]}