@gpc-cli/cli 0.9.66 → 0.9.67
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 +1 -0
- package/dist/bin.js +2 -2
- package/dist/{chunk-IUG4225Q.js → chunk-E2L6ZQ5H.js} +10 -7
- package/dist/chunk-E2L6ZQ5H.js.map +1 -0
- package/dist/{config-DDZMNYOB.js → config-KDRIYC2G.js} +2 -2
- package/dist/{doctor-QRHXY3FC.js → doctor-IZS4NBBZ.js} +75 -3
- package/dist/doctor-IZS4NBBZ.js.map +1 -0
- package/dist/{feedback-C2BA7CK6.js → feedback-RH6YMGHM.js} +2 -2
- package/dist/generated/docs-bundle.json +1 -1
- package/dist/index.js +1 -1
- package/dist/{update-GEH352BE.js → update-3CN6PKOC.js} +2 -2
- package/dist/{version-2RUEWMPK.js → version-CT4G2PSE.js} +2 -2
- package/dist/watch-YRXMHU2F.js +217 -0
- package/dist/watch-YRXMHU2F.js.map +1 -0
- package/package.json +4 -4
- package/dist/chunk-IUG4225Q.js.map +0 -1
- package/dist/doctor-QRHXY3FC.js.map +0 -1
- /package/dist/{config-DDZMNYOB.js.map → config-KDRIYC2G.js.map} +0 -0
- /package/dist/{feedback-C2BA7CK6.js.map → feedback-RH6YMGHM.js.map} +0 -0
- /package/dist/{update-GEH352BE.js.map → update-3CN6PKOC.js.map} +0 -0
- /package/dist/{version-2RUEWMPK.js.map → version-CT4G2PSE.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ function registerUpdateCommand(program) {
|
|
|
17
17
|
program.command("update").description("Update gpc to the latest version").option("--check", "Check for updates without installing (exits 0 always)").option("--force", "Update even if already on the latest version").action(async (opts, cmd) => {
|
|
18
18
|
const parentOpts = cmd.parent?.opts() ?? {};
|
|
19
19
|
const jsonMode = !!(parentOpts["json"] || parentOpts["output"] === "json");
|
|
20
|
-
const currentVersion = "0.9.
|
|
20
|
+
const currentVersion = "0.9.67";
|
|
21
21
|
if (currentVersion === "0.0.0") {
|
|
22
22
|
if (jsonMode) {
|
|
23
23
|
console.log(
|
|
@@ -172,4 +172,4 @@ Run: gpc update`);
|
|
|
172
172
|
export {
|
|
173
173
|
registerUpdateCommand
|
|
174
174
|
};
|
|
175
|
-
//# sourceMappingURL=update-
|
|
175
|
+
//# sourceMappingURL=update-3CN6PKOC.js.map
|
|
@@ -7,7 +7,7 @@ import "./chunk-3SJ6OXCZ.js";
|
|
|
7
7
|
// src/commands/version.ts
|
|
8
8
|
function registerVersionCommand(program) {
|
|
9
9
|
program.command("version").description("Show version information").action(() => {
|
|
10
|
-
const version = "0.9.
|
|
10
|
+
const version = "0.9.67";
|
|
11
11
|
if (program.opts()["output"] === "json") {
|
|
12
12
|
console.log(
|
|
13
13
|
JSON.stringify({
|
|
@@ -25,4 +25,4 @@ function registerVersionCommand(program) {
|
|
|
25
25
|
export {
|
|
26
26
|
registerVersionCommand
|
|
27
27
|
};
|
|
28
|
-
//# sourceMappingURL=version-
|
|
28
|
+
//# sourceMappingURL=version-CT4G2PSE.js.map
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
dim,
|
|
4
|
+
green,
|
|
5
|
+
red,
|
|
6
|
+
yellow
|
|
7
|
+
} from "./chunk-FAN4ZITI.js";
|
|
8
|
+
import {
|
|
9
|
+
getOutputFormat
|
|
10
|
+
} from "./chunk-ELXAK7GI.js";
|
|
11
|
+
|
|
12
|
+
// src/commands/watch.ts
|
|
13
|
+
import { loadConfig } from "@gpc-cli/config";
|
|
14
|
+
import { resolveAuth } from "@gpc-cli/auth";
|
|
15
|
+
import { createApiClient, createReportingClient } from "@gpc-cli/api";
|
|
16
|
+
import { runWatch, VALID_WATCH_METRICS, DEFAULT_WATCH_THRESHOLDS } from "@gpc-cli/core";
|
|
17
|
+
function parseMetrics(raw) {
|
|
18
|
+
const metrics = raw.split(",").map((s) => s.trim());
|
|
19
|
+
for (const m of metrics) {
|
|
20
|
+
if (!VALID_WATCH_METRICS.has(m)) {
|
|
21
|
+
throw Object.assign(
|
|
22
|
+
new Error(`Unknown metric "${m}". Valid: ${[...VALID_WATCH_METRICS].join(", ")}`),
|
|
23
|
+
{ code: "WATCH_USAGE_ERROR", exitCode: 2 }
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return metrics;
|
|
28
|
+
}
|
|
29
|
+
function parseActions(raw) {
|
|
30
|
+
const valid = /* @__PURE__ */ new Set(["notify", "halt", "webhook"]);
|
|
31
|
+
const actions = raw.split(",").map((s) => s.trim());
|
|
32
|
+
for (const a of actions) {
|
|
33
|
+
if (!valid.has(a)) {
|
|
34
|
+
throw Object.assign(new Error(`Unknown action "${a}". Valid: notify, halt, webhook`), {
|
|
35
|
+
code: "WATCH_USAGE_ERROR",
|
|
36
|
+
exitCode: 2
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return actions;
|
|
41
|
+
}
|
|
42
|
+
function pct(value) {
|
|
43
|
+
if (value === void 0 || value === null) return "\u2014";
|
|
44
|
+
return `${(value * 100).toFixed(1)}%`;
|
|
45
|
+
}
|
|
46
|
+
function rolloutPct(fraction) {
|
|
47
|
+
if (fraction === null) return "100%";
|
|
48
|
+
return `${(fraction * 100).toFixed(0)}%`;
|
|
49
|
+
}
|
|
50
|
+
function formatHumanEvent(event) {
|
|
51
|
+
const ts = new Date(event.timestamp).toLocaleTimeString();
|
|
52
|
+
const lines = [];
|
|
53
|
+
lines.push(`[${ts}] Round ${event.round}`);
|
|
54
|
+
if (event.rollout) {
|
|
55
|
+
const r = event.rollout;
|
|
56
|
+
lines.push(` Rollout: v${r.versionCode} at ${rolloutPct(r.userFraction)} (${r.status})`);
|
|
57
|
+
} else {
|
|
58
|
+
lines.push(` Rollout: no active release`);
|
|
59
|
+
}
|
|
60
|
+
for (const [metric, reading] of Object.entries(event.vitals)) {
|
|
61
|
+
if (!reading) continue;
|
|
62
|
+
const val = pct(reading.value);
|
|
63
|
+
const thresh = reading.threshold !== void 0 ? pct(reading.threshold) : "\u2014";
|
|
64
|
+
const label = reading.breached ? red("BREACH") : green("OK");
|
|
65
|
+
lines.push(` ${metric}: ${val} (threshold: ${thresh}) ${label}`);
|
|
66
|
+
}
|
|
67
|
+
if (event.halted) {
|
|
68
|
+
lines.push(red(` ! Rollout halted due to threshold breach.`));
|
|
69
|
+
} else if (event.breaches.length > 0) {
|
|
70
|
+
lines.push(yellow(` ! ${event.breaches.join(", ")} breached threshold.`));
|
|
71
|
+
}
|
|
72
|
+
return lines.join("\n");
|
|
73
|
+
}
|
|
74
|
+
function formatHumanSummary(summary) {
|
|
75
|
+
const duration = formatDuration(summary.durationMs);
|
|
76
|
+
const parts = [
|
|
77
|
+
`
|
|
78
|
+
Summary: ${summary.rounds} round${summary.rounds !== 1 ? "s" : ""} over ${duration}.`
|
|
79
|
+
];
|
|
80
|
+
if (summary.breachCount > 0) {
|
|
81
|
+
parts.push(`${summary.breachCount} breach${summary.breachCount !== 1 ? "es" : ""}.`);
|
|
82
|
+
} else {
|
|
83
|
+
parts.push("No breaches.");
|
|
84
|
+
}
|
|
85
|
+
if (summary.halted) {
|
|
86
|
+
parts.push("Rollout halted.");
|
|
87
|
+
} else if (summary.finalRollout === null) {
|
|
88
|
+
parts.push("Rollout at 100%.");
|
|
89
|
+
} else {
|
|
90
|
+
parts.push(`Rollout at ${rolloutPct(summary.finalRollout)}.`);
|
|
91
|
+
}
|
|
92
|
+
return parts.join(" ");
|
|
93
|
+
}
|
|
94
|
+
function formatDuration(ms) {
|
|
95
|
+
const totalSec = Math.round(ms / 1e3);
|
|
96
|
+
if (totalSec < 60) return `${totalSec}s`;
|
|
97
|
+
const m = Math.floor(totalSec / 60);
|
|
98
|
+
const s = totalSec % 60;
|
|
99
|
+
if (m < 60) return s > 0 ? `${m}m ${s}s` : `${m}m`;
|
|
100
|
+
const h = Math.floor(m / 60);
|
|
101
|
+
const rm = m % 60;
|
|
102
|
+
return rm > 0 ? `${h}h ${rm}m` : `${h}h`;
|
|
103
|
+
}
|
|
104
|
+
function registerWatchCommand(program) {
|
|
105
|
+
program.command("watch").description("Monitor a rollout with real-time vitals and threshold alerts").option("--track <name>", "Track to watch", "production").option("--metrics <csv>", "Comma-separated metrics to monitor", "crashes,anr").option("--interval <seconds>", "Poll interval in seconds (min 60)", "900").option("--rounds <n>", "Stop after N rounds (default: run until Ctrl+C)").option("--crash-threshold <pct>", "Crash rate threshold (e.g. 0.02 for 2%)").option("--anr-threshold <pct>", "ANR rate threshold (e.g. 0.01 for 1%)").option("--lmk-threshold <pct>", "LMK rate threshold").option("--slow-start-threshold <pct>", "Slow start rate threshold").option("--slow-render-threshold <pct>", "Slow rendering rate threshold").option("--error-count-threshold <n>", "Error report count threshold").option(
|
|
106
|
+
"--on-breach <actions>",
|
|
107
|
+
"Actions on breach: notify, halt, webhook (comma-separated)",
|
|
108
|
+
"notify"
|
|
109
|
+
).option("--webhook-url <url>", "Webhook URL for breach notifications").action(async (opts, cmd) => {
|
|
110
|
+
const config = await loadConfig();
|
|
111
|
+
const format = getOutputFormat(cmd.parent ?? program, config);
|
|
112
|
+
const jsonMode = format === "json";
|
|
113
|
+
const rootOpts = (cmd.parent ?? program).opts();
|
|
114
|
+
const packageName = rootOpts["app"] || config.app;
|
|
115
|
+
if (!packageName) {
|
|
116
|
+
throw Object.assign(new Error("No package name"), {
|
|
117
|
+
code: "WATCH_USAGE_ERROR",
|
|
118
|
+
exitCode: 2,
|
|
119
|
+
suggestion: "Use --app <package> or run: gpc config set app <package>"
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const metrics = parseMetrics(opts["metrics"]);
|
|
123
|
+
const actions = parseActions(opts["onBreach"]);
|
|
124
|
+
const intervalSeconds = parseInt(opts["interval"], 10);
|
|
125
|
+
if (isNaN(intervalSeconds) || intervalSeconds < 60) {
|
|
126
|
+
throw Object.assign(new Error("--interval must be at least 60 seconds"), {
|
|
127
|
+
code: "WATCH_USAGE_ERROR",
|
|
128
|
+
exitCode: 2
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const rounds = opts["rounds"] ? parseInt(opts["rounds"], 10) : null;
|
|
132
|
+
if (rounds !== null && (isNaN(rounds) || rounds < 1)) {
|
|
133
|
+
throw Object.assign(new Error("--rounds must be a positive integer"), {
|
|
134
|
+
code: "WATCH_USAGE_ERROR",
|
|
135
|
+
exitCode: 2
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const configThresholds = config["vitals"];
|
|
139
|
+
const thresholds = {
|
|
140
|
+
...DEFAULT_WATCH_THRESHOLDS
|
|
141
|
+
};
|
|
142
|
+
if (configThresholds?.thresholds) {
|
|
143
|
+
const ct = configThresholds.thresholds;
|
|
144
|
+
if (ct["crashRate"] !== void 0) thresholds.crashes = ct["crashRate"];
|
|
145
|
+
if (ct["anrRate"] !== void 0) thresholds.anr = ct["anrRate"];
|
|
146
|
+
if (ct["lmkRate"] !== void 0) thresholds.lmk = ct["lmkRate"];
|
|
147
|
+
if (ct["slowStartRate"] !== void 0) thresholds.slowStarts = ct["slowStartRate"];
|
|
148
|
+
if (ct["slowRenderingRate"] !== void 0) thresholds.slowRender = ct["slowRenderingRate"];
|
|
149
|
+
}
|
|
150
|
+
if (opts["crashThreshold"]) thresholds.crashes = parseFloat(opts["crashThreshold"]);
|
|
151
|
+
if (opts["anrThreshold"]) thresholds.anr = parseFloat(opts["anrThreshold"]);
|
|
152
|
+
if (opts["lmkThreshold"]) thresholds.lmk = parseFloat(opts["lmkThreshold"]);
|
|
153
|
+
if (opts["slowStartThreshold"])
|
|
154
|
+
thresholds.slowStarts = parseFloat(opts["slowStartThreshold"]);
|
|
155
|
+
if (opts["slowRenderThreshold"])
|
|
156
|
+
thresholds.slowRender = parseFloat(opts["slowRenderThreshold"]);
|
|
157
|
+
if (opts["errorCountThreshold"])
|
|
158
|
+
thresholds.errorCount = parseFloat(opts["errorCountThreshold"]);
|
|
159
|
+
const webhookUrl = opts["webhookUrl"] ?? config["webhooks"]?.["watch"];
|
|
160
|
+
if (actions.includes("webhook") && !webhookUrl) {
|
|
161
|
+
throw Object.assign(new Error("--webhook-url is required when using --on-breach webhook"), {
|
|
162
|
+
code: "WATCH_USAGE_ERROR",
|
|
163
|
+
exitCode: 2,
|
|
164
|
+
suggestion: "Provide --webhook-url <url> or set webhooks.watch in .gpcrc.json"
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const auth = await resolveAuth({
|
|
168
|
+
serviceAccountPath: config.auth?.serviceAccount
|
|
169
|
+
});
|
|
170
|
+
const client = createApiClient({ auth });
|
|
171
|
+
const reporting = createReportingClient({ auth });
|
|
172
|
+
if (!jsonMode) {
|
|
173
|
+
console.log(`gpc watch ${dim("\u2014")} ${packageName} (${opts["track"]} track)`);
|
|
174
|
+
console.log(
|
|
175
|
+
dim("Vitals data is typically 24-48h behind. Rollout status is near real-time.\n")
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
const summary = await runWatch(
|
|
179
|
+
client,
|
|
180
|
+
reporting,
|
|
181
|
+
{
|
|
182
|
+
packageName,
|
|
183
|
+
track: opts["track"],
|
|
184
|
+
intervalSeconds,
|
|
185
|
+
metrics,
|
|
186
|
+
thresholds,
|
|
187
|
+
maxRounds: rounds,
|
|
188
|
+
actions,
|
|
189
|
+
webhookUrl
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
onEvent(event) {
|
|
193
|
+
if (jsonMode) {
|
|
194
|
+
console.log(JSON.stringify(event));
|
|
195
|
+
} else {
|
|
196
|
+
console.log(formatHumanEvent(event));
|
|
197
|
+
console.log("");
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
async onBreach(_event) {
|
|
201
|
+
},
|
|
202
|
+
onComplete(s) {
|
|
203
|
+
if (jsonMode) {
|
|
204
|
+
console.log(JSON.stringify({ type: "summary", ...s }));
|
|
205
|
+
} else {
|
|
206
|
+
console.log(formatHumanSummary(s));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
process.exitCode = summary.breachCount > 0 ? 6 : 0;
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
export {
|
|
215
|
+
registerWatchCommand
|
|
216
|
+
};
|
|
217
|
+
//# sourceMappingURL=watch-YRXMHU2F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/watch.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { resolveAuth } from \"@gpc-cli/auth\";\nimport { createApiClient, createReportingClient } from \"@gpc-cli/api\";\nimport { runWatch, VALID_WATCH_METRICS, DEFAULT_WATCH_THRESHOLDS } from \"@gpc-cli/core\";\nimport type { WatchMetric, WatchAction, WatchEvent, WatchSummary } from \"@gpc-cli/core\";\nimport { getOutputFormat } from \"../format.js\";\nimport { green, red, yellow, dim } from \"../colors.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction parseMetrics(raw: string): WatchMetric[] {\n const metrics = raw.split(\",\").map((s) => s.trim()) as WatchMetric[];\n for (const m of metrics) {\n if (!VALID_WATCH_METRICS.has(m)) {\n throw Object.assign(\n new Error(`Unknown metric \"${m}\". Valid: ${[...VALID_WATCH_METRICS].join(\", \")}`),\n { code: \"WATCH_USAGE_ERROR\", exitCode: 2 },\n );\n }\n }\n return metrics;\n}\n\nfunction parseActions(raw: string): WatchAction[] {\n const valid = new Set<WatchAction>([\"notify\", \"halt\", \"webhook\"]);\n const actions = raw.split(\",\").map((s) => s.trim()) as WatchAction[];\n for (const a of actions) {\n if (!valid.has(a)) {\n throw Object.assign(new Error(`Unknown action \"${a}\". Valid: notify, halt, webhook`), {\n code: \"WATCH_USAGE_ERROR\",\n exitCode: 2,\n });\n }\n }\n return actions;\n}\n\nfunction pct(value: number | undefined | null): string {\n if (value === undefined || value === null) return \"—\";\n return `${(value * 100).toFixed(1)}%`;\n}\n\nfunction rolloutPct(fraction: number | null): string {\n if (fraction === null) return \"100%\";\n return `${(fraction * 100).toFixed(0)}%`;\n}\n\nfunction formatHumanEvent(event: WatchEvent): string {\n const ts = new Date(event.timestamp).toLocaleTimeString();\n const lines: string[] = [];\n\n lines.push(`[${ts}] Round ${event.round}`);\n\n if (event.rollout) {\n const r = event.rollout;\n lines.push(` Rollout: v${r.versionCode} at ${rolloutPct(r.userFraction)} (${r.status})`);\n } else {\n lines.push(` Rollout: no active release`);\n }\n\n for (const [metric, reading] of Object.entries(event.vitals)) {\n if (!reading) continue;\n const val = pct(reading.value);\n const thresh = reading.threshold !== undefined ? pct(reading.threshold) : \"—\";\n const label = reading.breached ? red(\"BREACH\") : green(\"OK\");\n lines.push(` ${metric}: ${val} (threshold: ${thresh}) ${label}`);\n }\n\n if (event.halted) {\n lines.push(red(` ! Rollout halted due to threshold breach.`));\n } else if (event.breaches.length > 0) {\n lines.push(yellow(` ! ${event.breaches.join(\", \")} breached threshold.`));\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction formatHumanSummary(summary: WatchSummary): string {\n const duration = formatDuration(summary.durationMs);\n const parts = [\n `\\nSummary: ${summary.rounds} round${summary.rounds !== 1 ? \"s\" : \"\"} over ${duration}.`,\n ];\n if (summary.breachCount > 0) {\n parts.push(`${summary.breachCount} breach${summary.breachCount !== 1 ? \"es\" : \"\"}.`);\n } else {\n parts.push(\"No breaches.\");\n }\n if (summary.halted) {\n parts.push(\"Rollout halted.\");\n } else if (summary.finalRollout === null) {\n parts.push(\"Rollout at 100%.\");\n } else {\n parts.push(`Rollout at ${rolloutPct(summary.finalRollout)}.`);\n }\n return parts.join(\" \");\n}\n\nfunction formatDuration(ms: number): string {\n const totalSec = Math.round(ms / 1000);\n if (totalSec < 60) return `${totalSec}s`;\n const m = Math.floor(totalSec / 60);\n const s = totalSec % 60;\n if (m < 60) return s > 0 ? `${m}m ${s}s` : `${m}m`;\n const h = Math.floor(m / 60);\n const rm = m % 60;\n return rm > 0 ? `${h}h ${rm}m` : `${h}h`;\n}\n\n// ---------------------------------------------------------------------------\n// Command registration\n// ---------------------------------------------------------------------------\n\nexport function registerWatchCommand(program: Command): void {\n program\n .command(\"watch\")\n .description(\"Monitor a rollout with real-time vitals and threshold alerts\")\n .option(\"--track <name>\", \"Track to watch\", \"production\")\n .option(\"--metrics <csv>\", \"Comma-separated metrics to monitor\", \"crashes,anr\")\n .option(\"--interval <seconds>\", \"Poll interval in seconds (min 60)\", \"900\")\n .option(\"--rounds <n>\", \"Stop after N rounds (default: run until Ctrl+C)\")\n .option(\"--crash-threshold <pct>\", \"Crash rate threshold (e.g. 0.02 for 2%)\")\n .option(\"--anr-threshold <pct>\", \"ANR rate threshold (e.g. 0.01 for 1%)\")\n .option(\"--lmk-threshold <pct>\", \"LMK rate threshold\")\n .option(\"--slow-start-threshold <pct>\", \"Slow start rate threshold\")\n .option(\"--slow-render-threshold <pct>\", \"Slow rendering rate threshold\")\n .option(\"--error-count-threshold <n>\", \"Error report count threshold\")\n .option(\n \"--on-breach <actions>\",\n \"Actions on breach: notify, halt, webhook (comma-separated)\",\n \"notify\",\n )\n .option(\"--webhook-url <url>\", \"Webhook URL for breach notifications\")\n .action(async (opts, cmd) => {\n const config = await loadConfig();\n const format = getOutputFormat(cmd.parent ?? program, config);\n const jsonMode = format === \"json\";\n\n const rootOpts = (cmd.parent ?? program).opts();\n const packageName = (rootOpts[\"app\"] || config.app) as string | undefined;\n\n if (!packageName) {\n throw Object.assign(new Error(\"No package name\"), {\n code: \"WATCH_USAGE_ERROR\",\n exitCode: 2,\n suggestion: \"Use --app <package> or run: gpc config set app <package>\",\n });\n }\n\n const metrics = parseMetrics(opts[\"metrics\"] as string);\n const actions = parseActions(opts[\"onBreach\"] as string);\n const intervalSeconds = parseInt(opts[\"interval\"] as string, 10);\n\n if (isNaN(intervalSeconds) || intervalSeconds < 60) {\n throw Object.assign(new Error(\"--interval must be at least 60 seconds\"), {\n code: \"WATCH_USAGE_ERROR\",\n exitCode: 2,\n });\n }\n\n const rounds = opts[\"rounds\"] ? parseInt(opts[\"rounds\"] as string, 10) : null;\n if (rounds !== null && (isNaN(rounds) || rounds < 1)) {\n throw Object.assign(new Error(\"--rounds must be a positive integer\"), {\n code: \"WATCH_USAGE_ERROR\",\n exitCode: 2,\n });\n }\n\n // Resolve thresholds: CLI flags > config > defaults\n const configThresholds = (config as Record<string, unknown>)[\"vitals\"] as\n | { thresholds?: Record<string, number> }\n | undefined;\n\n const thresholds: Partial<Record<WatchMetric, number>> = {\n ...DEFAULT_WATCH_THRESHOLDS,\n };\n if (configThresholds?.thresholds) {\n const ct = configThresholds.thresholds;\n if (ct[\"crashRate\"] !== undefined) thresholds.crashes = ct[\"crashRate\"];\n if (ct[\"anrRate\"] !== undefined) thresholds.anr = ct[\"anrRate\"];\n if (ct[\"lmkRate\"] !== undefined) thresholds.lmk = ct[\"lmkRate\"];\n if (ct[\"slowStartRate\"] !== undefined) thresholds.slowStarts = ct[\"slowStartRate\"];\n if (ct[\"slowRenderingRate\"] !== undefined) thresholds.slowRender = ct[\"slowRenderingRate\"];\n }\n if (opts[\"crashThreshold\"]) thresholds.crashes = parseFloat(opts[\"crashThreshold\"]);\n if (opts[\"anrThreshold\"]) thresholds.anr = parseFloat(opts[\"anrThreshold\"]);\n if (opts[\"lmkThreshold\"]) thresholds.lmk = parseFloat(opts[\"lmkThreshold\"]);\n if (opts[\"slowStartThreshold\"])\n thresholds.slowStarts = parseFloat(opts[\"slowStartThreshold\"]);\n if (opts[\"slowRenderThreshold\"])\n thresholds.slowRender = parseFloat(opts[\"slowRenderThreshold\"]);\n if (opts[\"errorCountThreshold\"])\n thresholds.errorCount = parseFloat(opts[\"errorCountThreshold\"]);\n\n const webhookUrl =\n (opts[\"webhookUrl\"] as string | undefined) ??\n ((config as Record<string, unknown>)[\"webhooks\"] as Record<string, string> | undefined)?.[\n \"watch\"\n ];\n\n if (actions.includes(\"webhook\") && !webhookUrl) {\n throw Object.assign(new Error(\"--webhook-url is required when using --on-breach webhook\"), {\n code: \"WATCH_USAGE_ERROR\",\n exitCode: 2,\n suggestion: \"Provide --webhook-url <url> or set webhooks.watch in .gpcrc.json\",\n });\n }\n\n const auth = await resolveAuth({\n serviceAccountPath: config.auth?.serviceAccount,\n });\n const client = createApiClient({ auth });\n const reporting = createReportingClient({ auth });\n\n if (!jsonMode) {\n console.log(`gpc watch ${dim(\"—\")} ${packageName} (${opts[\"track\"]} track)`);\n console.log(\n dim(\"Vitals data is typically 24-48h behind. Rollout status is near real-time.\\n\"),\n );\n }\n\n const summary = await runWatch(\n client,\n reporting,\n {\n packageName,\n track: opts[\"track\"] as string,\n intervalSeconds,\n metrics,\n thresholds,\n maxRounds: rounds,\n actions,\n webhookUrl,\n },\n {\n onEvent(event: WatchEvent) {\n if (jsonMode) {\n console.log(JSON.stringify(event));\n } else {\n console.log(formatHumanEvent(event));\n console.log(\"\");\n }\n },\n async onBreach(_event: WatchEvent) {\n // breach actions handled inside runWatch via handleBreach\n },\n onComplete(s: WatchSummary) {\n if (jsonMode) {\n console.log(JSON.stringify({ type: \"summary\", ...s }));\n } else {\n console.log(formatHumanSummary(s));\n }\n },\n },\n );\n\n process.exitCode = summary.breachCount > 0 ? 6 : 0;\n });\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gpc-cli/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.67",
|
|
4
4
|
"description": "GPC — Google Play Console CLI. 217 API endpoints including Managed Google Play. Upload AABs, manage releases, monitor vitals, publish private enterprise apps. Fastlane alternative for Android.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"commander": "^14.0.3",
|
|
22
|
-
"@gpc-cli/auth": "0.9.14",
|
|
23
|
-
"@gpc-cli/config": "0.9.14",
|
|
24
|
-
"@gpc-cli/core": "0.9.56",
|
|
25
22
|
"@gpc-cli/api": "1.0.36",
|
|
23
|
+
"@gpc-cli/config": "0.9.14",
|
|
24
|
+
"@gpc-cli/auth": "0.9.14",
|
|
25
|
+
"@gpc-cli/core": "0.9.57",
|
|
26
26
|
"@gpc-cli/plugin-sdk": "0.9.10"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugins.ts","../src/program.ts","../src/error-handler.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(\"GPC — Google Play Console CLI\")\n .version(process.env[\"__GPC_VERSION\"] || \"0.0.0\", \"-V, --version\")\n .option(\"-o, --output <format>\", \"Output format: table, json, yaml, markdown, junit\")\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 .option(\"--notify [target]\", \"Send webhook notification on completion (slack, discord, custom)\")\n .option(\"--ci\", \"Force CI mode (JSON output, no prompts, strict exit codes)\")\n .option(\"-j, --json\", \"Shorthand for --output json\")\n .option(\"--apps <csv>\", \"Comma-separated package names for multi-app operations\")\n .showSuggestionAfterError(false);\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 update: async () => {\n (await import(\"./commands/update.js\")).registerUpdateCommand(program);\n },\n docs: async () => {\n (await import(\"./commands/docs.js\")).registerDocsCommand(program);\n },\n changelog: async () => {\n (await import(\"./commands/changelog.js\")).registerChangelogCommand(program);\n },\n completion: async () => {\n (await import(\"./commands/completion.js\")).registerCompletionCommand(program, async () => {\n // Force-load every non-completion command so the introspection walker\n // sees the full tree (including plugins registered later in createProgram).\n await Promise.all(\n Object.entries(commandLoaders)\n .filter(([name]) => name !== \"completion\")\n .map(([, loader]) => loader()),\n );\n });\n },\n __complete: async () => {\n (await import(\"./commands/__complete.js\")).registerCompleteCommand(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 recovery: async () => {\n (await import(\"./commands/recovery.js\")).registerRecoveryCommands(program);\n },\n \"data-safety\": async () => {\n (await import(\"./commands/data-safety.js\")).registerDataSafetyCommands(program);\n },\n \"external-transactions\": async () => {\n (await import(\"./commands/external-transactions.js\")).registerExternalTransactionsCommands(\n program,\n );\n },\n \"device-tiers\": async () => {\n (await import(\"./commands/device-tiers.js\")).registerDeviceTiersCommands(program);\n },\n \"one-time-products\": async () => {\n (await import(\"./commands/one-time-products.js\")).registerOneTimeProductsCommands(program);\n },\n \"internal-sharing\": async () => {\n (await import(\"./commands/internal-sharing.js\")).registerInternalSharingCommands(program);\n },\n \"generated-apks\": async () => {\n (await import(\"./commands/generated-apks.js\")).registerGeneratedApksCommands(program);\n },\n \"system-apks\": async () => {\n (await import(\"./commands/system-apks.js\")).registerSystemApksCommands(program);\n },\n \"purchase-options\": async () => {\n (await import(\"./commands/purchase-options.js\")).registerPurchaseOptionsCommands(program);\n },\n bundle: async () => {\n (await import(\"./commands/bundle.js\")).registerBundleCommands(program);\n },\n audit: async () => {\n (await import(\"./commands/audit.js\")).registerAuditCommands(program);\n },\n migrate: async () => {\n (await import(\"./commands/migrate.js\")).registerMigrateCommands(program);\n },\n anomalies: async () => {\n (await import(\"./commands/anomalies.js\")).registerAnomaliesCommands(program);\n },\n \"install-skills\": async () => {\n (await import(\"./commands/install-skills.js\")).registerInstallSkillsCommand(program);\n },\n verify: async () => {\n (await import(\"./commands/verify.js\")).registerVerifyCommand(program);\n },\n version: async () => {\n (await import(\"./commands/version.js\")).registerVersionCommand(program);\n },\n cache: async () => {\n (await import(\"./commands/cache.js\")).registerCacheCommand(program);\n },\n feedback: async () => {\n (await import(\"./commands/feedback.js\")).registerFeedbackCommand(program);\n },\n quickstart: async () => {\n (await import(\"./commands/quickstart.js\")).registerQuickstartCommand(program);\n },\n grants: async () => {\n (await import(\"./commands/grants.js\")).registerGrantsCommands(program);\n },\n train: async () => {\n (await import(\"./commands/train.js\")).registerTrainCommands(program);\n },\n quota: async () => {\n (await import(\"./commands/quota.js\")).registerQuotaCommand(program);\n },\n games: async () => {\n (await import(\"./commands/games.js\")).registerGamesCommands(program);\n },\n enterprise: async () => {\n (await import(\"./commands/enterprise.js\")).registerEnterpriseCommands(program);\n },\n diff: async () => {\n (await import(\"./commands/diff.js\")).registerDiffCommand(program);\n },\n init: async () => {\n (await import(\"./commands/init.js\")).registerInitCommand(program);\n },\n preflight: async () => {\n (await import(\"./commands/preflight.js\")).registerPreflightCommand(program);\n },\n plugins: async () => {\n registerPluginsCommand(program, pluginManager);\n },\n rtdn: async () => {\n (await import(\"./commands/rtdn.js\")).registerRtdnCommands(program);\n },\n };\n\n // \"Did you mean?\" suggestions for unknown commands\n function levenshtein(a: string, b: string): number {\n const m = a.length,\n n = b.length;\n const dp: number[][] = Array.from({ length: m + 1 }, (_, i) =>\n Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),\n );\n const cell = (r: number, c: number): number => dp[r]?.[c] ?? 0;\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n (dp[i] as number[])[j] =\n a[i - 1] === b[j - 1]\n ? cell(i - 1, j - 1)\n : 1 + Math.min(cell(i - 1, j), cell(i, j - 1), cell(i - 1, j - 1));\n }\n }\n return cell(m, n);\n }\n\n program.on(\"command:*\", (operands: string[]) => {\n const cmd = operands[0] ?? \"\";\n const names = Object.keys(commandLoaders);\n const best = names\n .map((name) => ({ name, d: levenshtein(cmd, name) }))\n .sort((a, b) => a.d - b.d)[0];\n console.error(`Error: Unknown command \"${cmd}\".`);\n if (best && best.d <= 3) console.error(`Did you mean: gpc ${best.name}?`);\n console.error(`Run \"gpc --help\" to see all commands.`);\n process.exit(2);\n });\n\n // Resolve command aliases for lazy loading\n const commandAliases: Record<string, string> = {\n \"ext-txn\": \"external-transactions\",\n otp: \"one-time-products\",\n };\n\n const rawTarget = process.argv[2];\n const target = rawTarget ? (commandAliases[rawTarget] ?? rawTarget) : undefined;\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 const REGISTRY_URL =\n \"https://raw.githubusercontent.com/yasserstudio/gpc-plugins/main/registry.json\";\n\n interface RegistryPlugin {\n name: string;\n description: string;\n version: string;\n author?: string;\n tags?: string[];\n }\n\n cmd\n .command(\"search [query]\")\n .description(\"Search the GPC plugin registry\")\n .action(async (query?: string) => {\n try {\n const res = await fetch(REGISTRY_URL);\n if (!res.ok) throw new Error(`Registry fetch failed: ${res.status}`);\n const plugins = (await res.json()) as RegistryPlugin[];\n const filtered = query\n ? plugins.filter(\n (p) =>\n p.name.includes(query) ||\n p.description?.toLowerCase().includes(query.toLowerCase()),\n )\n : plugins;\n\n if (filtered.length === 0) {\n console.log(`No plugins found${query ? ` matching \"${query}\"` : \"\"}.`);\n return;\n }\n\n for (const p of filtered) {\n console.log(` ${p.name}@${p.version}`);\n if (p.description) console.log(` ${p.description}`);\n }\n console.log(`\\nInstall: gpc plugins install <name>`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n cmd\n .command(\"install <name>\")\n .description(\"Install a plugin from npm\")\n .action(async (name: string) => {\n const { spawnSync } = await import(\"node:child_process\");\n console.log(`Installing plugin \"${name}\"...`);\n try {\n // Use spawnSync with an array to avoid shell injection — no shell is invoked\n const result = spawnSync(\"npm\", [\"install\", \"-g\", name], { stdio: \"inherit\" });\n if (result.status !== 0) {\n throw new Error(`npm install exited with code ${result.status ?? \"unknown\"}`);\n }\n const { approvePlugin } = await import(\"@gpc-cli/config\");\n await approvePlugin(name);\n console.log(`\\nPlugin \"${name}\" installed and approved. It will be loaded on next run.`);\n console.log(`Configure it in .gpcrc.json: { \"plugins\": [\"${name}\"] }`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\n }\n });\n\n cmd\n .command(\"uninstall <name>\")\n .description(\"Uninstall a plugin and revoke its approval\")\n .action(async (name: string) => {\n const { spawnSync } = await import(\"node:child_process\");\n console.log(`Uninstalling plugin \"${name}\"...`);\n try {\n // Use spawnSync with an array to avoid shell injection — no shell is invoked\n const result = spawnSync(\"npm\", [\"uninstall\", \"-g\", name], { stdio: \"inherit\" });\n if (result.status !== 0) {\n throw new Error(`npm uninstall exited with code ${result.status ?? \"unknown\"}`);\n }\n const { revokePluginApproval } = await import(\"@gpc-cli/config\");\n await revokePluginApproval(name);\n console.log(`\\nPlugin \"${name}\" uninstalled and approval revoked.`);\n } catch (error) {\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(4);\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","/**\n * Shared error formatting for CLI output.\n * Extracts error code, message, and suggestion from typed errors (GpcError, AuthError, ApiError, ConfigError).\n */\n\ninterface TypedError {\n message: string;\n code?: string;\n suggestion?: string;\n exitCode?: number;\n /** When true, error handler prints nothing (e.g., user-aborted operations). */\n silent?: boolean;\n}\n\nfunction isTypedError(error: unknown): error is Error & TypedError {\n return (\n error instanceof Error && \"code\" in error && typeof (error as TypedError).code === \"string\"\n );\n}\n\nconst AUTH_KEYWORDS = [\"AUTH\", \"UNAUTHENTICATED\", \"PERMISSION_DENIED\", \"401\", \"403\"];\n\nfunction isAuthRelatedError(error: unknown): boolean {\n if (isTypedError(error)) {\n // Update errors hit GitHub, not Google Play — never an auth issue\n if (error.code?.startsWith(\"UPDATE_\")) return false;\n if (error.exitCode === 3) return true;\n if (error.code && AUTH_KEYWORDS.some((k) => error.code?.includes(k))) return true;\n }\n const msg = error instanceof Error ? error.message : String(error);\n return AUTH_KEYWORDS.some((k) => msg.includes(k));\n}\n\n/**\n * Format an error for CLI output. Prints:\n * Error [CODE]: message\n * Suggestion: suggestion (if available)\n *\n * Returns the appropriate exit code.\n */\nexport function handleCliError(error: unknown): number {\n // Silent errors (e.g., user abort) — don't print anything\n if (isTypedError(error) && error.silent) {\n return error.exitCode ?? 0;\n }\n\n const authHint = isAuthRelatedError(error)\n ? \"\\n\\u2192 Run gpc doctor to diagnose your credentials.\"\n : \"\";\n\n if (isTypedError(error)) {\n console.error(`Error [${error.code}]: ${error.message}`);\n if (error.suggestion) {\n console.error(`Suggestion: ${error.suggestion}`);\n }\n if (authHint) console.error(authHint);\n return error.exitCode ?? 1;\n }\n\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${message}`);\n if (authHint) console.error(authHint);\n return 1;\n}\n"],"mappings":"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","names":["loader","_"]}
|
|
@@ -1 +0,0 @@
|
|
|
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, 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// 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. 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":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|