@gpc-cli/cli 0.9.69 → 0.9.71

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 CHANGED
@@ -26,7 +26,7 @@ gpc listings push --dir metadata/ # Sync store metadata (Fastlane-co
26
26
  gpc changelog generate --target play-store --locales auto --ai # AI-translated "What's new" in every locale
27
27
  gpc enterprise publish app.aab --account 123 --title "Private App" # Managed Google Play
28
28
  gpc verify # Developer verification readiness
29
- gpc doctor # 20 setup checks
29
+ gpc doctor # 22 setup checks
30
30
  ```
31
31
 
32
32
  ## Why this over Fastlane?
@@ -97,7 +97,7 @@ curl -fsSL https://raw.githubusercontent.com/yasserstudio/gpc/main/scripts/insta
97
97
  - [Commands reference](https://yasserstudio.github.io/gpc/commands/)
98
98
  - [CI/CD recipes](https://yasserstudio.github.io/gpc/ci-cd/)
99
99
 
100
- Free to use. 2,237 tests. 90%+ coverage. Every write operation supports `--dry-run`.
100
+ Free to use. 2,269 tests. 90%+ coverage. Every write operation supports `--dry-run`.
101
101
 
102
102
  ## Licensing
103
103
 
package/dist/bin.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createProgram,
4
4
  handleCliError,
5
5
  loadPlugins
6
- } from "./chunk-3M3SM2YH.js";
6
+ } from "./chunk-RGSWTGKV.js";
7
7
  import {
8
8
  checkForUpdate,
9
9
  formatUpdateNotification
@@ -57,7 +57,7 @@ if (!_isJsonMode && !_isQuiet && !_isSetupCommand && !existsSync(getUserConfigPa
57
57
  }
58
58
  await setupNetworking();
59
59
  initAudit(getConfigDir());
60
- var currentVersion = "0.9.69";
60
+ var currentVersion = "0.9.71";
61
61
  var isUpdateCommand = process.argv[2] === "update";
62
62
  var isCompletionProvider = process.argv[2] === "__complete";
63
63
  var updateCheckPromise = isUpdateCommand || isCompletionProvider ? Promise.resolve(null) : checkForUpdate(currentVersion);
@@ -330,4 +330,4 @@ export {
330
330
  cleanupStaleUpdateFiles,
331
331
  updateBinaryInPlace
332
332
  };
333
- //# sourceMappingURL=chunk-5G2T4IJO.js.map
333
+ //# sourceMappingURL=chunk-QLR4EWJG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/updater.ts"],"sourcesContent":["/**\n * Self-update logic for `gpc update`.\n *\n * All functions here are pure / testable — no Commander.js dependency.\n * The command layer in commands/update.ts handles output and flags.\n */\n\nimport { createWriteStream } from \"node:fs\";\nimport { rename, chmod, unlink, readdir } from \"node:fs/promises\";\nimport { realpathSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable, Transform } from \"node:stream\";\nimport { spawn } from \"node:child_process\";\nimport { sha256File } from \"@gpc-cli/core\";\nimport { isNewerVersion } from \"./update-check.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type InstallMethod = \"npm\" | \"homebrew\" | \"binary\" | \"unknown\";\n\nexport interface GithubAsset {\n name: string;\n browser_download_url: string;\n size: number;\n}\n\nexport interface GithubRelease {\n tag_name: string;\n html_url: string;\n assets: GithubAsset[];\n}\n\nexport interface UpdateCheckResult {\n current: string;\n latest: string;\n latestTag: string;\n updateAvailable: boolean;\n installMethod: InstallMethod;\n release: GithubRelease;\n}\n\nconst GITHUB_API_URL = \"https://api.github.com/repos/yasserstudio/gpc/releases/latest\";\nconst GITHUB_TIMEOUT_MS = 10_000;\nconst DOWNLOAD_TIMEOUT_MS = 120_000;\n\n// ---------------------------------------------------------------------------\n// Install method detection\n// ---------------------------------------------------------------------------\n\n/**\n * Detect how gpc was installed.\n *\n * Priority:\n * 1. __GPC_BINARY env var (injected by esbuild at compile time) → \"binary\"\n * 2. npm_config_prefix env var → \"npm\"\n * 3. realpathSync(process.argv[1]) contains \"cellar\" or \"homebrew\" → \"homebrew\"\n * 4. realpathSync(process.argv[1]) contains \"node_modules\" → \"npm\"\n * 5. fallback → \"unknown\"\n *\n * Using realpathSync(process.argv[1]) instead of shelling to `which gpc`:\n * - No child process spawn\n * - Works on Windows without `where.exe`\n * - Resolves symlinks — critical for Intel Mac Homebrew where the bin path\n * is a symlink but the real path contains \"Cellar\"\n */\nexport function detectInstallMethod(): InstallMethod {\n // 1. Compiled binary — but Homebrew also distributes as compiled binary, check execPath\n if (process.env[\"__GPC_BINARY\"] === \"1\") {\n try {\n const resolved = realpathSync(process.execPath).toLowerCase();\n if (resolved.includes(\"cellar\") || resolved.includes(\"homebrew\")) return \"homebrew\";\n } catch {\n /* ignore */\n }\n return \"binary\";\n }\n\n // 2. npm global install\n if (process.env[\"npm_config_prefix\"]) return \"npm\";\n\n // 3. Resolve symlinks and inspect path\n try {\n const resolved = realpathSync(process.argv[1] ?? \"\").toLowerCase();\n if (resolved.includes(\"cellar\") || resolved.includes(\"homebrew\")) return \"homebrew\";\n if (resolved.includes(\"node_modules\")) return \"npm\";\n } catch {\n // realpathSync can throw if the path doesn't exist — fall through to unknown\n }\n\n return \"unknown\";\n}\n\n// ---------------------------------------------------------------------------\n// Platform asset mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the GitHub release asset name for the current platform/arch,\n * matching the names produced by scripts/build-binary.ts TARGETS map.\n */\nexport function getPlatformAsset(): string | null {\n const arch = process.arch === \"arm64\" ? \"arm64\" : \"x64\";\n switch (process.platform) {\n case \"darwin\":\n return `gpc-darwin-${arch}`;\n case \"linux\":\n return `gpc-linux-${arch}`;\n case \"win32\":\n return \"gpc-windows-x64.exe\";\n default:\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Current binary path\n// ---------------------------------------------------------------------------\n\n/**\n * Returns the path of the currently running gpc binary.\n * For compiled binaries, process.execPath IS the binary.\n * For npm/dev installs, process.argv[1] is the script entrypoint.\n */\nexport function getCurrentBinaryPath(): string {\n if (process.env[\"__GPC_BINARY\"] === \"1\") return process.execPath;\n return process.argv[1] ?? process.execPath;\n}\n\n// ---------------------------------------------------------------------------\n// GitHub Releases API\n// ---------------------------------------------------------------------------\n\nfunction getGithubToken(): string | undefined {\n return process.env[\"GPC_GITHUB_TOKEN\"] || process.env[\"GITHUB_TOKEN\"] || undefined;\n}\n\nfunction githubApiHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"User-Agent\": \"gpc-cli\",\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n };\n const token = getGithubToken();\n if (token) {\n headers[\"Authorization\"] = `Bearer ${token}`;\n }\n return headers;\n}\n\nfunction githubDownloadHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"User-Agent\": \"gpc-cli\",\n };\n const token = getGithubToken();\n if (token) {\n headers[\"Authorization\"] = `Bearer ${token}`;\n }\n return headers;\n}\n\nexport async function fetchLatestRelease(): Promise<GithubRelease> {\n let response: Response;\n try {\n response = await fetch(GITHUB_API_URL, {\n headers: githubApiHeaders(),\n signal: AbortSignal.timeout(GITHUB_TIMEOUT_MS),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw Object.assign(new Error(`Network error checking for updates: ${msg}`), {\n code: \"NETWORK_ERROR\",\n exitCode: 5,\n });\n }\n\n if (\n response.status === 429 ||\n (response.status === 403 && response.headers.get(\"x-ratelimit-remaining\") === \"0\")\n ) {\n throw Object.assign(\n new Error(\n \"GitHub API rate limit exceeded. Set GPC_GITHUB_TOKEN or GITHUB_TOKEN to increase the limit.\",\n ),\n {\n code: \"UPDATE_RATE_LIMITED\",\n exitCode: 4,\n suggestion: \"export GPC_GITHUB_TOKEN=ghp_... (a personal access token with no scopes)\",\n },\n );\n }\n\n if (!response.ok) {\n throw Object.assign(new Error(`GitHub API returned HTTP ${response.status}`), {\n code: \"UPDATE_API_ERROR\",\n exitCode: 4,\n });\n }\n\n return (await response.json()) as GithubRelease;\n}\n\n/**\n * Fetch and parse checksums.txt from the release assets.\n * Returns a Map of filename → lowercase sha256 hex.\n * Returns an empty Map if the asset is missing or the fetch fails.\n */\nexport async function fetchChecksums(release: GithubRelease): Promise<Map<string, string>> {\n const asset = release.assets.find((a) => a.name === \"checksums.txt\");\n if (!asset) return new Map();\n\n try {\n const response = await fetch(asset.browser_download_url, {\n headers: githubDownloadHeaders(),\n signal: AbortSignal.timeout(GITHUB_TIMEOUT_MS),\n });\n if (!response.ok) return new Map();\n\n const map = new Map<string, string>();\n for (const line of (await response.text()).split(\"\\n\")) {\n const parts = line.trim().split(/\\s+/);\n const hash = parts[0];\n const name = parts[1];\n if (hash && name) map.set(name, hash.toLowerCase());\n }\n return map;\n } catch {\n return new Map();\n }\n}\n\n// ---------------------------------------------------------------------------\n// High-level update check\n// ---------------------------------------------------------------------------\n\nexport async function checkForUpdate(currentVersion: string): Promise<UpdateCheckResult> {\n const release = await fetchLatestRelease();\n const latest = release.tag_name.replace(/^v/, \"\");\n return {\n current: currentVersion,\n latest,\n latestTag: release.tag_name,\n updateAvailable: isNewerVersion(currentVersion, latest),\n installMethod: detectInstallMethod(),\n release,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Update execution paths\n// ---------------------------------------------------------------------------\n\nexport async function updateViaNpm(options: { silent?: boolean } = {}): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(\"npm\", [\"install\", \"-g\", \"@gpc-cli/cli@latest\"], {\n // In silent (JSON) mode, redirect npm's stdout to stderr so it doesn't\n // pollute the machine-readable JSON that gpc writes to stdout.\n stdio: options.silent ? [\"inherit\", process.stderr, process.stderr] : \"inherit\",\n shell: false,\n });\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(\n Object.assign(new Error(`npm exited with code ${code}`), {\n code: \"UPDATE_NPM_FAILED\",\n exitCode: 1,\n suggestion: \"Run manually: npm install -g @gpc-cli/cli@latest\",\n }),\n );\n }\n });\n proc.on(\"error\", (err) => {\n reject(\n Object.assign(new Error(`Failed to run npm: ${err.message}`), {\n code: \"UPDATE_NPM_SPAWN_FAILED\",\n exitCode: 1,\n suggestion: \"Ensure npm is in your PATH\",\n }),\n );\n });\n });\n}\n\nexport async function updateViaBrew(options: { silent?: boolean } = {}): Promise<void> {\n return new Promise((resolve, reject) => {\n const proc = spawn(\"brew\", [\"upgrade\", \"yasserstudio/tap/gpc\"], {\n // In silent (JSON) mode, redirect brew's stdout to stderr so it doesn't\n // pollute the machine-readable JSON that gpc writes to stdout.\n stdio: options.silent ? [\"inherit\", process.stderr, process.stderr] : \"inherit\",\n shell: false,\n });\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(\n Object.assign(new Error(`brew exited with code ${code}`), {\n code: \"UPDATE_BREW_FAILED\",\n exitCode: 1,\n suggestion: \"Run manually: brew upgrade yasserstudio/tap/gpc\",\n }),\n );\n }\n });\n proc.on(\"error\", (err) => {\n reject(\n Object.assign(new Error(`Failed to run brew: ${err.message}`), {\n code: \"UPDATE_BREW_SPAWN_FAILED\",\n exitCode: 1,\n suggestion: \"Ensure Homebrew is installed: https://brew.sh\",\n }),\n );\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Binary in-place replace\n// ---------------------------------------------------------------------------\n\nfunction isPermissionError(err: unknown): boolean {\n return err instanceof Error && \"code\" in err && (err.code === \"EACCES\" || err.code === \"EPERM\");\n}\n\n// sha256File imported from @gpc-cli/core\n\n/**\n * Clean up stale `.gpc-old-*` and `.gpc-update-*.tmp` files left by\n * previous update attempts (e.g. Windows EBUSY on unlink).\n * Fire-and-forget — errors are silently ignored.\n */\nexport function cleanupStaleUpdateFiles(binaryPath: string): void {\n const dir = dirname(binaryPath);\n readdir(dir)\n .then((files) => {\n for (const f of files) {\n if (f.startsWith(\".gpc-old-\") || f.startsWith(\".gpc-update-\")) {\n unlink(join(dir, f)).catch(() => {});\n }\n }\n })\n .catch(() => {});\n}\n\n/**\n * Download a new binary and atomically replace the current one.\n *\n * macOS/Linux: rename(tmp, current) — safe because open files can be replaced\n * Windows: rename(current, .old) then rename(tmp, current) — avoids EBUSY\n * because Windows locks running executables\n */\nexport async function updateBinaryInPlace(\n assetUrl: string,\n expectedSha256: string,\n currentBinaryPath: string,\n options: { onProgress?: (downloaded: number, total: number) => void } = {},\n): Promise<void> {\n const dir = dirname(currentBinaryPath);\n const tmpPath = join(dir, `.gpc-update-${process.pid}.tmp`);\n const oldPath = join(dir, `.gpc-old-${process.pid}`);\n\n try {\n // 1. Download\n let response: Response;\n try {\n response = await fetch(assetUrl, {\n headers: githubDownloadHeaders(),\n signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw Object.assign(new Error(`Download failed: ${msg}`), {\n code: \"UPDATE_DOWNLOAD_FAILED\",\n exitCode: 5,\n });\n }\n\n if (!response.ok) {\n throw Object.assign(new Error(`Download failed: HTTP ${response.status}`), {\n code: \"UPDATE_DOWNLOAD_FAILED\",\n exitCode: 4,\n });\n }\n if (!response.body) {\n throw Object.assign(new Error(\"Empty response body\"), {\n code: \"UPDATE_DOWNLOAD_FAILED\",\n exitCode: 4,\n });\n }\n\n const contentLength = response.headers.get(\"content-length\");\n const total = contentLength ? parseInt(contentLength, 10) : 0;\n let downloaded = 0;\n\n const dest = createWriteStream(tmpPath);\n const { onProgress } = options;\n\n if (onProgress) {\n const tracker = new Transform({\n transform(chunk: Buffer, _enc, cb) {\n downloaded += chunk.length;\n onProgress(downloaded, total);\n cb(null, chunk);\n },\n });\n await pipeline(\n Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]),\n tracker,\n dest,\n );\n } else {\n await pipeline(\n Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]),\n dest,\n );\n }\n\n // 2. Verify checksum (skip if no checksum available)\n if (expectedSha256) {\n const actual = await sha256File(tmpPath);\n if (actual !== expectedSha256.toLowerCase()) {\n throw Object.assign(\n new Error(`Checksum mismatch — expected ${expectedSha256}, got ${actual}`),\n {\n code: \"UPDATE_CHECKSUM_MISMATCH\",\n exitCode: 1,\n suggestion: \"The download may be corrupt. Try again.\",\n },\n );\n }\n }\n\n // 3. Set executable bit (no-op on Windows)\n if (process.platform !== \"win32\") {\n await chmod(tmpPath, 0o755);\n }\n\n // 4. Atomic replace\n if (process.platform === \"win32\") {\n // Windows locks running executables, so we rename the current binary\n // out of the way first, then move the new one into place\n await rename(currentBinaryPath, oldPath);\n try {\n await rename(tmpPath, currentBinaryPath);\n } catch (renameErr) {\n // Roll back — restore original binary\n await rename(oldPath, currentBinaryPath).catch(() => {});\n throw renameErr;\n }\n // Delete the old binary in the background (best-effort)\n unlink(oldPath).catch(() => {});\n } else {\n await rename(tmpPath, currentBinaryPath);\n }\n } catch (err) {\n // Clean up temp file on any error\n await unlink(tmpPath).catch(() => {});\n\n if (isPermissionError(err)) {\n throw Object.assign(new Error(`Permission denied replacing ${currentBinaryPath}`), {\n code: \"UPDATE_PERMISSION_DENIED\",\n exitCode: 1,\n suggestion: `Run with elevated permissions: sudo gpc update`,\n });\n }\n throw err;\n }\n}\n"],"mappings":"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","names":[]}
@@ -67,19 +67,19 @@ function registerPluginCommands(program, manager) {
67
67
  import { Command } from "commander";
68
68
  async function createProgram(pluginManager) {
69
69
  const program = new Command();
70
- program.name("gpc").description("GPC \u2014 Google Play Console CLI").version("0.9.69", "-V, --version").option("-o, --output <format>", "Output format: table, json, yaml, markdown, csv, tsv, junit").option("-v, --verbose", "Enable debug logging").option("-q, --quiet", "Suppress non-essential output").option("-a, --app <package>", "App package name").option("-p, --profile <name>", "Auth profile name").option("--no-color", "Disable colored output").option("--no-interactive", "Disable interactive prompts").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Preview changes without executing").option("--notify [target]", "Send webhook notification on completion (slack, discord, custom)").option("--ci", "Force CI mode (JSON output, no prompts, strict exit codes)").option("-j, --json", "Shorthand for --output json").option("--apps <csv>", "Comma-separated package names for multi-app operations").showSuggestionAfterError(false);
70
+ program.name("gpc").description("GPC \u2014 Google Play Console CLI").version("0.9.71", "-V, --version").option("-o, --output <format>", "Output format: table, json, yaml, markdown, csv, tsv, junit").option("-v, --verbose", "Enable debug logging").option("-q, --quiet", "Suppress non-essential output").option("-a, --app <package>", "App package name").option("-p, --profile <name>", "Auth profile name").option("--no-color", "Disable colored output").option("--no-interactive", "Disable interactive prompts").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Preview changes without executing").option("--notify [target]", "Send webhook notification on completion (slack, discord, custom)").option("--ci", "Force CI mode (JSON output, no prompts, strict exit codes)").option("-j, --json", "Shorthand for --output json").option("--apps <csv>", "Comma-separated package names for multi-app operations").showSuggestionAfterError(false);
71
71
  const commandLoaders = {
72
72
  auth: async () => {
73
73
  (await import("./auth-4DRT7ZH2.js")).registerAuthCommands(program);
74
74
  },
75
75
  config: async () => {
76
- (await import("./config-ZOWACWRK.js")).registerConfigCommands(program);
76
+ (await import("./config-YWZ5REXE.js")).registerConfigCommands(program);
77
77
  },
78
78
  doctor: async () => {
79
- (await import("./doctor-EKXMIWK3.js")).registerDoctorCommand(program);
79
+ (await import("./doctor-XGZPJNPN.js")).registerDoctorCommand(program);
80
80
  },
81
81
  update: async () => {
82
- (await import("./update-4GEB7YA4.js")).registerUpdateCommand(program);
82
+ (await import("./update-D7HC5W7B.js")).registerUpdateCommand(program);
83
83
  },
84
84
  docs: async () => {
85
85
  (await import("./docs-OU6LSSJD.js")).registerDocsCommand(program);
@@ -101,7 +101,7 @@ async function createProgram(pluginManager) {
101
101
  (await import("./apps-WPUQOQLL.js")).registerAppsCommands(program);
102
102
  },
103
103
  releases: async () => {
104
- (await import("./releases-P3ISQZ3F.js")).registerReleasesCommands(program);
104
+ (await import("./releases-WJXNU25H.js")).registerReleasesCommands(program);
105
105
  },
106
106
  tracks: async () => {
107
107
  (await import("./tracks-RH3RKVFB.js")).registerTracksCommands(program);
@@ -196,13 +196,13 @@ async function createProgram(pluginManager) {
196
196
  (await import("./verify-O2PSBTIC.js")).registerVerifyCommand(program);
197
197
  },
198
198
  version: async () => {
199
- (await import("./version-2P3QCXBN.js")).registerVersionCommand(program);
199
+ (await import("./version-4J57NSWF.js")).registerVersionCommand(program);
200
200
  },
201
201
  cache: async () => {
202
202
  (await import("./cache-FGNP7Y37.js")).registerCacheCommand(program);
203
203
  },
204
204
  feedback: async () => {
205
- (await import("./feedback-6GOFNCUK.js")).registerFeedbackCommand(program);
205
+ (await import("./feedback-IB2UMPWP.js")).registerFeedbackCommand(program);
206
206
  },
207
207
  setup: async () => {
208
208
  (await import("./setup-IKHZQJIH.js")).registerSetupCommand(program);
@@ -476,4 +476,4 @@ export {
476
476
  createProgram,
477
477
  handleCliError
478
478
  };
479
- //# sourceMappingURL=chunk-3M3SM2YH.js.map
479
+ //# sourceMappingURL=chunk-RGSWTGKV.js.map
@@ -78,7 +78,7 @@ Configuration file created: ${path}`);
78
78
  });
79
79
  console.log("\nVerifying setup...");
80
80
  try {
81
- const { registerDoctorCommand } = await import("./doctor-EKXMIWK3.js");
81
+ const { registerDoctorCommand } = await import("./doctor-XGZPJNPN.js");
82
82
  const { Command } = await import("commander");
83
83
  const doctorProgram = new Command();
84
84
  doctorProgram.option("-o, --output <format>", "Output format").option("-j, --json", "JSON mode");
@@ -107,4 +107,4 @@ Configuration file created: ${path}`);
107
107
  export {
108
108
  registerConfigCommands
109
109
  };
110
- //# sourceMappingURL=config-ZOWACWRK.js.map
110
+ //# sourceMappingURL=config-YWZ5REXE.js.map
@@ -141,7 +141,7 @@ function checkCiEnvironment() {
141
141
  };
142
142
  }
143
143
  async function checkGpcVersion() {
144
- const currentVersion = "0.9.69";
144
+ const currentVersion = "0.9.71";
145
145
  if (currentVersion === "0.0.0") {
146
146
  return { name: "version", status: "info", message: "GPC development build" };
147
147
  }
@@ -460,6 +460,68 @@ async function checkShellCompletion() {
460
460
  suggestion: "Install with: gpc completion install"
461
461
  };
462
462
  }
463
+ async function checkQuotaProximity() {
464
+ try {
465
+ const { getQuotaUsage } = await import("@gpc-cli/core");
466
+ const usage = await getQuotaUsage();
467
+ if (usage.dailyCallsUsed === 0) return null;
468
+ if (usage.dailyCallsLimit === 0 || usage.minuteCallsLimit === 0) return null;
469
+ const minutePct = usage.minuteCallsUsed / usage.minuteCallsLimit;
470
+ if (minutePct > 0.8) {
471
+ return {
472
+ name: "quota",
473
+ status: "warn",
474
+ message: `Per-minute quota: ${usage.minuteCallsUsed}/${usage.minuteCallsLimit} (${Math.round(minutePct * 100)}%)`,
475
+ suggestion: "You are approaching the per-minute rate limit. Space out API calls or wait before retrying."
476
+ };
477
+ }
478
+ const dailyPct = usage.dailyCallsUsed / usage.dailyCallsLimit;
479
+ if (dailyPct > 0.8) {
480
+ return {
481
+ name: "quota",
482
+ status: "warn",
483
+ message: `Daily quota: ${usage.dailyCallsUsed}/${usage.dailyCallsLimit} (${Math.round(dailyPct * 100)}%)`,
484
+ suggestion: "You are approaching the daily API call limit. Monitor usage with: gpc quota status"
485
+ };
486
+ }
487
+ return {
488
+ name: "quota",
489
+ status: "pass",
490
+ message: `Quota: ${usage.dailyCallsUsed}/${usage.dailyCallsLimit} daily, ${usage.minuteCallsUsed}/${usage.minuteCallsLimit}/min`
491
+ };
492
+ } catch {
493
+ return null;
494
+ }
495
+ }
496
+ async function checkPluginHealth(configPlugins) {
497
+ try {
498
+ const { discoverPlugins, PluginManager } = await import("@gpc-cli/core");
499
+ const plugins = await discoverPlugins({ configPlugins });
500
+ if (plugins.length === 0) return [];
501
+ const results = [];
502
+ const manager = new PluginManager();
503
+ for (const plugin of plugins) {
504
+ try {
505
+ await manager.load(plugin);
506
+ results.push({
507
+ name: `plugin-${plugin.name}`,
508
+ status: "pass",
509
+ message: `Plugin: ${plugin.name}@${plugin.version ?? "unknown"}`
510
+ });
511
+ } catch {
512
+ results.push({
513
+ name: `plugin-${plugin.name}`,
514
+ status: "warn",
515
+ message: `Plugin failed to load: ${plugin.name}`,
516
+ suggestion: `Try reinstalling: npm install ${plugin.name}`
517
+ });
518
+ }
519
+ }
520
+ return results;
521
+ } catch {
522
+ return [];
523
+ }
524
+ }
463
525
  async function checkSigningKey(packageName, accessToken, keystorePath, storePassword, keyAlias) {
464
526
  const results = [];
465
527
  const baseUrl = `https://${API_HOST}/androidpublisher/v3/applications/${encodeURIComponent(packageName)}`;
@@ -948,6 +1010,10 @@ function registerDoctorCommand(program) {
948
1010
  if (staleCacheResult) results.push(staleCacheResult);
949
1011
  const completionResult = await checkShellCompletion();
950
1012
  if (completionResult) results.push(completionResult);
1013
+ const quotaResult = await checkQuotaProximity();
1014
+ if (quotaResult) results.push(quotaResult);
1015
+ const pluginResults = await checkPluginHealth(config?.plugins);
1016
+ results.push(...pluginResults);
951
1017
  if (opts["verify"] && accessToken && config?.app) {
952
1018
  const ksPath = opts["keystore"] ?? process.env["GPC_KEYSTORE_PATH"];
953
1019
  const ksPass = opts["storePass"] ?? process.env["GPC_STORE_PASSWORD"];
@@ -1037,10 +1103,12 @@ export {
1037
1103
  checkDeveloperId,
1038
1104
  checkNodeVersion,
1039
1105
  checkPackageName,
1106
+ checkPluginHealth,
1040
1107
  checkProxy,
1108
+ checkQuotaProximity,
1041
1109
  checkShellCompletion,
1042
1110
  checkStaleCache,
1043
1111
  checkVerificationDeadline,
1044
1112
  registerDoctorCommand
1045
1113
  };
1046
- //# sourceMappingURL=doctor-EKXMIWK3.js.map
1114
+ //# sourceMappingURL=doctor-XGZPJNPN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig, getCacheDir, getConfigDir } from \"@gpc-cli/config\";\nimport { green, red, yellow } from \"../colors.js\";\nimport { resolveAuth, AuthError } from \"@gpc-cli/auth\";\nimport { existsSync, accessSync, statSync, constants } from \"node:fs\";\nimport { readFile, readdir, stat, statfs } from \"node:fs/promises\";\nimport { resolve, join } from \"node:path\";\nimport { lookup } from \"node:dns/promises\";\nimport { isNewerVersion } from \"../update-check.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface CheckResult {\n name: string;\n status: \"pass\" | \"fail\" | \"warn\" | \"info\";\n message: string;\n suggestion?: string;\n /** Structured data for applyFix — avoids fragile regex on suggestion text. */\n fixData?: Record<string, string>;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst PASS = \"\\u2713\";\nconst FAIL = \"\\u2717\";\nconst WARN = \"\\u26A0\";\nconst INFO = \"-\";\n\nconst ANDROID_PACKAGE_RE = /^[a-zA-Z][a-zA-Z0-9_]*(\\.[a-zA-Z][a-zA-Z0-9_]*)+$/;\n\n/** All user-facing keys accepted in .gpcrc.json / config.json. */\nconst KNOWN_CONFIG_KEYS = new Set([\n \"app\",\n \"output\",\n \"profile\",\n \"auth\",\n \"developerId\",\n \"plugins\",\n \"profiles\",\n \"approvedPlugins\",\n \"webhooks\",\n \"debug\",\n \"train\",\n]);\n\nconst NPM_REGISTRY_URL = \"https://registry.npmjs.org/@gpc-cli/cli/latest\";\nconst API_HOST = \"androidpublisher.googleapis.com\";\nconst REPORTING_HOST = \"playdeveloperreporting.googleapis.com\";\nconst SA_KEY_ROTATION_DAYS = 90;\n\n// ---------------------------------------------------------------------------\n// Display helpers\n// ---------------------------------------------------------------------------\n\nfunction icon(status: CheckResult[\"status\"]): string {\n switch (status) {\n case \"pass\":\n return green(PASS);\n case \"fail\":\n return red(FAIL);\n case \"warn\":\n return yellow(WARN);\n case \"info\":\n return INFO;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Pure, testable check helpers\n// ---------------------------------------------------------------------------\n\nexport function checkNodeVersion(nodeVersion: string): CheckResult {\n const major = parseInt(nodeVersion.split(\".\")[0] ?? \"0\", 10);\n return major >= 20\n ? { name: \"node\", status: \"pass\", message: `Node.js ${nodeVersion}` }\n : {\n name: \"node\",\n status: \"fail\",\n message: `Node.js ${nodeVersion} (requires >=20)`,\n suggestion: \"Upgrade Node.js to v20 or later: https://nodejs.org\",\n };\n}\n\nexport function checkPackageName(app: string | undefined): CheckResult | null {\n if (!app) return null;\n return ANDROID_PACKAGE_RE.test(app)\n ? { name: \"package-name\", status: \"pass\", message: `Package name format OK: ${app}` }\n : {\n name: \"package-name\",\n status: \"warn\",\n message: `Package name may be invalid: ${app}`,\n suggestion:\n \"Android package names must have 2+ dot-separated segments, each starting with a letter (e.g. com.example.app)\",\n };\n}\n\nexport function checkProxy(url: string | undefined): CheckResult | null {\n if (!url) return null;\n try {\n new URL(url);\n return { name: \"proxy\", status: \"pass\", message: `Proxy configured: ${url}` };\n } catch {\n return {\n name: \"proxy\",\n status: \"warn\",\n message: `Invalid proxy URL: ${url}`,\n suggestion: \"Set HTTPS_PROXY to a valid URL (e.g. http://proxy.example.com:8080)\",\n };\n }\n}\n\nexport function checkDeveloperId(id: string | undefined): CheckResult | null {\n if (!id) return null;\n if (/^\\d+$/.test(id)) {\n return { name: \"developer-id\", status: \"pass\", message: `Developer ID: ${id}` };\n }\n return {\n name: \"developer-id\",\n status: \"warn\",\n message: `Developer ID may be invalid: ${id}`,\n suggestion:\n \"Developer IDs are numeric. Find yours at: Play Console → Settings → Developer account → Developer ID\",\n };\n}\n\nexport function checkConflictingCredentials(configSaPath?: string): CheckResult | null {\n const sources: string[] = [];\n if (configSaPath) sources.push(\"config file (auth.serviceAccount)\");\n if (process.env[\"GPC_SERVICE_ACCOUNT\"]) sources.push(\"GPC_SERVICE_ACCOUNT env var\");\n if (process.env[\"GOOGLE_APPLICATION_CREDENTIALS\"])\n sources.push(\"GOOGLE_APPLICATION_CREDENTIALS env var\");\n\n if (sources.length <= 1) return null;\n return {\n name: \"credentials-conflict\",\n status: \"warn\",\n message: `Multiple credential sources: ${sources.join(\", \")}`,\n suggestion:\n \"GPC uses the first match: config file → GPC_SERVICE_ACCOUNT → GOOGLE_APPLICATION_CREDENTIALS → ADC. Remove unused sources to avoid confusion.\",\n };\n}\n\nexport function checkConfigKeys(config: Record<string, unknown>): CheckResult | null {\n const unknown = Object.keys(config).filter((k) => !KNOWN_CONFIG_KEYS.has(k));\n if (unknown.length === 0) return null;\n return {\n name: \"config-keys\",\n status: \"warn\",\n message: `Unknown config key${unknown.length > 1 ? \"s\" : \"\"}: ${unknown.join(\", \")}`,\n suggestion: `Valid keys: ${[...KNOWN_CONFIG_KEYS].sort().join(\", \")}`,\n fixData: { keys: unknown.join(\", \") },\n };\n}\n\nexport function checkCiEnvironment(): CheckResult | null {\n if (!process.env[\"CI\"]) return null;\n\n let platform = \"Unknown CI\";\n if (process.env[\"GITHUB_ACTIONS\"]) platform = \"GitHub Actions\";\n else if (process.env[\"GITLAB_CI\"]) platform = \"GitLab CI\";\n else if (process.env[\"BITBUCKET_PIPELINE_UUID\"]) platform = \"Bitbucket Pipelines\";\n else if (process.env[\"CIRCLECI\"]) platform = \"CircleCI\";\n else if (process.env[\"JENKINS_URL\"]) platform = \"Jenkins\";\n else if (process.env[\"TRAVIS\"]) platform = \"Travis CI\";\n else if (process.env[\"CODEBUILD_BUILD_ID\"]) platform = \"AWS CodeBuild\";\n else if (process.env[\"BUILD_BUILDID\"]) platform = \"Azure Pipelines\";\n\n const tips: string[] = [];\n if (!process.env[\"GPC_NO_COLOR\"]) tips.push(\"Set GPC_NO_COLOR=1 for clean logs\");\n if (!process.env[\"GPC_NO_UPDATE_CHECK\"])\n tips.push(\"Set GPC_NO_UPDATE_CHECK=1 to skip update checks\");\n\n return {\n name: \"ci\",\n status: \"info\",\n message: `CI detected: ${platform}`,\n suggestion: tips.length > 0 ? tips.join(\". \") : undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Async check helpers\n// ---------------------------------------------------------------------------\n\nasync function checkGpcVersion(): Promise<CheckResult> {\n const currentVersion = process.env[\"__GPC_VERSION\"] ?? \"0.0.0\";\n if (currentVersion === \"0.0.0\") {\n return { name: \"version\", status: \"info\", message: \"GPC development build\" };\n }\n try {\n const resp = await fetch(NPM_REGISTRY_URL, {\n signal: AbortSignal.timeout(3000),\n });\n if (!resp.ok) return { name: \"version\", status: \"pass\", message: `GPC v${currentVersion}` };\n const body = (await resp.json()) as { version?: string };\n if (!body.version)\n return { name: \"version\", status: \"pass\", message: `GPC v${currentVersion}` };\n\n if (isNewerVersion(currentVersion, body.version)) {\n return {\n name: \"version\",\n status: \"warn\",\n message: `GPC v${currentVersion} (v${body.version} available)`,\n suggestion: \"Run: gpc update\",\n };\n }\n return {\n name: \"version\",\n status: \"pass\",\n message: `GPC v${currentVersion} (up to date)`,\n };\n } catch {\n return { name: \"version\", status: \"pass\", message: `GPC v${currentVersion}` };\n }\n}\n\nasync function checkDiskSpace(dir: string): Promise<CheckResult> {\n try {\n const stats = await statfs(dir);\n const availableGB = (Number(stats.bavail) * Number(stats.bsize)) / 1024 ** 3;\n if (availableGB < 0.1) {\n return {\n name: \"disk-space\",\n status: \"warn\",\n message: `Low disk space: ${availableGB.toFixed(1)} GB available`,\n suggestion: \"Free up disk space — AAB uploads can be up to 2 GB\",\n };\n }\n return {\n name: \"disk-space\",\n status: \"pass\",\n message: `Disk space: ${availableGB.toFixed(1)} GB available`,\n };\n } catch {\n // statfs may fail on some filesystems (network mounts, etc.)\n return { name: \"disk-space\", status: \"info\", message: \"Could not check disk space\" };\n }\n}\n\nasync function checkSaKeyAge(saPath: string): Promise<CheckResult | null> {\n try {\n const stats = await stat(saPath);\n const ageDays = Math.floor((Date.now() - stats.mtimeMs) / (1000 * 60 * 60 * 24));\n if (ageDays > SA_KEY_ROTATION_DAYS) {\n return {\n name: \"service-account-age\",\n status: \"warn\",\n message: `Service account key is ${ageDays} days old`,\n suggestion: `Google recommends rotating service account keys every ${SA_KEY_ROTATION_DAYS} days`,\n };\n }\n return null; // Don't clutter output when key is fresh\n } catch {\n return null;\n }\n}\n\nasync function checkTokenCache(cacheDir: string): Promise<CheckResult | null> {\n const cachePath = join(cacheDir, \"token-cache.json\");\n try {\n if (!existsSync(cachePath)) return null;\n const content = await readFile(cachePath, \"utf-8\");\n JSON.parse(content);\n return { name: \"token-cache\", status: \"pass\", message: \"Token cache OK\" };\n } catch {\n return {\n name: \"token-cache\",\n status: \"warn\",\n message: \"Token cache is corrupt\",\n suggestion: \"Clear with: gpc cache clear\",\n fixData: { path: cachePath },\n };\n }\n}\n\nasync function probeHttps(\n host: string,\n timeoutMs = 5000,\n): Promise<{ ok: boolean; latencyMs: number; error?: string }> {\n // Use fetch (undici under the hood) instead of raw tls.connect so the probe\n // exercises the same HTTP stack as every real API call the rest of GPC\n // makes. A raw tls.connect would bypass any configured undici dispatcher,\n // HTTPS_PROXY, NODE_EXTRA_CA_CERTS injection, or TLS-intercepting corporate\n // proxy — and report a misleading \"self-signed certificate\" failure on\n // hosts that the actual API calls reach fine. Any HTTP response (including\n // 4xx/5xx) proves we successfully talked to the host; only fetch-level\n // errors (network, DNS, TLS) indicate real connectivity problems.\n const start = performance.now();\n try {\n const response = await fetch(`https://${host}/`, {\n method: \"HEAD\",\n signal: AbortSignal.timeout(timeoutMs),\n redirect: \"manual\",\n });\n // Consume (and discard) any response body to let the connection close\n // cleanly without leaking the stream.\n await response.body?.cancel?.().catch(() => {});\n const latencyMs = Math.round(performance.now() - start);\n return { ok: true, latencyMs };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n // AbortSignal.timeout fires with a TimeoutError name.\n const isTimeout =\n err instanceof Error && (err.name === \"TimeoutError\" || /timeout/i.test(err.message));\n return {\n ok: false,\n latencyMs: 0,\n error: isTimeout ? \"Connection timed out\" : message,\n };\n }\n}\n\nasync function checkAppAccess(packageName: string, accessToken: string): Promise<CheckResult> {\n try {\n const insertResp = await fetch(\n `https://${API_HOST}/androidpublisher/v3/applications/${encodeURIComponent(packageName)}/edits`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({}),\n signal: AbortSignal.timeout(10_000),\n },\n );\n\n if (!insertResp.ok) {\n const body = (await insertResp.json().catch(() => ({}))) as {\n error?: { message?: string; status?: string };\n };\n\n // API not enabled in GCP project\n if (\n body.error?.status === \"PERMISSION_DENIED\" &&\n body.error?.message?.includes(\"has not been used\")\n ) {\n return {\n name: \"app-access\",\n status: \"fail\",\n message: \"Google Play Android Developer API is not enabled\",\n suggestion:\n \"Enable it: https://console.cloud.google.com/apis/api/androidpublisher.googleapis.com\",\n };\n }\n\n if (insertResp.status === 403) {\n return {\n name: \"app-access\",\n status: \"fail\",\n message: `No access to ${packageName}`,\n suggestion:\n \"Grant the service account access in Google Play Console → Users and permissions\",\n };\n }\n if (insertResp.status === 404) {\n return {\n name: \"app-access\",\n status: \"fail\",\n message: `App not found: ${packageName}`,\n suggestion: \"Check the package name with: gpc config get app\",\n };\n }\n return {\n name: \"app-access\",\n status: \"fail\",\n message: `App access check failed: HTTP ${insertResp.status}`,\n suggestion: body.error?.message ?? \"Check your credentials and app configuration\",\n };\n }\n\n // Clean up the test edit\n const edit = (await insertResp.json()) as { id?: string };\n if (edit.id) {\n await fetch(\n `https://${API_HOST}/androidpublisher/v3/applications/${encodeURIComponent(packageName)}/edits/${edit.id}`,\n {\n method: \"DELETE\",\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(5000),\n },\n ).catch(() => {});\n }\n\n return {\n name: \"app-access\",\n status: \"pass\",\n message: `App access verified: ${packageName}`,\n };\n } catch (err) {\n return {\n name: \"app-access\",\n status: \"warn\",\n message: `Could not verify app access: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Enterprise / Play Custom App Publishing API probe\n// ---------------------------------------------------------------------------\n\n/**\n * Best-effort probe of the Play Custom App Publishing API.\n *\n * The Custom App API only exposes `accounts.customApps.create` (POST). There's\n * no read-only endpoint to probe with, so we issue a GET against the collection\n * URL — which the API doesn't support. The response code reveals what we can\n * and can't do:\n *\n * - 400 / 404 / 405 → API reachable, auth working, permission likely present\n * - 403 → \"create and publish private apps\" permission is missing\n * - 401 → auth misconfigured (already caught by other doctor checks)\n * - network/timeout → inconclusive, return info status\n *\n * This is best-effort. A passing result doesn't guarantee `gpc enterprise publish`\n * will succeed against a specific enterprise — that also depends on organization\n * membership. A failing result is a reliable signal that setup is incomplete.\n */\nasync function checkEnterpriseAccess(accessToken: string): Promise<CheckResult> {\n try {\n // Use account ID \"1\" as a harmless syntactic placeholder. We expect this\n // to be rejected (404 or 400), which tells us the API is reachable and\n // our auth is recognized.\n const response = await fetch(\n \"https://playcustomapp.googleapis.com/playcustomapp/v1/accounts/1/customApps\",\n {\n method: \"GET\",\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(10_000),\n },\n );\n\n if (response.status === 403) {\n const body = (await response.json().catch(() => ({}))) as {\n error?: { message?: string; status?: string };\n };\n\n // API not enabled in this Google Cloud project\n if (body.error?.message?.includes(\"has not been used\")) {\n return {\n name: \"enterprise-access\",\n status: \"warn\",\n message: \"Play Custom App Publishing API is not enabled for this project\",\n suggestion:\n \"Enable it (only required for `gpc enterprise publish`): https://console.cloud.google.com/apis/library/playcustomapp.googleapis.com\",\n };\n }\n\n return {\n name: \"enterprise-access\",\n status: \"warn\",\n message: \"Service account is missing the 'create and publish private apps' permission\",\n suggestion:\n \"In Play Console → Users and permissions, grant this service account the 'create and publish private apps' account-level permission. Only required if you use `gpc enterprise publish`.\",\n };\n }\n\n // 400 / 404 / 405 = API reachable, auth working, permission likely present.\n // Google returns 400 for invalid account IDs once it gets past auth/permission.\n if (response.status === 400 || response.status === 404 || response.status === 405) {\n return {\n name: \"enterprise-access\",\n status: \"pass\",\n message: \"Play Custom App Publishing API is reachable\",\n };\n }\n\n // 401 = auth problem; let other doctor checks flag that.\n if (response.status === 401) {\n return {\n name: \"enterprise-access\",\n status: \"info\",\n message: \"Enterprise API probe skipped (auth not ready)\",\n };\n }\n\n // Any other status — inconclusive, don't fail the doctor run.\n return {\n name: \"enterprise-access\",\n status: \"info\",\n message: `Enterprise API probe inconclusive (HTTP ${response.status})`,\n suggestion: \"This probe is best-effort. Run `gpc enterprise publish` to verify end-to-end.\",\n };\n } catch (err) {\n return {\n name: \"enterprise-access\",\n status: \"info\",\n message: `Enterprise API probe skipped: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Verification deadline check\n// ---------------------------------------------------------------------------\n\nconst VERIFICATION_ENFORCEMENT = new Date(\"2026-09-30\");\n\nexport function checkVerificationDeadline(): CheckResult {\n const daysLeft = Math.ceil(\n (VERIFICATION_ENFORCEMENT.getTime() - Date.now()) / (1000 * 60 * 60 * 24),\n );\n if (daysLeft > 0) {\n return {\n name: \"verification\",\n status: daysLeft <= 90 ? \"warn\" : \"info\",\n message: `Android developer verification enforcement begins September 30, 2026 (${daysLeft} days, BR/ID/SG/TH)`,\n suggestion:\n \"Run 'gpc verify' for details or 'gpc verify checklist' for a readiness walkthrough\",\n };\n }\n return {\n name: \"verification\",\n status: \"warn\",\n message: \"Android developer verification is being enforced. Ensure your account is verified.\",\n suggestion: \"Run 'gpc verify checklist' to check your readiness\",\n };\n}\n\n// ---------------------------------------------------------------------------\n// Stale cache check\n// ---------------------------------------------------------------------------\n\nexport async function checkStaleCache(cacheDir: string): Promise<CheckResult | null> {\n const STALE_DAYS = 7;\n try {\n if (!existsSync(cacheDir)) return null;\n const files = await readdir(cacheDir);\n const statusFiles = files.filter((f) => f.startsWith(\"status-\") && f.endsWith(\".json\"));\n if (statusFiles.length === 0) return null;\n\n const stale: string[] = [];\n for (const file of statusFiles) {\n const filePath = join(cacheDir, file);\n const stats = await stat(filePath);\n const ageDays = Math.floor((Date.now() - stats.mtimeMs) / (1000 * 60 * 60 * 24));\n if (ageDays > STALE_DAYS) {\n stale.push(file.replace(\"status-\", \"\").replace(\".json\", \"\"));\n }\n }\n\n if (stale.length === 0) return null;\n return {\n name: \"stale-cache\",\n status: \"warn\",\n message: `Stale status cache (>${STALE_DAYS} days): ${stale.join(\", \")}`,\n suggestion: \"Refresh with: gpc status --refresh\",\n };\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shell completion check\n// ---------------------------------------------------------------------------\n\nexport async function checkShellCompletion(): Promise<CheckResult | null> {\n const shell = process.env[\"SHELL\"] ?? \"\";\n if (!shell) return null;\n\n const home = process.env[\"HOME\"] ?? \"\";\n if (!home) return null;\n\n const shellName = shell.split(\"/\").pop() ?? \"\";\n let installed = false;\n\n if (shellName === \"zsh\") {\n const rcPath = join(home, \".zshrc\");\n try {\n if (existsSync(rcPath)) {\n const rc = await readFile(rcPath, \"utf-8\");\n const fpath = process.env[\"FPATH\"] ?? \"\";\n installed = rc.includes(\"gpc\") && (rc.includes(\"compdef\") || fpath.includes(\"gpc\"));\n }\n } catch {\n // fall through\n }\n } else if (shellName === \"bash\") {\n const rcPath = join(home, \".bashrc\");\n try {\n if (existsSync(rcPath)) {\n const rc = await readFile(rcPath, \"utf-8\");\n installed = rc.includes(\"gpc\") && rc.includes(\"complete\");\n }\n } catch {\n // fall through\n }\n } else {\n return null;\n }\n\n if (installed) {\n return { name: \"shell-completion\", status: \"pass\", message: `Shell completion: ${shellName}` };\n }\n return {\n name: \"shell-completion\",\n status: \"info\",\n message: `Shell completion not detected for ${shellName}`,\n suggestion: \"Install with: gpc completion install\",\n };\n}\n\n// ---------------------------------------------------------------------------\n// Quota proximity check\n// ---------------------------------------------------------------------------\n\nexport async function checkQuotaProximity(): Promise<CheckResult | null> {\n try {\n const { getQuotaUsage } = await import(\"@gpc-cli/core\");\n const usage = await getQuotaUsage();\n\n if (usage.dailyCallsUsed === 0) return null;\n if (usage.dailyCallsLimit === 0 || usage.minuteCallsLimit === 0) return null;\n\n const minutePct = usage.minuteCallsUsed / usage.minuteCallsLimit;\n if (minutePct > 0.8) {\n return {\n name: \"quota\",\n status: \"warn\",\n message: `Per-minute quota: ${usage.minuteCallsUsed}/${usage.minuteCallsLimit} (${Math.round(minutePct * 100)}%)`,\n suggestion:\n \"You are approaching the per-minute rate limit. Space out API calls or wait before retrying.\",\n };\n }\n\n const dailyPct = usage.dailyCallsUsed / usage.dailyCallsLimit;\n if (dailyPct > 0.8) {\n return {\n name: \"quota\",\n status: \"warn\",\n message: `Daily quota: ${usage.dailyCallsUsed}/${usage.dailyCallsLimit} (${Math.round(dailyPct * 100)}%)`,\n suggestion: \"You are approaching the daily API call limit. Monitor usage with: gpc quota status\",\n };\n }\n\n return {\n name: \"quota\",\n status: \"pass\",\n message: `Quota: ${usage.dailyCallsUsed}/${usage.dailyCallsLimit} daily, ${usage.minuteCallsUsed}/${usage.minuteCallsLimit}/min`,\n };\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Plugin health check\n// ---------------------------------------------------------------------------\n\nexport async function checkPluginHealth(\n configPlugins?: string[],\n): Promise<CheckResult[]> {\n try {\n const { discoverPlugins, PluginManager } = await import(\"@gpc-cli/core\");\n const plugins = await discoverPlugins({ configPlugins });\n if (plugins.length === 0) return [];\n\n const results: CheckResult[] = [];\n const manager = new PluginManager();\n\n for (const plugin of plugins) {\n try {\n await manager.load(plugin);\n results.push({\n name: `plugin-${plugin.name}`,\n status: \"pass\",\n message: `Plugin: ${plugin.name}@${plugin.version ?? \"unknown\"}`,\n });\n } catch {\n results.push({\n name: `plugin-${plugin.name}`,\n status: \"warn\",\n message: `Plugin failed to load: ${plugin.name}`,\n suggestion: `Try reinstalling: npm install ${plugin.name}`,\n });\n }\n }\n\n return results;\n } catch {\n return [];\n }\n}\n\n// ---------------------------------------------------------------------------\n// Signing key verification (--verify)\n// ---------------------------------------------------------------------------\n\nasync function checkSigningKey(\n packageName: string,\n accessToken: string,\n keystorePath?: string,\n storePassword?: string,\n keyAlias?: string,\n): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n const baseUrl = `https://${API_HOST}/androidpublisher/v3/applications/${encodeURIComponent(packageName)}`;\n\n let apiFingerprint: string | undefined;\n let latestVersionCode: number | undefined;\n\n try {\n const editResp = await fetch(`${baseUrl}/edits`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${accessToken}`, \"Content-Type\": \"application/json\" },\n body: JSON.stringify({}),\n signal: AbortSignal.timeout(10_000),\n });\n if (!editResp.ok) {\n results.push({\n name: \"signing-api\",\n status: \"warn\",\n message: \"Could not create edit to check signing key\",\n });\n return results;\n }\n const edit = (await editResp.json()) as { id: string };\n\n try {\n const bundlesResp = await fetch(`${baseUrl}/edits/${edit.id}/bundles`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(10_000),\n });\n if (!bundlesResp.ok) {\n results.push({\n name: \"signing-api\",\n status: \"warn\",\n message: \"Could not list bundles\",\n });\n return results;\n }\n const bundlesData = (await bundlesResp.json()) as { bundles?: { versionCode: number }[] };\n const bundles = bundlesData.bundles ?? [];\n\n if (bundles.length === 0) {\n results.push({\n name: \"signing-api\",\n status: \"warn\",\n message: \"No bundles uploaded yet\",\n suggestion:\n \"Upload at least one AAB with 'gpc publish' to enable signing key verification\",\n });\n return results;\n }\n\n latestVersionCode = bundles.reduce((max, b) =>\n b.versionCode > max.versionCode ? b : max,\n ).versionCode;\n\n const apksResp = await fetch(`${baseUrl}/generatedApks/${latestVersionCode}`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(10_000),\n });\n if (apksResp.ok) {\n const apksData = (await apksResp.json()) as {\n generatedApks?: { certificateSha256Fingerprint?: string }[];\n };\n apiFingerprint = apksData.generatedApks?.[0]?.certificateSha256Fingerprint;\n }\n } finally {\n await fetch(`${baseUrl}/edits/${edit.id}`, {\n method: \"DELETE\",\n headers: { Authorization: `Bearer ${accessToken}` },\n signal: AbortSignal.timeout(5_000),\n }).catch(() => {});\n }\n } catch (err) {\n results.push({\n name: \"signing-api\",\n status: \"warn\",\n message: `Could not verify signing key: ${err instanceof Error ? err.message : String(err)}`,\n });\n return results;\n }\n\n if (apiFingerprint) {\n results.push({\n name: \"signing-api\",\n status: \"pass\",\n message: `Play signing cert (v${latestVersionCode}): ${apiFingerprint}`,\n });\n } else {\n results.push({\n name: \"signing-api\",\n status: \"warn\",\n message: `No signing certificate found for versionCode ${latestVersionCode}`,\n suggestion: \"Your app may not be enrolled in Play App Signing\",\n });\n return results;\n }\n\n if (!keystorePath) {\n results.push({\n name: \"signing-local\",\n status: \"info\",\n message: \"No local keystore provided for comparison\",\n suggestion:\n \"Provide --keystore <path> and --store-pass <password> to compare against Play signing cert\",\n });\n return results;\n }\n\n if (!storePassword) {\n results.push({\n name: \"signing-local\",\n status: \"warn\",\n message: \"Keystore path provided but no password\",\n suggestion: \"Provide --store-pass <password> or set GPC_STORE_PASSWORD\",\n });\n return results;\n }\n\n try {\n const { getKeystoreFingerprint, compareFingerprints } = await import(\"@gpc-cli/core\");\n const local = await getKeystoreFingerprint(keystorePath, storePassword, keyAlias);\n\n if (compareFingerprints(local.sha256, apiFingerprint)) {\n results.push({\n name: \"signing-local\",\n status: \"pass\",\n message: `Local keystore (${local.alias}) matches Play signing cert`,\n });\n } else {\n results.push({\n name: \"signing-local\",\n status: \"fail\",\n message: `Signing key mismatch: local ${local.sha256} vs Play ${apiFingerprint}`,\n suggestion:\n \"Your local keystore does not match the Play signing certificate. If you distribute outside Play with this key, register it in Play Console to avoid installation blocks after September 30, 2026.\",\n });\n }\n } catch (err) {\n const error = err as { code?: string; message?: string };\n if (error.code === \"KEYTOOL_NOT_FOUND\") {\n results.push({\n name: \"signing-local\",\n status: \"warn\",\n message: \"keytool not found\",\n suggestion: \"Install a JDK to enable local keystore verification\",\n });\n } else {\n results.push({\n name: \"signing-local\",\n status: \"warn\",\n message: `Could not read keystore: ${error.message ?? String(err)}`,\n });\n }\n }\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Auto-fix\n// ---------------------------------------------------------------------------\n\nasync function applyFix(check: CheckResult): Promise<string | null> {\n switch (check.name) {\n case \"config-dir\":\n case \"cache-dir\": {\n const dirMatch = check.message.match(/: (.+)$/);\n if (!dirMatch?.[1]) return null;\n const { mkdir } = await import(\"node:fs/promises\");\n await mkdir(dirMatch[1], {\n recursive: true,\n mode: check.name === \"cache-dir\" ? 0o700 : 0o755,\n });\n return `Created ${dirMatch[1]}`;\n }\n case \"service-account-permissions\": {\n const saPath = check.fixData?.[\"path\"];\n if (!saPath) return null;\n const { chmod } = await import(\"node:fs/promises\");\n await chmod(saPath, 0o600);\n return `Fixed permissions on ${saPath}`;\n }\n case \"token-cache\": {\n const cachePath = check.fixData?.[\"path\"];\n if (!cachePath) return null;\n const { unlink } = await import(\"node:fs/promises\");\n await unlink(cachePath);\n return `Cleared corrupt token cache`;\n }\n case \"config\": {\n const { initConfig } = await import(\"@gpc-cli/config\");\n await initConfig({});\n return \"Initialized config file\";\n }\n case \"version\": {\n // Suggest running gpc update\n return \"Run: gpc update\";\n }\n case \"auth\": {\n // Guide user to authenticate\n return \"Run: gpc auth login --service-account <path/to/key.json>\";\n }\n case \"config-keys\": {\n const keys = check.fixData?.[\"keys\"];\n if (!keys) return null;\n const { deleteConfigValue } = await import(\"@gpc-cli/config\");\n for (const key of keys.split(\",\")) {\n await deleteConfigValue(key.trim());\n }\n return `Removed unknown keys: ${keys}`;\n }\n default:\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Command registration\n// ---------------------------------------------------------------------------\n\nexport function registerDoctorCommand(program: Command): void {\n program\n .command(\"doctor\")\n .description(\"Verify setup and connectivity\")\n .option(\"--fix\", \"Attempt to auto-fix failing checks\")\n .option(\"--verify\", \"Run signing key verification checks\")\n .option(\"--keystore <path>\", \"Path to Android keystore (or set GPC_KEYSTORE_PATH)\")\n .option(\"--store-pass <password>\", \"Keystore password (or set GPC_STORE_PASSWORD)\")\n .option(\"--key-alias <alias>\", \"Key alias in keystore\")\n .action(async (opts, cmd) => {\n const results: CheckResult[] = [];\n const parentOpts = cmd.parent?.opts() ?? {};\n const jsonMode = !!(parentOpts[\"json\"] || parentOpts[\"output\"] === \"json\");\n\n // -----------------------------------------------------------------------\n // 1. Node.js version\n // -----------------------------------------------------------------------\n results.push(checkNodeVersion(process.versions.node));\n\n // -----------------------------------------------------------------------\n // 2. GPC version (non-blocking — catches internally)\n // -----------------------------------------------------------------------\n results.push(await checkGpcVersion());\n\n // -----------------------------------------------------------------------\n // 3. CI environment (info only)\n // -----------------------------------------------------------------------\n const ciResult = checkCiEnvironment();\n if (ciResult) results.push(ciResult);\n\n // -----------------------------------------------------------------------\n // 4. Config file + dependent checks\n // -----------------------------------------------------------------------\n let config;\n try {\n config = await loadConfig();\n results.push({ name: \"config\", status: \"pass\", message: \"Configuration loaded\" });\n\n // 4b. Unknown config keys\n const keysCheck = checkConfigKeys(config as unknown as Record<string, unknown>);\n if (keysCheck) results.push(keysCheck);\n\n // 4c. Default app\n if (config.app) {\n results.push({\n name: \"default-app\",\n status: \"pass\",\n message: `Default app: ${config.app}`,\n });\n const pkgCheck = checkPackageName(config.app);\n if (pkgCheck) results.push(pkgCheck);\n } else {\n results.push({\n name: \"default-app\",\n status: \"info\",\n message: \"No default app configured\",\n suggestion: \"Use --app flag or run: gpc config set app <package>\",\n });\n }\n\n // 4d. Developer ID\n const devIdCheck = checkDeveloperId(config.developerId);\n if (devIdCheck) results.push(devIdCheck);\n } catch {\n results.push({\n name: \"config\",\n status: \"fail\",\n message: \"Configuration could not be loaded\",\n suggestion:\n \"Run gpc config init to create a config file, or check .gpcrc.json for syntax errors\",\n });\n }\n\n // -----------------------------------------------------------------------\n // 5. Config directory permissions\n // -----------------------------------------------------------------------\n const configDir = getConfigDir();\n try {\n if (existsSync(configDir)) {\n accessSync(configDir, constants.R_OK | constants.W_OK);\n results.push({\n name: \"config-dir\",\n status: \"pass\",\n message: `Config directory: ${configDir}`,\n });\n } else {\n results.push({\n name: \"config-dir\",\n status: \"info\",\n message: `Config directory does not exist yet: ${configDir}`,\n });\n }\n } catch {\n results.push({\n name: \"config-dir\",\n status: \"warn\",\n message: `Config directory not writable: ${configDir}`,\n suggestion: `Fix permissions: chmod 755 ${configDir}`,\n });\n }\n\n // -----------------------------------------------------------------------\n // 6. Cache directory permissions\n // -----------------------------------------------------------------------\n const cacheDir = getCacheDir();\n try {\n if (existsSync(cacheDir)) {\n accessSync(cacheDir, constants.R_OK | constants.W_OK);\n results.push({\n name: \"cache-dir\",\n status: \"pass\",\n message: `Cache directory: ${cacheDir}`,\n });\n } else {\n results.push({\n name: \"cache-dir\",\n status: \"info\",\n message: `Cache directory does not exist yet: ${cacheDir}`,\n });\n }\n } catch {\n results.push({\n name: \"cache-dir\",\n status: \"warn\",\n message: `Cache directory not writable: ${cacheDir}`,\n suggestion: `Fix permissions: chmod 700 ${cacheDir}`,\n });\n }\n\n // -----------------------------------------------------------------------\n // 7. Disk space\n // -----------------------------------------------------------------------\n const spaceDir = existsSync(cacheDir) ? cacheDir : configDir;\n if (existsSync(spaceDir)) {\n results.push(await checkDiskSpace(spaceDir));\n }\n\n // -----------------------------------------------------------------------\n // 8. Service account file + permissions\n // -----------------------------------------------------------------------\n let saFilePath: string | undefined;\n if (config?.auth?.serviceAccount) {\n const saValue = config.auth.serviceAccount;\n const looksLikePath = !saValue.trim().startsWith(\"{\");\n if (looksLikePath) {\n saFilePath = resolve(saValue);\n if (existsSync(saFilePath)) {\n try {\n accessSync(saFilePath, constants.R_OK);\n results.push({\n name: \"service-account-file\",\n status: \"pass\",\n message: `Service account file: ${saFilePath}`,\n });\n } catch {\n results.push({\n name: \"service-account-file\",\n status: \"fail\",\n message: `Service account file not readable: ${saFilePath}`,\n suggestion: `Fix permissions: chmod 600 ${saFilePath}`,\n });\n }\n\n // 8b. SA key file permissions (Unix only)\n if (process.platform !== \"win32\") {\n try {\n const mode = statSync(saFilePath).mode;\n const groupRead = (mode & 0o040) !== 0;\n const worldRead = (mode & 0o004) !== 0;\n if (groupRead || worldRead) {\n results.push({\n name: \"service-account-permissions\",\n status: \"warn\",\n message: `Service account file is group/world-readable (mode: ${(mode & 0o777).toString(8)})`,\n suggestion: `Restrict permissions: chmod 600 ${saFilePath}`,\n fixData: { path: saFilePath },\n });\n } else {\n results.push({\n name: \"service-account-permissions\",\n status: \"pass\",\n message: `Service account file permissions OK (mode: ${(mode & 0o777).toString(8)})`,\n });\n }\n } catch {\n // stat failed — skip permission check\n }\n }\n\n // 8c. SA key age\n const ageResult = await checkSaKeyAge(saFilePath);\n if (ageResult) results.push(ageResult);\n } else {\n results.push({\n name: \"service-account-file\",\n status: \"fail\",\n message: `Service account file not found: ${saFilePath}`,\n suggestion: \"Check the path in your config or GPC_SERVICE_ACCOUNT env var\",\n });\n }\n }\n }\n\n // -----------------------------------------------------------------------\n // 9. Conflicting credentials\n // -----------------------------------------------------------------------\n const conflictCheck = checkConflictingCredentials(saFilePath);\n if (conflictCheck) results.push(conflictCheck);\n\n // -----------------------------------------------------------------------\n // 10. Token cache health\n // -----------------------------------------------------------------------\n const cacheResult = await checkTokenCache(cacheDir);\n if (cacheResult) results.push(cacheResult);\n\n // -----------------------------------------------------------------------\n // 11. Profile validation\n // -----------------------------------------------------------------------\n const gpcProfile = process.env[\"GPC_PROFILE\"];\n if (gpcProfile && config) {\n if (config.profiles && gpcProfile in config.profiles) {\n results.push({\n name: \"profile\",\n status: \"pass\",\n message: `Profile \"${gpcProfile}\" found`,\n });\n } else {\n const available = config.profiles ? Object.keys(config.profiles).join(\", \") : \"\";\n results.push({\n name: \"profile\",\n status: \"fail\",\n message: `Profile \"${gpcProfile}\" not found`,\n suggestion: available\n ? `Available profiles: ${available}. Create with: gpc auth login --profile ${gpcProfile}`\n : `No profiles defined. Create one with: gpc auth login --profile ${gpcProfile}`,\n });\n }\n }\n\n // -----------------------------------------------------------------------\n // 12. Proxy configuration\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 const proxyCheck = checkProxy(proxyUrl);\n if (proxyCheck) results.push(proxyCheck);\n\n // -----------------------------------------------------------------------\n // 13. CA certificate\n // -----------------------------------------------------------------------\n const caCert = process.env[\"GPC_CA_CERT\"] || process.env[\"NODE_EXTRA_CA_CERTS\"];\n if (caCert) {\n if (existsSync(caCert)) {\n results.push({\n name: \"ca-cert\",\n status: \"pass\",\n message: `CA certificate: ${caCert}`,\n });\n } else {\n results.push({\n name: \"ca-cert\",\n status: \"warn\",\n message: `CA certificate file not found: ${caCert}`,\n suggestion: \"Check that GPC_CA_CERT points to an existing PEM file\",\n });\n }\n }\n\n // -----------------------------------------------------------------------\n // 14. DNS resolution — with latency\n // -----------------------------------------------------------------------\n const dnsHosts = [API_HOST, REPORTING_HOST];\n const dnsPassedHosts: string[] = [];\n\n for (const host of dnsHosts) {\n const label = host.split(\".\")[0]!;\n try {\n const start = performance.now();\n await lookup(host);\n const ms = Math.round(performance.now() - start);\n results.push({\n name: `dns-${label}`,\n status: \"pass\",\n message: `DNS: ${host} (${ms}ms)`,\n });\n dnsPassedHosts.push(host);\n } catch {\n results.push({\n name: `dns-${label}`,\n status: \"fail\",\n message: `Cannot resolve ${host}`,\n suggestion: \"Check your DNS settings and network connection\",\n });\n }\n }\n\n // -----------------------------------------------------------------------\n // 15. HTTPS connectivity probe — only for hosts that passed DNS\n // -----------------------------------------------------------------------\n for (const host of dnsPassedHosts) {\n const label = host.split(\".\")[0]!;\n const probe = await probeHttps(host);\n if (probe.ok) {\n results.push({\n name: `https-${label}`,\n status: \"pass\",\n message: `HTTPS: ${host} (${probe.latencyMs}ms)`,\n });\n } else {\n results.push({\n name: `https-${label}`,\n status: \"fail\",\n message: `HTTPS connection failed: ${host}`,\n suggestion: probe.error\n ? `Error: ${probe.error}. Check firewall rules and proxy settings.`\n : \"Check firewall rules and proxy settings\",\n });\n }\n }\n\n // -----------------------------------------------------------------------\n // 16. Authentication + API connectivity\n // -----------------------------------------------------------------------\n let accessToken: string | undefined;\n\n try {\n const authConfig = config ?? (await loadConfig());\n const client = await resolveAuth({\n serviceAccountPath: authConfig.auth?.serviceAccount,\n });\n results.push({\n name: \"auth\",\n status: \"pass\",\n message: `Authenticated as ${client.getClientEmail()}`,\n });\n\n accessToken = await client.getAccessToken();\n results.push({\n name: \"api-connectivity\",\n status: \"pass\",\n message: \"API connectivity verified\",\n });\n } catch (error) {\n if (error instanceof AuthError) {\n results.push({\n name: \"auth\",\n status: \"fail\",\n message: `Authentication: ${error.message}`,\n suggestion: error.suggestion,\n });\n } else {\n const detail = error instanceof Error ? error.message : String(error);\n results.push({\n name: \"api-connectivity\",\n status: \"fail\",\n message: `API connectivity failed: ${detail}`,\n suggestion: \"Check your network connection and credentials\",\n });\n }\n }\n\n // -----------------------------------------------------------------------\n // 17. App access (only if auth succeeded and app is configured)\n // -----------------------------------------------------------------------\n if (accessToken && config?.app) {\n results.push(await checkAppAccess(config.app, accessToken));\n }\n\n // -----------------------------------------------------------------------\n // 17b. Enterprise / Play Custom App Publishing API probe (best-effort)\n // -----------------------------------------------------------------------\n if (accessToken) {\n results.push(await checkEnterpriseAccess(accessToken));\n }\n\n // -----------------------------------------------------------------------\n // 18. Developer ID format validation (info only)\n // -----------------------------------------------------------------------\n if (config?.developerId) {\n const devId = String(config.developerId);\n if (/^\\d{10,}$/.test(devId)) {\n results.push({\n name: \"developer-id\",\n status: \"pass\",\n message: `Developer ID: ${devId}`,\n });\n } else {\n results.push({\n name: \"developer-id\",\n status: \"warn\",\n message: `Developer ID \"${devId}\" may be invalid — expected a long numeric string`,\n suggestion:\n \"Find your Developer ID in Play Console → Settings → Developer account → Developer ID.\",\n });\n }\n }\n\n // -----------------------------------------------------------------------\n // 19. Developer verification deadline\n // -----------------------------------------------------------------------\n results.push(checkVerificationDeadline());\n\n // -----------------------------------------------------------------------\n // 20. Stale status cache\n // -----------------------------------------------------------------------\n const staleCacheResult = await checkStaleCache(cacheDir);\n if (staleCacheResult) results.push(staleCacheResult);\n\n // -----------------------------------------------------------------------\n // 21. Shell completion\n // -----------------------------------------------------------------------\n const completionResult = await checkShellCompletion();\n if (completionResult) results.push(completionResult);\n\n // -----------------------------------------------------------------------\n // 22. Quota proximity (reads local audit log, no API needed)\n // -----------------------------------------------------------------------\n const quotaResult = await checkQuotaProximity();\n if (quotaResult) results.push(quotaResult);\n\n // -----------------------------------------------------------------------\n // 23. Plugin health\n // -----------------------------------------------------------------------\n const pluginResults = await checkPluginHealth(config?.plugins);\n results.push(...pluginResults);\n\n // -----------------------------------------------------------------------\n // 24. Signing key verification (only when --verify is passed)\n // -----------------------------------------------------------------------\n if (opts[\"verify\"] && accessToken && config?.app) {\n const ksPath = (opts[\"keystore\"] as string | undefined) ?? process.env[\"GPC_KEYSTORE_PATH\"];\n const ksPass =\n (opts[\"storePass\"] as string | undefined) ?? process.env[\"GPC_STORE_PASSWORD\"];\n const ksAlias = opts[\"keyAlias\"] as string | undefined;\n const signingResults = await checkSigningKey(\n config.app,\n accessToken,\n ksPath,\n ksPass,\n ksAlias,\n );\n results.push(...signingResults);\n } else if (opts[\"verify\"] && !accessToken) {\n results.push({\n name: \"signing-api\",\n status: \"warn\",\n message: \"Cannot verify signing key without authentication\",\n suggestion: \"Run 'gpc auth login' first, then retry with --verify\",\n });\n } else if (opts[\"verify\"] && !config?.app) {\n results.push({\n name: \"signing-api\",\n status: \"warn\",\n message: \"Cannot verify signing key without a configured app\",\n suggestion: \"Set a default app with 'gpc config set app <package>' or use --app\",\n });\n }\n\n // -----------------------------------------------------------------------\n // Output\n // -----------------------------------------------------------------------\n\n // Auto-fix failing checks if --fix was passed\n if (opts[\"fix\"]) {\n for (const r of results) {\n if (r.status === \"fail\" || r.status === \"warn\") {\n try {\n const fixMsg = await applyFix(r);\n if (fixMsg) {\n console.log(` ${green(\"\\u2192\")} Fixed: ${fixMsg}`);\n r.status = \"pass\";\n r.message += \" (fixed)\";\n }\n } catch (err) {\n console.error(\n ` ${red(\"\\u2717\")} Could not fix \"${r.name}\": ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n }\n\n const errors = results.filter((r) => r.status === \"fail\").length;\n const warnings = results.filter((r) => r.status === \"warn\").length;\n const passed = results.filter((r) => r.status === \"pass\").length;\n\n if (jsonMode) {\n // Strip fixData from JSON output\n const cleanResults = results.map(({ fixData: _, ...rest }) => rest);\n console.log(\n JSON.stringify(\n { success: errors === 0, errors, warnings, checks: cleanResults },\n null,\n 2,\n ),\n );\n process.exitCode = errors > 0 ? 1 : 0;\n return;\n }\n\n console.log(\"GPC Doctor\\n\");\n for (const r of results) {\n console.log(` ${icon(r.status)} ${r.message}`);\n if (r.suggestion && r.status !== \"pass\") {\n console.log(` ${r.suggestion}`);\n }\n }\n\n console.log(\n `\\n ${green(PASS)} ${passed} passed ${yellow(WARN)} ${warnings} warning${warnings !== 1 ? \"s\" : \"\"} ${red(FAIL)} ${errors} failed`,\n );\n\n if (errors > 0) {\n console.log(\"\\nSome checks failed. Fix the issues above and run again.\");\n process.exitCode = 1;\n } else if (warnings > 0) {\n console.log(\"\\nAll checks passed with warnings.\");\n } else {\n console.log(`\\n${green(\"\\u2713\")} Ready. Try: gpc status`);\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  detectInstallMethod
4
- } from "./chunk-5G2T4IJO.js";
4
+ } from "./chunk-QLR4EWJG.js";
5
5
  import "./chunk-3SJ6OXCZ.js";
6
6
 
7
7
  // src/commands/feedback.ts
@@ -9,7 +9,7 @@ import { execFile } from "child_process";
9
9
  import { listAuditEvents } from "@gpc-cli/core";
10
10
  function registerFeedbackCommand(program) {
11
11
  program.command("feedback").description("Open a pre-filled GitHub issue with system diagnostics").option("--title <title>", "Issue title").option("--print", "Print the report to stdout instead of opening a browser").action(async (opts) => {
12
- const version = "0.9.69";
12
+ const version = "0.9.71";
13
13
  let lastCommand = "";
14
14
  try {
15
15
  const events = await listAuditEvents({ limit: 3 });
@@ -67,4 +67,4 @@ ${url}`);
67
67
  export {
68
68
  registerFeedbackCommand
69
69
  };
70
- //# sourceMappingURL=feedback-6GOFNCUK.js.map
70
+ //# sourceMappingURL=feedback-IB2UMPWP.js.map