@gpc-cli/cli 0.1.3 → 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.
- package/README.md +21 -21
- package/dist/{apps-BBYNHB2H.js → apps-TZG5GEDW.js} +9 -7
- package/dist/apps-TZG5GEDW.js.map +1 -0
- package/dist/{auth-T7IDSMVX.js → auth-CIITFC3C.js} +4 -2
- package/dist/auth-CIITFC3C.js.map +1 -0
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-IVVT73IP.js → chunk-22DW4R5W.js} +31 -26
- package/dist/chunk-22DW4R5W.js.map +1 -0
- package/dist/{chunk-4QV4WD3F.js → chunk-Q7KVGI46.js} +9 -7
- package/dist/chunk-Q7KVGI46.js.map +1 -0
- package/dist/{chunk-QMKZYXDJ.js → chunk-Y3QZDAKS.js} +2 -2
- package/dist/chunk-Y3QZDAKS.js.map +1 -0
- package/dist/{completion-U44CGHRH.js → completion-IHVLP7OK.js} +1 -1
- package/dist/completion-IHVLP7OK.js.map +1 -0
- package/dist/{config-K7UJKIXT.js → config-7QKUVNZZ.js} +8 -4
- package/dist/config-7QKUVNZZ.js.map +1 -0
- package/dist/{doctor-VDDUPTIM.js → doctor-KVP7PGZU.js} +5 -3
- package/dist/doctor-KVP7PGZU.js.map +1 -0
- package/dist/{iap-QIV4CXKZ.js → iap-Z365AMDD.js} +37 -25
- package/dist/iap-Z365AMDD.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{listings-PF5FDXKQ.js → listings-U3T6NFVH.js} +128 -68
- package/dist/listings-U3T6NFVH.js.map +1 -0
- package/dist/{pricing-S4SB5FXJ.js → pricing-LXIRB4R7.js} +21 -15
- package/dist/pricing-LXIRB4R7.js.map +1 -0
- package/dist/{prompt-VP5LURRP.js → prompt-ASDQX6LZ.js} +2 -2
- package/dist/{publish-3BAIN4NQ.js → publish-HKOJVZ23.js} +27 -16
- package/dist/publish-HKOJVZ23.js.map +1 -0
- package/dist/{purchases-E6A2T5WQ.js → purchases-ZQ7FXEZQ.js} +84 -49
- package/dist/purchases-ZQ7FXEZQ.js.map +1 -0
- package/dist/{releases-464IMEEF.js → releases-IZJJYTNZ.js} +103 -51
- package/dist/releases-IZJJYTNZ.js.map +1 -0
- package/dist/{reports-3YAD4U4F.js → reports-43OVCCU3.js} +83 -29
- package/dist/reports-43OVCCU3.js.map +1 -0
- package/dist/{reviews-2CLM53E3.js → reviews-T3SRAZLW.js} +25 -16
- package/dist/reviews-T3SRAZLW.js.map +1 -0
- package/dist/{status-M7U3YNMU.js → status-TBPVS7YR.js} +5 -3
- package/dist/status-TBPVS7YR.js.map +1 -0
- package/dist/{subscriptions-PUHH4FBB.js → subscriptions-UJUX3ELS.js} +201 -130
- package/dist/subscriptions-UJUX3ELS.js.map +1 -0
- package/dist/{testers-WWZMLB7J.js → testers-YNOGFHUR.js} +81 -44
- package/dist/testers-YNOGFHUR.js.map +1 -0
- package/dist/{tracks-427E34S3.js → tracks-HMJ3F55N.js} +5 -3
- package/dist/tracks-HMJ3F55N.js.map +1 -0
- package/dist/{users-E5Y5HI6K.js → users-GRQTY6HY.js} +48 -28
- package/dist/users-GRQTY6HY.js.map +1 -0
- package/dist/{vitals-YMZMUPNA.js → vitals-VP2GKG3G.js} +23 -9
- package/dist/vitals-VP2GKG3G.js.map +1 -0
- package/package.json +5 -5
- package/dist/apps-BBYNHB2H.js.map +0 -1
- package/dist/auth-T7IDSMVX.js.map +0 -1
- package/dist/chunk-4QV4WD3F.js.map +0 -1
- package/dist/chunk-IVVT73IP.js.map +0 -1
- package/dist/chunk-QMKZYXDJ.js.map +0 -1
- package/dist/completion-U44CGHRH.js.map +0 -1
- package/dist/config-K7UJKIXT.js.map +0 -1
- package/dist/doctor-VDDUPTIM.js.map +0 -1
- package/dist/iap-QIV4CXKZ.js.map +0 -1
- package/dist/listings-PF5FDXKQ.js.map +0 -1
- package/dist/pricing-S4SB5FXJ.js.map +0 -1
- package/dist/publish-3BAIN4NQ.js.map +0 -1
- package/dist/purchases-E6A2T5WQ.js.map +0 -1
- package/dist/releases-464IMEEF.js.map +0 -1
- package/dist/reports-3YAD4U4F.js.map +0 -1
- package/dist/reviews-2CLM53E3.js.map +0 -1
- package/dist/status-M7U3YNMU.js.map +0 -1
- package/dist/subscriptions-PUHH4FBB.js.map +0 -1
- package/dist/testers-WWZMLB7J.js.map +0 -1
- package/dist/tracks-427E34S3.js.map +0 -1
- package/dist/users-E5Y5HI6K.js.map +0 -1
- package/dist/vitals-YMZMUPNA.js.map +0 -1
- /package/dist/{prompt-VP5LURRP.js.map → prompt-ASDQX6LZ.js.map} +0 -0
package/README.md
CHANGED
|
@@ -38,18 +38,18 @@ gpc reviews list --stars 1-3 --since 7d
|
|
|
38
38
|
|
|
39
39
|
162 API endpoints across 10 command groups:
|
|
40
40
|
|
|
41
|
-
| Command Group
|
|
42
|
-
|
|
43
|
-
| **Releases**
|
|
44
|
-
| **Listings**
|
|
45
|
-
| **Reviews**
|
|
46
|
-
| **Vitals**
|
|
47
|
-
| **Subscriptions** | `list`, `create`, `base-plans`, `offers`
|
|
48
|
-
| **IAP**
|
|
49
|
-
| **Purchases**
|
|
50
|
-
| **Reports**
|
|
51
|
-
| **Testers**
|
|
52
|
-
| **Users**
|
|
41
|
+
| Command Group | Examples |
|
|
42
|
+
| ----------------- | -------------------------------------------------------------- |
|
|
43
|
+
| **Releases** | `upload`, `promote`, `rollout increase/halt/resume`, `publish` |
|
|
44
|
+
| **Listings** | `pull`, `push`, `images upload/delete`, Fastlane format |
|
|
45
|
+
| **Reviews** | `list`, `reply`, `export --format csv` |
|
|
46
|
+
| **Vitals** | `crashes`, `anr`, `startup`, `rendering`, `battery`, `memory` |
|
|
47
|
+
| **Subscriptions** | `list`, `create`, `base-plans`, `offers` |
|
|
48
|
+
| **IAP** | `list`, `create`, `sync --dir products/` |
|
|
49
|
+
| **Purchases** | `get`, `acknowledge`, `cancel`, `refund` |
|
|
50
|
+
| **Reports** | `download financial`, `download stats` |
|
|
51
|
+
| **Testers** | `add`, `remove`, `import --file testers.csv` |
|
|
52
|
+
| **Users** | `invite`, `update`, `remove`, per-app grants |
|
|
53
53
|
|
|
54
54
|
## CI/CD
|
|
55
55
|
|
|
@@ -81,15 +81,15 @@ Full docs at **[yasserstudio.github.io/gpc](https://yasserstudio.github.io/gpc/)
|
|
|
81
81
|
|
|
82
82
|
## Part of the GPC Monorepo
|
|
83
83
|
|
|
84
|
-
| Package
|
|
85
|
-
|
|
86
|
-
| **@gpc-cli/cli**
|
|
87
|
-
| [@gpc-cli/core](https://www.npmjs.com/package/@gpc-cli/core)
|
|
88
|
-
| [@gpc-cli/api](https://www.npmjs.com/package/@gpc-cli/api)
|
|
89
|
-
| [@gpc-cli/auth](https://www.npmjs.com/package/@gpc-cli/auth)
|
|
90
|
-
| [@gpc-cli/config](https://www.npmjs.com/package/@gpc-cli/config)
|
|
91
|
-
| [@gpc-cli/plugin-sdk](https://www.npmjs.com/package/@gpc-cli/plugin-sdk) | Plugin interface and lifecycle hooks
|
|
92
|
-
| [@gpc-cli/plugin-ci](https://www.npmjs.com/package/@gpc-cli/plugin-ci)
|
|
84
|
+
| Package | Description |
|
|
85
|
+
| ------------------------------------------------------------------------ | -------------------------------------------- |
|
|
86
|
+
| **@gpc-cli/cli** | CLI entry point (this package) |
|
|
87
|
+
| [@gpc-cli/core](https://www.npmjs.com/package/@gpc-cli/core) | Business logic and orchestration |
|
|
88
|
+
| [@gpc-cli/api](https://www.npmjs.com/package/@gpc-cli/api) | Typed Google Play API v3 client |
|
|
89
|
+
| [@gpc-cli/auth](https://www.npmjs.com/package/@gpc-cli/auth) | Authentication (service account, OAuth, ADC) |
|
|
90
|
+
| [@gpc-cli/config](https://www.npmjs.com/package/@gpc-cli/config) | Configuration and profiles |
|
|
91
|
+
| [@gpc-cli/plugin-sdk](https://www.npmjs.com/package/@gpc-cli/plugin-sdk) | Plugin interface and lifecycle hooks |
|
|
92
|
+
| [@gpc-cli/plugin-ci](https://www.npmjs.com/package/@gpc-cli/plugin-ci) | CI/CD helpers |
|
|
93
93
|
|
|
94
94
|
## License
|
|
95
95
|
|
|
@@ -32,19 +32,21 @@ function registerAppsCommands(program) {
|
|
|
32
32
|
});
|
|
33
33
|
apps.command("update").description("Update app details").option("--email <email>", "Contact email").option("--phone <phone>", "Contact phone").option("--website <url>", "Contact website").option("--default-lang <lang>", "Default language").action(async (options) => {
|
|
34
34
|
const config = await loadConfig();
|
|
35
|
-
const packageName = options
|
|
35
|
+
const packageName = options["app"] || program.opts()["app"] || config.app;
|
|
36
36
|
if (!packageName) {
|
|
37
37
|
console.error("Error: No package name provided.");
|
|
38
38
|
console.error("Usage: gpc apps update --email user@example.com");
|
|
39
39
|
process.exit(2);
|
|
40
40
|
}
|
|
41
41
|
const data = {};
|
|
42
|
-
if (options
|
|
43
|
-
if (options
|
|
44
|
-
if (options
|
|
45
|
-
if (options
|
|
42
|
+
if (options["email"]) data["contactEmail"] = options["email"];
|
|
43
|
+
if (options["phone"]) data["contactPhone"] = options["phone"];
|
|
44
|
+
if (options["website"]) data["contactWebsite"] = options["website"];
|
|
45
|
+
if (options["defaultLang"]) data["defaultLanguage"] = options["defaultLang"];
|
|
46
46
|
if (Object.keys(data).length === 0) {
|
|
47
|
-
console.error(
|
|
47
|
+
console.error(
|
|
48
|
+
"Error: Provide at least one field to update (--email, --phone, --website, --default-lang)."
|
|
49
|
+
);
|
|
48
50
|
process.exit(2);
|
|
49
51
|
}
|
|
50
52
|
try {
|
|
@@ -80,4 +82,4 @@ function registerAppsCommands(program) {
|
|
|
80
82
|
export {
|
|
81
83
|
registerAppsCommands
|
|
82
84
|
};
|
|
83
|
-
//# sourceMappingURL=apps-
|
|
85
|
+
//# sourceMappingURL=apps-TZG5GEDW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/apps.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient } from \"@gpc-cli/api\";\nimport { getAppInfo, updateAppDetails } from \"@gpc-cli/core\";\nimport { detectOutputFormat, formatOutput } from \"@gpc-cli/core\";\n\nexport function registerAppsCommands(program: Command): void {\n const apps = program.command(\"apps\").description(\"Manage applications\");\n\n apps\n .command(\"info [package]\")\n .description(\"Show app details\")\n .action(async (packageArg?: string) => {\n const config = await loadConfig();\n const packageName = packageArg || config.app;\n\n if (!packageName) {\n console.error(\"Error: No package name provided.\");\n console.error(\"Usage: gpc apps info <package>\");\n console.error(\"Or set a default: gpc config set app com.example.app\");\n process.exit(2);\n }\n\n try {\n const auth = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n });\n const client = createApiClient({ auth });\n const info = await getAppInfo(client, packageName);\n const format = 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(\n \"Error: Provide at least one field to update (--email, --phone, --website, --default-lang).\",\n );\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"]}
|
|
@@ -113,7 +113,9 @@ function registerAuthCommands(program) {
|
|
|
113
113
|
const profiles = await listProfiles();
|
|
114
114
|
const format = detectOutputFormat();
|
|
115
115
|
if (profiles.length === 0) {
|
|
116
|
-
console.log(
|
|
116
|
+
console.log(
|
|
117
|
+
"No profiles configured. Use: gpc auth login --service-account <path> --profile <name>"
|
|
118
|
+
);
|
|
117
119
|
return;
|
|
118
120
|
}
|
|
119
121
|
const data = profiles.map((name) => ({
|
|
@@ -126,4 +128,4 @@ function registerAuthCommands(program) {
|
|
|
126
128
|
export {
|
|
127
129
|
registerAuthCommands
|
|
128
130
|
};
|
|
129
|
-
//# sourceMappingURL=auth-
|
|
131
|
+
//# sourceMappingURL=auth-CIITFC3C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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.command(\"auth\").description(\"Manage authentication\");\n\n auth\n .command(\"login\")\n .description(\"Authenticate with Google Play Developer API\")\n .option(\"--service-account <path>\", \"Path to service account JSON key file\")\n .option(\"--adc\", \"Use Application Default Credentials\")\n .option(\"--profile <name>\", \"Store credentials under a named profile\")\n .action(async (options: { serviceAccount?: string; adc?: boolean; profile?: string }) => {\n try {\n if (options.serviceAccount) {\n const key = await loadServiceAccountKey(options.serviceAccount);\n\n if (options.profile) {\n const { setProfileConfig } = await import(\"@gpc-cli/config\");\n await setProfileConfig(options.profile, {\n auth: { serviceAccount: options.serviceAccount },\n });\n console.log(`Profile \"${options.profile}\" configured with ${key.client_email}`);\n } else {\n const { setConfigValue } = await import(\"@gpc-cli/config\");\n await setConfigValue(\"auth.serviceAccount\", options.serviceAccount);\n console.log(`Authenticated as ${key.client_email}`);\n }\n console.log(`Project: ${key.project_id}`);\n } else if (options.adc) {\n const client = await resolveAuth();\n console.log(`Authenticated via Application Default Credentials`);\n console.log(`Account: ${client.getClientEmail()}`);\n } else {\n 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(\n \"No profiles configured. Use: gpc auth login --service-account <path> --profile <name>\",\n );\n return;\n }\n\n const data = profiles.map((name) => ({\n name,\n active: name === config.profile,\n }));\n console.log(formatOutput(data, format));\n });\n}\n"],"mappings":";;;AACA,SAAS,aAAa,uBAAuB,iBAAiB,iBAAiB;AAC/E,SAAS,YAAY,mBAAmB;AACxC,SAAS,oBAAoB,oBAAoB;AAE1C,SAAS,qBAAqB,SAAwB;AAC3D,QAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,YAAY,uBAAuB;AAExE,OACG,QAAQ,OAAO,EACf,YAAY,6CAA6C,EACzD,OAAO,4BAA4B,uCAAuC,EAC1E,OAAO,SAAS,qCAAqC,EACrD,OAAO,oBAAoB,yCAAyC,EACpE,OAAO,OAAO,YAA0E;AACvF,QAAI;AACF,UAAI,QAAQ,gBAAgB;AAC1B,cAAM,MAAM,MAAM,sBAAsB,QAAQ,cAAc;AAE9D,YAAI,QAAQ,SAAS;AACnB,gBAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,iBAAiB;AAC3D,gBAAM,iBAAiB,QAAQ,SAAS;AAAA,YACtC,MAAM,EAAE,gBAAgB,QAAQ,eAAe;AAAA,UACjD,CAAC;AACD,kBAAQ,IAAI,YAAY,QAAQ,OAAO,qBAAqB,IAAI,YAAY,EAAE;AAAA,QAChF,OAAO;AACL,gBAAM,EAAE,eAAe,IAAI,MAAM,OAAO,iBAAiB;AACzD,gBAAM,eAAe,uBAAuB,QAAQ,cAAc;AAClE,kBAAQ,IAAI,oBAAoB,IAAI,YAAY,EAAE;AAAA,QACpD;AACA,gBAAQ,IAAI,YAAY,IAAI,UAAU,EAAE;AAAA,MAC1C,WAAW,QAAQ,KAAK;AACtB,cAAM,SAAS,MAAM,YAAY;AACjC,gBAAQ,IAAI,mDAAmD;AAC/D,gBAAQ,IAAI,YAAY,OAAO,eAAe,CAAC,EAAE;AAAA,MACnD,OAAO;AACL,gBAAQ,IAAI,gDAAgD;AAC5D,gBAAQ,IAAI,EAAE;AACd,gBAAQ,IAAI,yBAAyB;AACrC,gBAAQ,IAAI,2DAA2D;AACvE,gBAAQ,IAAI,6DAA6D;AACzE,gBAAQ,IAAI,EAAE;AACd,gBAAQ,IAAI,UAAU;AACtB,gBAAQ,IAAI,yDAAyD;AAAA,MACvE;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,WAAW;AAC9B,gBAAQ,MAAM,UAAU,MAAM,OAAO,EAAE;AACvC,YAAI,MAAM,WAAY,SAAQ,MAAM,eAAe,MAAM,UAAU,EAAE;AACrE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM;AAAA,IACR;AAAA,EACF,CAAC;AAEH,OACG,QAAQ,QAAQ,EAChB,YAAY,oCAAoC,EAChD,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAAS,MAAM,WAAW;AAChC,YAAM,SAAS,MAAM,YAAY;AAAA,QAC/B,oBAAoB,OAAO,MAAM;AAAA,QACjC,WAAW,YAAY;AAAA,MACzB,CAAC;AACD,YAAM,SAAS,mBAAmB;AAClC,YAAM,OAAO;AAAA,QACX,eAAe;AAAA,QACf,SAAS,OAAO,eAAe;AAAA,QAC/B,SAAS,OAAO,aAAa;AAAA,QAC7B,GAAI,OAAO,WAAW,EAAE,SAAS,OAAO,QAAQ;AAAA,MAClD;AACA,cAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AAAA,IACxC,SAAS,OAAO;AACd,UAAI,iBAAiB,WAAW;AAC9B,cAAM,SAAS,mBAAmB;AAClC,cAAM,OAAO;AAAA,UACX,eAAe;AAAA,UACf,OAAO,MAAM;AAAA,UACb,YAAY,MAAM;AAAA,QACpB;AACA,gBAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AACtC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,YAAM;AAAA,IACR;AAAA,EACF,CAAC;AAEH,OACG,QAAQ,QAAQ,EAChB,YAAY,0CAA0C,EACtD,OAAO,YAAY;AAClB,UAAM,EAAE,eAAe,IAAI,MAAM,OAAO,iBAAiB;AACzD,UAAM,eAAe,uBAAuB,EAAE;AAC9C,UAAM,gBAAgB,YAAY,CAAC;AACnC,YAAQ,IAAI,sCAAsC;AAAA,EACpD,CAAC;AAEH,OACG,QAAQ,QAAQ,EAChB,YAAY,qCAAqC,EACjD,OAAO,YAAY;AAClB,QAAI;AACF,YAAM,SAAS,MAAM,WAAW;AAChC,YAAM,SAAS,MAAM,YAAY;AAAA,QAC/B,oBAAoB,OAAO,MAAM;AAAA,QACjC,WAAW,YAAY;AAAA,MACzB,CAAC;AACD,cAAQ,IAAI,OAAO,eAAe,CAAC;AAAA,IACrC,QAAQ;AACN,cAAQ,MAAM,wCAAwC;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,OACG,QAAQ,kBAAkB,EAC1B,YAAY,2BAA2B,EACvC,OAAO,OAAO,YAAoB;AACjC,QAAI;AAEF,YAAM,SAAS,MAAM,WAAW,EAAE,QAAQ,CAAC;AAC3C,YAAM,EAAE,eAAe,IAAI,MAAM,OAAO,iBAAiB;AACzD,YAAM,eAAe,WAAW,OAAO;AACvC,cAAQ,IAAI,wBAAwB,OAAO,GAAG;AAC9C,UAAI,OAAO,MAAM,gBAAgB;AAC/B,gBAAQ,IAAI,oBAAoB,OAAO,KAAK,cAAc,EAAE;AAAA,MAC9D;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAChF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,OACG,QAAQ,UAAU,EAClB,YAAY,0BAA0B,EACtC,OAAO,YAAY;AAClB,UAAM,EAAE,aAAa,IAAI,MAAM,OAAO,iBAAiB;AACvD,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,WAAW,MAAM,aAAa;AACpC,UAAM,SAAS,mBAAmB;AAElC,QAAI,SAAS,WAAW,GAAG;AACzB,cAAQ;AAAA,QACN;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,OAAO,SAAS,IAAI,CAAC,UAAU;AAAA,MACnC;AAAA,MACA,QAAQ,SAAS,OAAO;AAAA,IAC1B,EAAE;AACF,YAAQ,IAAI,aAAa,MAAM,MAAM,CAAC;AAAA,EACxC,CAAC;AACL;","names":[]}
|
package/dist/bin.js
CHANGED
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/networking.ts","../src/bin.ts"],"sourcesContent":["/**\n * Set up proxy and custom CA certificate support.\n * Must be called before any fetch() calls.\n */\nexport async function setupNetworking(): Promise<void> {\n // Map GPC_CA_CERT to NODE_EXTRA_CA_CERTS (works in both Node and Bun)\n const caCert = process.env[\"GPC_CA_CERT\"];\n if (caCert && !process.env[\"NODE_EXTRA_CA_CERTS\"]) {\n process.env[\"NODE_EXTRA_CA_CERTS\"] = caCert;\n }\n\n // In standalone binary mode, Bun handles HTTPS_PROXY/HTTP_PROXY natively\n if (process.env[\"__GPC_BINARY\"] === \"1\") return;\n\n const proxyUrl
|
|
1
|
+
{"version":3,"sources":["../src/networking.ts","../src/bin.ts"],"sourcesContent":["/**\n * Set up proxy and custom CA certificate support.\n * Must be called before any fetch() calls.\n */\nexport async function setupNetworking(): Promise<void> {\n // Map GPC_CA_CERT to NODE_EXTRA_CA_CERTS (works in both Node and Bun)\n const caCert = process.env[\"GPC_CA_CERT\"];\n if (caCert && !process.env[\"NODE_EXTRA_CA_CERTS\"]) {\n process.env[\"NODE_EXTRA_CA_CERTS\"] = caCert;\n }\n\n // In standalone binary mode, Bun handles HTTPS_PROXY/HTTP_PROXY natively\n if (process.env[\"__GPC_BINARY\"] === \"1\") return;\n\n const proxyUrl =\n process.env[\"HTTPS_PROXY\"] ||\n process.env[\"https_proxy\"] ||\n process.env[\"HTTP_PROXY\"] ||\n process.env[\"http_proxy\"];\n if (proxyUrl) {\n try {\n // @ts-expect-error undici types not available in all environments\n const { ProxyAgent, setGlobalDispatcher } = await import(\"undici\");\n setGlobalDispatcher(new ProxyAgent(proxyUrl));\n } catch {\n console.error(\"Warning: Proxy support requires Node.js 20+. HTTPS_PROXY will be ignored.\");\n }\n }\n}\n","import { setupNetworking } from \"./networking.js\";\nimport { createProgram } from \"./program.js\";\nimport { loadPlugins } from \"./plugins.js\";\nimport { initAudit } from \"@gpc-cli/core\";\nimport { getConfigDir } from \"@gpc-cli/config\";\n\nawait setupNetworking();\ninitAudit(getConfigDir());\nconst pluginManager = await loadPlugins();\nconst program = await createProgram(pluginManager);\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(1);\n});\n"],"mappings":";;;;;;;AAIA,eAAsB,kBAAiC;AAErD,QAAM,SAAS,QAAQ,IAAI,aAAa;AACxC,MAAI,UAAU,CAAC,QAAQ,IAAI,qBAAqB,GAAG;AACjD,YAAQ,IAAI,qBAAqB,IAAI;AAAA,EACvC;AAGA,MAAI,QAAQ,IAAI,cAAc,MAAM,IAAK;AAEzC,QAAM,WACJ,QAAQ,IAAI,aAAa,KACzB,QAAQ,IAAI,aAAa,KACzB,QAAQ,IAAI,YAAY,KACxB,QAAQ,IAAI,YAAY;AAC1B,MAAI,UAAU;AACZ,QAAI;AAEF,YAAM,EAAE,YAAY,oBAAoB,IAAI,MAAM,OAAO,QAAQ;AACjE,0BAAoB,IAAI,WAAW,QAAQ,CAAC;AAAA,IAC9C,QAAQ;AACN,cAAQ,MAAM,2EAA2E;AAAA,IAC3F;AAAA,EACF;AACF;;;ACzBA,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAE7B,MAAM,gBAAgB;AACtB,UAAU,aAAa,CAAC;AACxB,IAAM,gBAAgB,MAAM,YAAY;AACxC,IAAM,UAAU,MAAM,cAAc,aAAa;AACjD,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,UAAmB;AACzD,UAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACpE,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
|
@@ -43,7 +43,11 @@ function registerPluginCommands(program, manager) {
|
|
|
43
43
|
}
|
|
44
44
|
if (def.options) {
|
|
45
45
|
for (const opt of def.options) {
|
|
46
|
-
cmd.option(
|
|
46
|
+
cmd.option(
|
|
47
|
+
opt.flags,
|
|
48
|
+
opt.description,
|
|
49
|
+
opt.defaultValue
|
|
50
|
+
);
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
cmd.action(async (...rawArgs) => {
|
|
@@ -66,77 +70,78 @@ async function createProgram(pluginManager) {
|
|
|
66
70
|
program.name("gpc").description("The complete Google Play CLI").version(process.env["__GPC_VERSION"] || "0.0.0", "-V, --version").option("-o, --output <format>", "Output format: table, json, yaml, markdown").option("-v, --verbose", "Enable debug logging").option("-q, --quiet", "Suppress non-essential output").option("-a, --app <package>", "App package name").option("-p, --profile <name>", "Auth profile name").option("--no-color", "Disable colored output").option("--no-interactive", "Disable interactive prompts").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Preview changes without executing");
|
|
67
71
|
const commandLoaders = {
|
|
68
72
|
auth: async () => {
|
|
69
|
-
(await import("./auth-
|
|
73
|
+
(await import("./auth-CIITFC3C.js")).registerAuthCommands(program);
|
|
70
74
|
},
|
|
71
75
|
config: async () => {
|
|
72
|
-
(await import("./config-
|
|
76
|
+
(await import("./config-7QKUVNZZ.js")).registerConfigCommands(program);
|
|
73
77
|
},
|
|
74
78
|
doctor: async () => {
|
|
75
|
-
(await import("./doctor-
|
|
79
|
+
(await import("./doctor-KVP7PGZU.js")).registerDoctorCommand(program);
|
|
76
80
|
},
|
|
77
81
|
docs: async () => {
|
|
78
82
|
(await import("./docs-CVTWIVMS.js")).registerDocsCommand(program);
|
|
79
83
|
},
|
|
80
84
|
completion: async () => {
|
|
81
|
-
(await import("./completion-
|
|
85
|
+
(await import("./completion-IHVLP7OK.js")).registerCompletionCommand(program);
|
|
82
86
|
},
|
|
83
87
|
apps: async () => {
|
|
84
|
-
(await import("./apps-
|
|
88
|
+
(await import("./apps-TZG5GEDW.js")).registerAppsCommands(program);
|
|
85
89
|
},
|
|
86
90
|
releases: async () => {
|
|
87
|
-
(await import("./releases-
|
|
91
|
+
(await import("./releases-IZJJYTNZ.js")).registerReleasesCommands(program);
|
|
88
92
|
},
|
|
89
93
|
tracks: async () => {
|
|
90
|
-
(await import("./tracks-
|
|
94
|
+
(await import("./tracks-HMJ3F55N.js")).registerTracksCommands(program);
|
|
91
95
|
},
|
|
92
96
|
status: async () => {
|
|
93
|
-
(await import("./status-
|
|
97
|
+
(await import("./status-TBPVS7YR.js")).registerStatusCommand(program);
|
|
94
98
|
},
|
|
95
99
|
listings: async () => {
|
|
96
|
-
(await import("./listings-
|
|
100
|
+
(await import("./listings-U3T6NFVH.js")).registerListingsCommands(program);
|
|
97
101
|
},
|
|
98
102
|
reviews: async () => {
|
|
99
|
-
(await import("./reviews-
|
|
103
|
+
(await import("./reviews-T3SRAZLW.js")).registerReviewsCommands(program);
|
|
100
104
|
},
|
|
101
105
|
vitals: async () => {
|
|
102
|
-
(await import("./vitals-
|
|
106
|
+
(await import("./vitals-VP2GKG3G.js")).registerVitalsCommands(program);
|
|
103
107
|
},
|
|
104
108
|
subscriptions: async () => {
|
|
105
|
-
(await import("./subscriptions-
|
|
109
|
+
(await import("./subscriptions-UJUX3ELS.js")).registerSubscriptionsCommands(program);
|
|
106
110
|
},
|
|
107
111
|
iap: async () => {
|
|
108
|
-
(await import("./iap-
|
|
112
|
+
(await import("./iap-Z365AMDD.js")).registerIapCommands(program);
|
|
109
113
|
},
|
|
110
114
|
purchases: async () => {
|
|
111
|
-
(await import("./purchases-
|
|
115
|
+
(await import("./purchases-ZQ7FXEZQ.js")).registerPurchasesCommands(program);
|
|
112
116
|
},
|
|
113
117
|
pricing: async () => {
|
|
114
|
-
(await import("./pricing-
|
|
118
|
+
(await import("./pricing-LXIRB4R7.js")).registerPricingCommands(program);
|
|
115
119
|
},
|
|
116
120
|
reports: async () => {
|
|
117
|
-
(await import("./reports-
|
|
121
|
+
(await import("./reports-43OVCCU3.js")).registerReportsCommands(program);
|
|
118
122
|
},
|
|
119
123
|
users: async () => {
|
|
120
|
-
(await import("./users-
|
|
124
|
+
(await import("./users-GRQTY6HY.js")).registerUsersCommands(program);
|
|
121
125
|
},
|
|
122
126
|
testers: async () => {
|
|
123
|
-
(await import("./testers-
|
|
127
|
+
(await import("./testers-YNOGFHUR.js")).registerTestersCommands(program);
|
|
124
128
|
},
|
|
125
129
|
validate: async () => {
|
|
126
130
|
(await import("./validate-TPKVSIMR.js")).registerValidateCommand(program);
|
|
127
131
|
},
|
|
128
132
|
publish: async () => {
|
|
129
|
-
(await import("./publish-
|
|
133
|
+
(await import("./publish-HKOJVZ23.js")).registerPublishCommand(program);
|
|
130
134
|
},
|
|
131
135
|
plugins: async () => {
|
|
132
136
|
registerPluginsCommand(program, pluginManager);
|
|
133
137
|
}
|
|
134
138
|
};
|
|
135
139
|
const target = process.argv[2];
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
const loader = target ? commandLoaders[target] : void 0;
|
|
141
|
+
if (loader) {
|
|
142
|
+
await loader();
|
|
138
143
|
} else {
|
|
139
|
-
await Promise.all(Object.values(commandLoaders).map((
|
|
144
|
+
await Promise.all(Object.values(commandLoaders).map((loader2) => loader2()));
|
|
140
145
|
}
|
|
141
146
|
if (pluginManager) {
|
|
142
147
|
registerPluginCommands(program, pluginManager);
|
|
@@ -214,11 +219,11 @@ function wrapCommandHooks(program, manager) {
|
|
|
214
219
|
app: program.opts()["app"],
|
|
215
220
|
startedAt: /* @__PURE__ */ new Date()
|
|
216
221
|
};
|
|
217
|
-
thisCommand
|
|
222
|
+
thisCommand["__pluginEvent"] = event;
|
|
218
223
|
await manager.runBeforeCommand(event);
|
|
219
224
|
});
|
|
220
225
|
program.hook("postAction", async (thisCommand) => {
|
|
221
|
-
const event = thisCommand
|
|
226
|
+
const event = thisCommand["__pluginEvent"];
|
|
222
227
|
if (!event) return;
|
|
223
228
|
const result = {
|
|
224
229
|
success: true,
|
|
@@ -242,4 +247,4 @@ export {
|
|
|
242
247
|
loadPlugins,
|
|
243
248
|
createProgram
|
|
244
249
|
};
|
|
245
|
-
//# sourceMappingURL=chunk-
|
|
250
|
+
//# sourceMappingURL=chunk-22DW4R5W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins.ts","../src/program.ts"],"sourcesContent":["import { PluginManager, discoverPlugins } from \"@gpc-cli/core\";\nimport type { Command } from \"commander\";\n\n/**\n * Load and initialize all plugins.\n * First-party plugins (@gpc-cli/*) are auto-trusted.\n * Third-party plugins require prior approval stored in config.\n * Plugin loading is disabled in standalone binary mode.\n */\nexport async function loadPlugins(): Promise<PluginManager> {\n const manager = new PluginManager();\n\n // Standalone binary cannot resolve external npm packages at runtime\n if (process.env[\"__GPC_BINARY\"] === \"1\") {\n return manager;\n }\n\n try {\n const { loadConfig } = await import(\"@gpc-cli/config\");\n const config = await loadConfig();\n const plugins = await discoverPlugins({ configPlugins: config.plugins });\n const approved = new Set(config.approvedPlugins ?? []);\n\n for (const plugin of plugins) {\n const isTrusted = plugin.name.startsWith(\"@gpc-cli/\");\n\n if (!isTrusted && !approved.has(plugin.name)) {\n // Skip unapproved third-party plugins silently in non-interactive mode\n // In interactive mode, the user would run `gpc plugins approve <name>` first\n const isQuiet = process.argv.includes(\"--quiet\") || process.argv.includes(\"-q\");\n if (!isQuiet) {\n console.error(\n `Plugin \"${plugin.name}\" is not approved. Run: gpc plugins approve ${plugin.name}`,\n );\n }\n continue;\n }\n\n try {\n await manager.load(plugin);\n } catch {\n // Skip plugins that fail to load — don't block the CLI\n }\n }\n } catch {\n // Config loading failure shouldn't block plugin-free commands\n }\n\n return manager;\n}\n\n/**\n * Register plugin-defined commands with the Commander program.\n */\nexport function registerPluginCommands(program: Command, manager: PluginManager): void {\n for (const def of manager.getRegisteredCommands()) {\n const cmd = program.command(def.name).description(def.description);\n\n if (def.arguments) {\n for (const arg of def.arguments) {\n const syntax = arg.required ? `<${arg.name}>` : `[${arg.name}]`;\n cmd.argument(syntax, arg.description);\n }\n }\n\n if (def.options) {\n for (const opt of def.options) {\n cmd.option(\n opt.flags,\n opt.description,\n opt.defaultValue as string | boolean | string[] | undefined,\n );\n }\n }\n\n cmd.action(async (...rawArgs: unknown[]) => {\n const opts = rawArgs[rawArgs.length - 2] as Record<string, unknown>;\n const args: Record<string, unknown> = {};\n\n if (def.arguments) {\n def.arguments.forEach((argDef, i) => {\n args[argDef.name] = rawArgs[i];\n });\n }\n\n await def.action(args, opts);\n });\n }\n}\n","import { Command } from \"commander\";\nimport type { PluginManager } from \"@gpc-cli/core\";\nimport type { CommandEvent, CommandResult } from \"@gpc-cli/plugin-sdk\";\nimport { registerPluginCommands } from \"./plugins.js\";\n\nexport async function createProgram(pluginManager?: PluginManager): Promise<Command> {\n const program = new Command();\n\n program\n .name(\"gpc\")\n .description(\"The complete Google Play CLI\")\n .version(process.env[\"__GPC_VERSION\"] || \"0.0.0\", \"-V, --version\")\n .option(\"-o, --output <format>\", \"Output format: table, json, yaml, markdown\")\n .option(\"-v, --verbose\", \"Enable debug logging\")\n .option(\"-q, --quiet\", \"Suppress non-essential output\")\n .option(\"-a, --app <package>\", \"App package name\")\n .option(\"-p, --profile <name>\", \"Auth profile name\")\n .option(\"--no-color\", \"Disable colored output\")\n .option(\"--no-interactive\", \"Disable interactive prompts\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .option(\"--dry-run\", \"Preview changes without executing\");\n\n const commandLoaders: Record<string, () => Promise<void>> = {\n auth: async () => {\n (await import(\"./commands/auth.js\")).registerAuthCommands(program);\n },\n config: async () => {\n (await import(\"./commands/config.js\")).registerConfigCommands(program);\n },\n doctor: async () => {\n (await import(\"./commands/doctor.js\")).registerDoctorCommand(program);\n },\n docs: async () => {\n (await import(\"./commands/docs.js\")).registerDocsCommand(program);\n },\n completion: async () => {\n (await import(\"./commands/completion.js\")).registerCompletionCommand(program);\n },\n apps: async () => {\n (await import(\"./commands/apps.js\")).registerAppsCommands(program);\n },\n releases: async () => {\n (await import(\"./commands/releases.js\")).registerReleasesCommands(program);\n },\n tracks: async () => {\n (await import(\"./commands/tracks.js\")).registerTracksCommands(program);\n },\n status: async () => {\n (await import(\"./commands/status.js\")).registerStatusCommand(program);\n },\n listings: async () => {\n (await import(\"./commands/listings.js\")).registerListingsCommands(program);\n },\n reviews: async () => {\n (await import(\"./commands/reviews.js\")).registerReviewsCommands(program);\n },\n vitals: async () => {\n (await import(\"./commands/vitals.js\")).registerVitalsCommands(program);\n },\n subscriptions: async () => {\n (await import(\"./commands/subscriptions.js\")).registerSubscriptionsCommands(program);\n },\n iap: async () => {\n (await import(\"./commands/iap.js\")).registerIapCommands(program);\n },\n purchases: async () => {\n (await import(\"./commands/purchases.js\")).registerPurchasesCommands(program);\n },\n pricing: async () => {\n (await import(\"./commands/pricing.js\")).registerPricingCommands(program);\n },\n reports: async () => {\n (await import(\"./commands/reports.js\")).registerReportsCommands(program);\n },\n users: async () => {\n (await import(\"./commands/users.js\")).registerUsersCommands(program);\n },\n testers: async () => {\n (await import(\"./commands/testers.js\")).registerTestersCommands(program);\n },\n validate: async () => {\n (await import(\"./commands/validate.js\")).registerValidateCommand(program);\n },\n publish: async () => {\n (await import(\"./commands/publish.js\")).registerPublishCommand(program);\n },\n plugins: async () => {\n registerPluginsCommand(program, pluginManager);\n },\n };\n\n const target = process.argv[2];\n\n const loader = target ? commandLoaders[target] : undefined;\n if (loader) {\n await loader();\n } else {\n await Promise.all(Object.values(commandLoaders).map((loader) => loader()));\n }\n\n // Register plugin-defined commands\n if (pluginManager) {\n registerPluginCommands(program, pluginManager);\n }\n\n // Wire plugin lifecycle hooks around command execution\n if (pluginManager) {\n wrapCommandHooks(program, pluginManager);\n }\n\n return program;\n}\n\n/**\n * `gpc plugins` — manage plugins.\n */\nfunction registerPluginsCommand(program: Command, manager?: PluginManager): void {\n const cmd = program.command(\"plugins\").description(\"Manage plugins\");\n\n cmd\n .command(\"list\")\n .description(\"List loaded plugins\")\n .action(() => {\n const plugins = manager?.getLoadedPlugins() ?? [];\n const opts = program.opts();\n\n if (opts[\"output\"] === \"json\") {\n console.log(JSON.stringify(plugins, null, 2));\n return;\n }\n\n if (plugins.length === 0) {\n console.log(\"No plugins loaded.\");\n console.log('\\nConfigure plugins in .gpcrc.json: { \"plugins\": [\"@gpc-cli/plugin-ci\"] }');\n return;\n }\n\n console.log(\"Loaded plugins:\\n\");\n for (const p of plugins) {\n const trust = p.trusted ? \"trusted\" : \"third-party\";\n console.log(` ${p.name}@${p.version} (${trust})`);\n }\n\n const commands = manager?.getRegisteredCommands() ?? [];\n if (commands.length > 0) {\n console.log(\"\\nPlugin commands:\\n\");\n for (const c of commands) {\n console.log(` gpc ${c.name} — ${c.description}`);\n }\n }\n });\n\n cmd\n .command(\"init <name>\")\n .description(\"Scaffold a new plugin project\")\n .option(\"-d, --dir <path>\", \"Output directory (defaults to ./gpc-plugin-<name>)\")\n .option(\"--description <text>\", \"Plugin description\")\n .action(async (name: string, opts: { dir?: string; description?: string }) => {\n const { scaffoldPlugin } = await import(\"@gpc-cli/core\");\n const pluginName = name.startsWith(\"gpc-plugin-\") ? name : `gpc-plugin-${name}`;\n const dir = opts.dir ?? `./${pluginName}`;\n\n const result = await scaffoldPlugin({ name, dir, description: opts.description });\n\n console.log(`Plugin scaffolded at ${result.dir}/\\n`);\n console.log(\"Files created:\");\n for (const f of result.files) {\n console.log(` ${f}`);\n }\n console.log(`\\nNext steps:`);\n console.log(` cd ${pluginName}`);\n console.log(` npm install`);\n console.log(` npm run build`);\n console.log(` npm test`);\n });\n\n cmd\n .command(\"approve <name>\")\n .description(\"Approve a third-party plugin for loading\")\n .action(async (name: string) => {\n const { approvePlugin } = await import(\"@gpc-cli/config\");\n await approvePlugin(name);\n console.log(`Plugin \"${name}\" approved. It will be loaded on next run.`);\n });\n\n cmd\n .command(\"revoke <name>\")\n .description(\"Revoke approval for a third-party plugin\")\n .action(async (name: string) => {\n const { revokePluginApproval } = await import(\"@gpc-cli/config\");\n const removed = await revokePluginApproval(name);\n if (removed) {\n console.log(`Plugin \"${name}\" approval revoked.`);\n } else {\n console.log(`Plugin \"${name}\" was not in the approved list.`);\n }\n });\n}\n\n/**\n * Wrap all registered commands so plugin hooks fire before/after each command.\n */\nfunction wrapCommandHooks(program: Command, manager: PluginManager): void {\n program.hook(\"preAction\", async (thisCommand) => {\n const event: CommandEvent = {\n command: getFullCommandName(thisCommand),\n args: thisCommand.opts(),\n app: program.opts()[\"app\"] as string | undefined,\n startedAt: new Date(),\n };\n\n // Store on the command for afterCommand/onError\n (thisCommand as unknown as Record<string, unknown>)[\"__pluginEvent\"] = event;\n\n await manager.runBeforeCommand(event);\n });\n\n program.hook(\"postAction\", async (thisCommand) => {\n const event: CommandEvent = (thisCommand as unknown as Record<string, unknown>)[\n \"__pluginEvent\"\n ] as CommandEvent;\n if (!event) return;\n\n const result: CommandResult = {\n success: true,\n durationMs: Date.now() - event.startedAt.getTime(),\n exitCode: 0,\n };\n\n await manager.runAfterCommand(event, result);\n });\n}\n\nfunction getFullCommandName(cmd: Command): string {\n const parts: string[] = [];\n let current: Command | null = cmd;\n while (current && current.name() !== \"gpc\") {\n parts.unshift(current.name());\n current = current.parent;\n }\n return parts.join(\" \");\n}\n"],"mappings":"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","names":["loader"]}
|
|
@@ -6,7 +6,7 @@ function isInteractive(program) {
|
|
|
6
6
|
if (program) {
|
|
7
7
|
let root = program;
|
|
8
8
|
while (root.parent) root = root.parent;
|
|
9
|
-
if (root.opts()
|
|
9
|
+
if (root.opts()["interactive"] === false) return false;
|
|
10
10
|
}
|
|
11
11
|
if (process.env["GPC_NO_INTERACTIVE"] === "1" || process.env["GPC_NO_INTERACTIVE"] === "true") {
|
|
12
12
|
return false;
|
|
@@ -20,7 +20,7 @@ function skipConfirm(program) {
|
|
|
20
20
|
if (!program) return false;
|
|
21
21
|
let root = program;
|
|
22
22
|
while (root.parent) root = root.parent;
|
|
23
|
-
return root.opts()
|
|
23
|
+
return root.opts()["yes"] === true;
|
|
24
24
|
}
|
|
25
25
|
async function requireOption(name, value, prompt, interactive) {
|
|
26
26
|
if (value) return value;
|
|
@@ -29,8 +29,10 @@ async function requireOption(name, value, prompt, interactive) {
|
|
|
29
29
|
}
|
|
30
30
|
process.stderr.write(`Error: Missing required option --${name}
|
|
31
31
|
`);
|
|
32
|
-
process.stderr.write(
|
|
33
|
-
`)
|
|
32
|
+
process.stderr.write(
|
|
33
|
+
`Suggestion: Provide --${name} or run interactively (remove --no-interactive)
|
|
34
|
+
`
|
|
35
|
+
);
|
|
34
36
|
process.exit(2);
|
|
35
37
|
}
|
|
36
38
|
async function requireConfirm(message, program) {
|
|
@@ -67,14 +69,14 @@ async function promptSelect(message, choices, defaultValue) {
|
|
|
67
69
|
const trimmed = answer.trim();
|
|
68
70
|
const num = Number(trimmed);
|
|
69
71
|
if (num >= 1 && num <= choices.length) {
|
|
70
|
-
resolve(choices[num - 1]);
|
|
72
|
+
resolve(choices[num - 1] ?? "");
|
|
71
73
|
return;
|
|
72
74
|
}
|
|
73
75
|
if (choices.includes(trimmed)) {
|
|
74
76
|
resolve(trimmed);
|
|
75
77
|
return;
|
|
76
78
|
}
|
|
77
|
-
resolve(defaultValue
|
|
79
|
+
resolve(defaultValue ?? choices[0] ?? "");
|
|
78
80
|
});
|
|
79
81
|
});
|
|
80
82
|
}
|
|
@@ -100,4 +102,4 @@ export {
|
|
|
100
102
|
promptSelect,
|
|
101
103
|
promptConfirm
|
|
102
104
|
};
|
|
103
|
-
//# sourceMappingURL=chunk-
|
|
105
|
+
//# sourceMappingURL=chunk-Q7KVGI46.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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: { parent?: unknown; opts(): Record<string, unknown> } = program;\n while (root.parent) root = root.parent as typeof root;\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: { parent?: unknown; opts(): Record<string, unknown> } = program;\n while (root.parent) root = root.parent as typeof root;\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(\n `Suggestion: Provide --${name} or run interactively (remove --no-interactive)\\n`,\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(\n message: string,\n choices: string[],\n defaultValue?: string,\n): 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":"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","names":[]}
|
|
@@ -6,7 +6,7 @@ function isDryRun(program) {
|
|
|
6
6
|
while (cmd.parent) {
|
|
7
7
|
cmd = cmd.parent;
|
|
8
8
|
}
|
|
9
|
-
return !!cmd.opts()
|
|
9
|
+
return !!cmd.opts()["dryRun"];
|
|
10
10
|
}
|
|
11
11
|
function printDryRun(preview, format, formatOutput) {
|
|
12
12
|
const output = {
|
|
@@ -21,4 +21,4 @@ export {
|
|
|
21
21
|
isDryRun,
|
|
22
22
|
printDryRun
|
|
23
23
|
};
|
|
24
|
-
//# sourceMappingURL=chunk-
|
|
24
|
+
//# sourceMappingURL=chunk-Y3QZDAKS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dry-run.ts"],"sourcesContent":["import type { OutputFormat } from \"@gpc-cli/config\";\n\nexport interface DryRunPreview {\n command: string;\n action: string;\n target: string;\n details?: Record<string, unknown>;\n}\n\nexport function isDryRun(program: { opts(): Record<string, unknown> }): boolean {\n let cmd: { parent?: unknown; opts(): Record<string, unknown> } = program;\n while (cmd.parent) {\n cmd = cmd.parent as typeof cmd;\n }\n return !!cmd.opts()[\"dryRun\"];\n}\n\nexport function printDryRun(\n preview: DryRunPreview,\n format: OutputFormat,\n formatOutput: (data: unknown, format: OutputFormat, redact?: boolean) => string,\n): void {\n const output = {\n dryRun: true,\n ...preview,\n message: `Would ${preview.action} ${preview.target}`,\n };\n console.log(formatOutput(output, format));\n}\n"],"mappings":";;;AASO,SAAS,SAAS,SAAuD;AAC9E,MAAI,MAA6D;AACjE,SAAO,IAAI,QAAQ;AACjB,UAAM,IAAI;AAAA,EACZ;AACA,SAAO,CAAC,CAAC,IAAI,KAAK,EAAE,QAAQ;AAC9B;AAEO,SAAS,YACd,SACA,QACA,cACM;AACN,QAAM,SAAS;AAAA,IACb,QAAQ;AAAA,IACR,GAAG;AAAA,IACH,SAAS,SAAS,QAAQ,MAAM,IAAI,QAAQ,MAAM;AAAA,EACpD;AACA,UAAQ,IAAI,aAAa,QAAQ,MAAM,CAAC;AAC1C;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/completion.ts"],"sourcesContent":["import type { Command } from \"commander\";\n\nexport function registerCompletionCommand(program: Command): void {\n const completion = program.command(\"completion\").description(\"Generate shell completions\");\n\n completion\n .command(\"bash\")\n .description(\"Generate bash completions\")\n .action(() => {\n console.log(generateBashCompletions());\n });\n\n completion\n .command(\"zsh\")\n .description(\"Generate zsh completions\")\n .action(() => {\n console.log(generateZshCompletions());\n });\n\n completion\n .command(\"fish\")\n .description(\"Generate fish completions\")\n .action(() => {\n console.log(generateFishCompletions());\n });\n}\n\nfunction generateBashCompletions(): string {\n return `# bash completion for gpc\n_gpc() {\n local cur prev commands\n COMPREPLY=()\n cur=\"\\${COMP_WORDS[COMP_CWORD]}\"\n prev=\"\\${COMP_WORDS[COMP_CWORD-1]}\"\n\n commands=\"auth config doctor docs completion\"\n\n case \"\\${prev}\" in\n gpc)\n COMPREPLY=( $(compgen -W \"\\${commands}\" -- \"\\${cur}\") )\n return 0\n ;;\n auth)\n COMPREPLY=( $(compgen -W \"login status logout whoami\" -- \"\\${cur}\") )\n return 0\n ;;\n config)\n COMPREPLY=( $(compgen -W \"init show set path\" -- \"\\${cur}\") )\n return 0\n ;;\n completion)\n COMPREPLY=( $(compgen -W \"bash zsh fish\" -- \"\\${cur}\") )\n return 0\n ;;\n esac\n\n COMPREPLY=( $(compgen -W \"\\${commands}\" -- \"\\${cur}\") )\n return 0\n}\n\ncomplete -F _gpc gpc`;\n}\n\nfunction generateZshCompletions(): string {\n return `#compdef gpc\n\n_gpc() {\n local -a commands auth_commands config_commands completion_commands\n\n commands=(\n 'auth:Manage authentication'\n 'config:Manage CLI configuration'\n 'doctor:Check environment and configuration'\n 'docs:Open documentation'\n 'completion:Generate shell completions'\n )\n\n auth_commands=(\n 'login:Authenticate with Google Play Console'\n 'status:Show current authentication status'\n 'logout:Remove stored credentials'\n 'whoami:Show the authenticated account'\n )\n\n config_commands=(\n 'init:Initialize a new configuration'\n 'show:Show current configuration'\n 'set:Set a configuration value'\n 'path:Show the configuration file path'\n )\n\n completion_commands=(\n 'bash:Generate bash completions'\n 'zsh:Generate zsh completions'\n 'fish:Generate fish completions'\n )\n\n _arguments -C \\\\\n '1: :->command' \\\\\n '2: :->subcommand' \\\\\n '*::arg:->args'\n\n case \"$state\" in\n command)\n _describe -t commands 'gpc commands' commands\n ;;\n subcommand)\n case \"$words[2]\" in\n auth)\n _describe -t auth_commands 'auth commands' auth_commands\n ;;\n config)\n _describe -t config_commands 'config commands' config_commands\n ;;\n completion)\n _describe -t completion_commands 'completion commands' completion_commands\n ;;\n esac\n ;;\n esac\n}\n\n_gpc \"$@\"`;\n}\n\nfunction generateFishCompletions(): string {\n return `# fish completions for gpc\n\n# Disable file completions by default\ncomplete -c gpc -f\n\n# Top-level commands\ncomplete -c gpc -n '__fish_use_subcommand' -a auth -d 'Manage authentication'\ncomplete -c gpc -n '__fish_use_subcommand' -a config -d 'Manage CLI configuration'\ncomplete -c gpc -n '__fish_use_subcommand' -a doctor -d 'Check environment and configuration'\ncomplete -c gpc -n '__fish_use_subcommand' -a docs -d 'Open documentation'\ncomplete -c gpc -n '__fish_use_subcommand' -a completion -d 'Generate shell completions'\n\n# auth subcommands\ncomplete -c gpc -n '__fish_seen_subcommand_from auth' -a login -d 'Authenticate with Google Play Console'\ncomplete -c gpc -n '__fish_seen_subcommand_from auth' -a status -d 'Show current authentication status'\ncomplete -c gpc -n '__fish_seen_subcommand_from auth' -a logout -d 'Remove stored credentials'\ncomplete -c gpc -n '__fish_seen_subcommand_from auth' -a whoami -d 'Show the authenticated account'\n\n# config subcommands\ncomplete -c gpc -n '__fish_seen_subcommand_from config' -a init -d 'Initialize a new configuration'\ncomplete -c gpc -n '__fish_seen_subcommand_from config' -a show -d 'Show current configuration'\ncomplete -c gpc -n '__fish_seen_subcommand_from config' -a set -d 'Set a configuration value'\ncomplete -c gpc -n '__fish_seen_subcommand_from config' -a path -d 'Show the configuration file path'\n\n# completion subcommands\ncomplete -c gpc -n '__fish_seen_subcommand_from completion' -a bash -d 'Generate bash completions'\ncomplete -c gpc -n '__fish_seen_subcommand_from completion' -a zsh -d 'Generate zsh completions'\ncomplete -c gpc -n '__fish_seen_subcommand_from completion' -a fish -d 'Generate fish completions'`;\n}\n"],"mappings":";;;AAEO,SAAS,0BAA0B,SAAwB;AAChE,QAAM,aAAa,QAAQ,QAAQ,YAAY,EAAE,YAAY,4BAA4B;AAEzF,aACG,QAAQ,MAAM,EACd,YAAY,2BAA2B,EACvC,OAAO,MAAM;AACZ,YAAQ,IAAI,wBAAwB,CAAC;AAAA,EACvC,CAAC;AAEH,aACG,QAAQ,KAAK,EACb,YAAY,0BAA0B,EACtC,OAAO,MAAM;AACZ,YAAQ,IAAI,uBAAuB,CAAC;AAAA,EACtC,CAAC;AAEH,aACG,QAAQ,MAAM,EACd,YAAY,2BAA2B,EACvC,OAAO,MAAM;AACZ,YAAQ,IAAI,wBAAwB,CAAC;AAAA,EACvC,CAAC;AACL;AAEA,SAAS,0BAAkC;AACzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCT;AAEA,SAAS,yBAAiC;AACxC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2DT;AAEA,SAAS,0BAAkC;AACzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BT;","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
isInteractive,
|
|
4
4
|
promptInput,
|
|
5
5
|
promptSelect
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-Q7KVGI46.js";
|
|
7
7
|
|
|
8
8
|
// src/commands/config.ts
|
|
9
9
|
import { loadConfig, setConfigValue, getUserConfigPath, initConfig } from "@gpc-cli/config";
|
|
@@ -11,11 +11,15 @@ import { detectOutputFormat, formatOutput, writeAuditLog, createAuditEntry } fro
|
|
|
11
11
|
function registerConfigCommands(program) {
|
|
12
12
|
const config = program.command("config").description("Manage configuration");
|
|
13
13
|
config.command("init").description("Create a configuration file").option("--global", "Create in user config directory (~/.config/gpc/)").action(async (_options) => {
|
|
14
|
-
|
|
14
|
+
const initialConfig = {};
|
|
15
15
|
if (isInteractive(program)) {
|
|
16
16
|
const app = await promptInput("Default package name (e.g. com.example.app, blank to skip)");
|
|
17
17
|
if (app) initialConfig["app"] = app;
|
|
18
|
-
const output = await promptSelect(
|
|
18
|
+
const output = await promptSelect(
|
|
19
|
+
"Default output format:",
|
|
20
|
+
["table", "json", "yaml", "markdown"],
|
|
21
|
+
"table"
|
|
22
|
+
);
|
|
19
23
|
if (output !== "table") initialConfig["output"] = output;
|
|
20
24
|
const sa = await promptInput("Service account JSON path (blank to skip)");
|
|
21
25
|
if (sa) initialConfig["auth"] = { serviceAccount: sa };
|
|
@@ -41,4 +45,4 @@ function registerConfigCommands(program) {
|
|
|
41
45
|
export {
|
|
42
46
|
registerConfigCommands
|
|
43
47
|
};
|
|
44
|
-
//# sourceMappingURL=config-
|
|
48
|
+
//# sourceMappingURL=config-7QKUVNZZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/config.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig, setConfigValue, getUserConfigPath, initConfig } from \"@gpc-cli/config\";\nimport type { GpcConfig } from \"@gpc-cli/config\";\nimport { detectOutputFormat, formatOutput, writeAuditLog, createAuditEntry } from \"@gpc-cli/core\";\nimport { isInteractive, promptInput, promptSelect } from \"../prompt.js\";\n\nexport function registerConfigCommands(program: Command): void {\n const config = program.command(\"config\").description(\"Manage configuration\");\n\n config\n .command(\"init\")\n .description(\"Create a configuration file\")\n .option(\"--global\", \"Create in user config directory (~/.config/gpc/)\")\n .action(async (_options: { global?: boolean }) => {\n const initialConfig: Record<string, unknown> = {};\n\n if (isInteractive(program)) {\n const app = await promptInput(\"Default package name (e.g. com.example.app, blank to skip)\");\n if (app) initialConfig[\"app\"] = app;\n\n const output = await promptSelect(\n \"Default output format:\",\n [\"table\", \"json\", \"yaml\", \"markdown\"],\n \"table\",\n );\n if (output !== \"table\") initialConfig[\"output\"] = output;\n\n const sa = await promptInput(\"Service account JSON path (blank to skip)\");\n if (sa) initialConfig[\"auth\"] = { serviceAccount: sa };\n }\n\n const path = await initConfig(initialConfig as GpcConfig);\n console.log(`Configuration file created at: ${path}`);\n writeAuditLog(createAuditEntry(\"config init\", { path })).catch(() => {});\n });\n\n config\n .command(\"show\")\n .description(\"Display resolved configuration\")\n .action(async () => {\n const resolved = await loadConfig();\n const format = detectOutputFormat();\n console.log(formatOutput(resolved, format));\n });\n\n config\n .command(\"set <key> <value>\")\n .description(\"Set a configuration value\")\n .action(async (key: string, value: string) => {\n await setConfigValue(key, value);\n console.log(`Set ${key} = ${value}`);\n });\n\n config\n .command(\"path\")\n .description(\"Show configuration file path\")\n .action(() => {\n console.log(getUserConfigPath());\n });\n}\n"],"mappings":";;;;;;;;AACA,SAAS,YAAY,gBAAgB,mBAAmB,kBAAkB;AAE1E,SAAS,oBAAoB,cAAc,eAAe,wBAAwB;AAG3E,SAAS,uBAAuB,SAAwB;AAC7D,QAAM,SAAS,QAAQ,QAAQ,QAAQ,EAAE,YAAY,sBAAsB;AAE3E,SACG,QAAQ,MAAM,EACd,YAAY,6BAA6B,EACzC,OAAO,YAAY,kDAAkD,EACrE,OAAO,OAAO,aAAmC;AAChD,UAAM,gBAAyC,CAAC;AAEhD,QAAI,cAAc,OAAO,GAAG;AAC1B,YAAM,MAAM,MAAM,YAAY,4DAA4D;AAC1F,UAAI,IAAK,eAAc,KAAK,IAAI;AAEhC,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,CAAC,SAAS,QAAQ,QAAQ,UAAU;AAAA,QACpC;AAAA,MACF;AACA,UAAI,WAAW,QAAS,eAAc,QAAQ,IAAI;AAElD,YAAM,KAAK,MAAM,YAAY,2CAA2C;AACxE,UAAI,GAAI,eAAc,MAAM,IAAI,EAAE,gBAAgB,GAAG;AAAA,IACvD;AAEA,UAAM,OAAO,MAAM,WAAW,aAA0B;AACxD,YAAQ,IAAI,kCAAkC,IAAI,EAAE;AACpD,kBAAc,iBAAiB,eAAe,EAAE,KAAK,CAAC,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACzE,CAAC;AAEH,SACG,QAAQ,MAAM,EACd,YAAY,gCAAgC,EAC5C,OAAO,YAAY;AAClB,UAAM,WAAW,MAAM,WAAW;AAClC,UAAM,SAAS,mBAAmB;AAClC,YAAQ,IAAI,aAAa,UAAU,MAAM,CAAC;AAAA,EAC5C,CAAC;AAEH,SACG,QAAQ,mBAAmB,EAC3B,YAAY,2BAA2B,EACvC,OAAO,OAAO,KAAa,UAAkB;AAC5C,UAAM,eAAe,KAAK,KAAK;AAC/B,YAAQ,IAAI,OAAO,GAAG,MAAM,KAAK,EAAE;AAAA,EACrC,CAAC;AAEH,SACG,QAAQ,MAAM,EACd,YAAY,8BAA8B,EAC1C,OAAO,MAAM;AACZ,YAAQ,IAAI,kBAAkB,CAAC;AAAA,EACjC,CAAC;AACL;","names":[]}
|
|
@@ -8,7 +8,7 @@ function registerDoctorCommand(program) {
|
|
|
8
8
|
console.log("GPC Doctor\n");
|
|
9
9
|
let allGood = true;
|
|
10
10
|
const nodeVersion = process.versions.node;
|
|
11
|
-
const major = parseInt(nodeVersion.split(".")[0], 10);
|
|
11
|
+
const major = parseInt(nodeVersion.split(".")[0] ?? "0", 10);
|
|
12
12
|
if (major >= 20) {
|
|
13
13
|
console.log(` \u2713 Node.js ${nodeVersion}`);
|
|
14
14
|
} else {
|
|
@@ -21,7 +21,9 @@ function registerDoctorCommand(program) {
|
|
|
21
21
|
if (config.app) {
|
|
22
22
|
console.log(` \u2713 Default app: ${config.app}`);
|
|
23
23
|
} else {
|
|
24
|
-
console.log(
|
|
24
|
+
console.log(
|
|
25
|
+
` - No default app configured (use --app flag or gpc config set app <package>)`
|
|
26
|
+
);
|
|
25
27
|
}
|
|
26
28
|
} catch {
|
|
27
29
|
console.log(" \u2717 Configuration error");
|
|
@@ -56,4 +58,4 @@ function registerDoctorCommand(program) {
|
|
|
56
58
|
export {
|
|
57
59
|
registerDoctorCommand
|
|
58
60
|
};
|
|
59
|
-
//# sourceMappingURL=doctor-
|
|
61
|
+
//# sourceMappingURL=doctor-KVP7PGZU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth, AuthError } from \"@gpc-cli/auth\";\n\nexport function registerDoctorCommand(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"Verify setup and connectivity\")\n .action(async () => {\n console.log(\"GPC Doctor\\n\");\n let allGood = true;\n\n // Check Node.js version\n const nodeVersion = process.versions.node;\n const major = parseInt(nodeVersion.split(\".\")[0] ?? \"0\", 10);\n if (major >= 20) {\n console.log(` \\u2713 Node.js ${nodeVersion}`);\n } else {\n console.log(` \\u2717 Node.js ${nodeVersion} (requires >=20)`);\n allGood = false;\n }\n\n // Check config\n try {\n const config = await loadConfig();\n console.log(` \\u2713 Configuration loaded`);\n if (config.app) {\n console.log(` \\u2713 Default app: ${config.app}`);\n } else {\n console.log(\n ` - No default app configured (use --app flag or gpc config set app <package>)`,\n );\n }\n } catch {\n console.log(\" \\u2717 Configuration error\");\n allGood = false;\n }\n\n // Check auth\n try {\n const config = await loadConfig();\n const client = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n });\n console.log(` \\u2713 Authenticated as ${client.getClientEmail()}`);\n\n // Try to get a token to verify connectivity\n await client.getAccessToken();\n console.log(\" \\u2713 API connectivity verified\");\n } catch (error) {\n if (error instanceof AuthError) {\n console.log(` \\u2717 Authentication: ${error.message}`);\n if (error.suggestion) console.log(` ${error.suggestion}`);\n } else {\n console.log(\" \\u2717 API connectivity failed\");\n }\n allGood = false;\n }\n\n console.log(\"\");\n if (allGood) {\n console.log(\"All checks passed!\");\n } else {\n console.log(\"Some checks failed. Fix the issues above and run again.\");\n process.exit(1);\n }\n });\n}\n"],"mappings":";;;AACA,SAAS,kBAAkB;AAC3B,SAAS,aAAa,iBAAiB;AAEhC,SAAS,sBAAsB,SAAwB;AAC5D,UACG,QAAQ,QAAQ,EAChB,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,YAAQ,IAAI,cAAc;AAC1B,QAAI,UAAU;AAGd,UAAM,cAAc,QAAQ,SAAS;AACrC,UAAM,QAAQ,SAAS,YAAY,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AAC3D,QAAI,SAAS,IAAI;AACf,cAAQ,IAAI,oBAAoB,WAAW,EAAE;AAAA,IAC/C,OAAO;AACL,cAAQ,IAAI,oBAAoB,WAAW,kBAAkB;AAC7D,gBAAU;AAAA,IACZ;AAGA,QAAI;AACF,YAAM,SAAS,MAAM,WAAW;AAChC,cAAQ,IAAI,+BAA+B;AAC3C,UAAI,OAAO,KAAK;AACd,gBAAQ,IAAI,yBAAyB,OAAO,GAAG,EAAE;AAAA,MACnD,OAAO;AACL,gBAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AACN,cAAQ,IAAI,8BAA8B;AAC1C,gBAAU;AAAA,IACZ;AAGA,QAAI;AACF,YAAM,SAAS,MAAM,WAAW;AAChC,YAAM,SAAS,MAAM,YAAY;AAAA,QAC/B,oBAAoB,OAAO,MAAM;AAAA,MACnC,CAAC;AACD,cAAQ,IAAI,6BAA6B,OAAO,eAAe,CAAC,EAAE;AAGlE,YAAM,OAAO,eAAe;AAC5B,cAAQ,IAAI,oCAAoC;AAAA,IAClD,SAAS,OAAO;AACd,UAAI,iBAAiB,WAAW;AAC9B,gBAAQ,IAAI,4BAA4B,MAAM,OAAO,EAAE;AACvD,YAAI,MAAM,WAAY,SAAQ,IAAI,OAAO,MAAM,UAAU,EAAE;AAAA,MAC7D,OAAO;AACL,gBAAQ,IAAI,kCAAkC;AAAA,MAChD;AACA,gBAAU;AAAA,IACZ;AAEA,YAAQ,IAAI,EAAE;AACd,QAAI,SAAS;AACX,cAAQ,IAAI,oBAAoB;AAAA,IAClC,OAAO;AACL,cAAQ,IAAI,yDAAyD;AACrE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AACL;","names":[]}
|