@gpc-cli/cli 0.9.29 → 0.9.31
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/dist/apps-CVBURB5V.js +0 -0
- package/dist/audit-A4BP27DN.js +0 -0
- package/dist/auth-5XAQMZRV.js +0 -0
- package/dist/bin.js +8 -83
- package/dist/bin.js.map +1 -1
- package/dist/bundle-7IF5FIB4.js +0 -0
- package/dist/chunk-4O4D5SGL.js +86 -0
- package/dist/chunk-4O4D5SGL.js.map +1 -0
- package/dist/{chunk-SIY3HJN6.js → chunk-5VVYPCDE.js} +4 -1
- package/dist/chunk-5VVYPCDE.js.map +1 -0
- package/dist/chunk-ELXAK7GI.js +0 -0
- package/dist/chunk-FWKYRLKY.js +0 -0
- package/dist/chunk-NV75I5VP.js +0 -0
- package/dist/chunk-Y3QZDAKS.js +0 -0
- package/dist/completion-C3PPWNS7.js +0 -0
- package/dist/config-2L7QUYWP.js +0 -0
- package/dist/data-safety-GDPKV5PN.js +0 -0
- package/dist/device-tiers-GHIYJPMB.js +0 -0
- package/dist/docs-HIGQU4UL.js +0 -0
- package/dist/doctor-UZB2UB5X.js +0 -0
- package/dist/external-transactions-HCL7ROMN.js +0 -0
- package/dist/generated-apks-VX7HYZDU.js +0 -0
- package/dist/iap-BBHF7BLZ.js +0 -0
- package/dist/index.js +1 -1
- package/dist/install-skills-OV4HVANW.js +0 -0
- package/dist/internal-sharing-E7SJYDW3.js +0 -0
- package/dist/listings-VSBHQY5H.js +0 -0
- package/dist/migrate-XQV7P4R7.js +0 -0
- package/dist/one-time-products-2PK4QKWE.js +0 -0
- package/dist/pricing-BYZSLN74.js +0 -0
- package/dist/prompt-BSV22CQZ.js +0 -0
- package/dist/publish-I6WJGR4S.js +0 -0
- package/dist/purchase-options-CKRN4VIW.js +0 -0
- package/dist/purchases-YRO6B7M6.js +0 -0
- package/dist/recovery-S5UNJDBO.js +0 -0
- package/dist/releases-JMRKXEZU.js +0 -0
- package/dist/reports-N5X66IUN.js +0 -0
- package/dist/reviews-GJAQ5OVC.js +0 -0
- package/dist/status-6Y2CHHVD.js +0 -0
- package/dist/subscriptions-Z5ZPVUFM.js +0 -0
- package/dist/testers-UWSUGGVT.js +0 -0
- package/dist/tracks-XFUN7JJX.js +0 -0
- package/dist/update-GC2A2WVP.js +451 -0
- package/dist/update-GC2A2WVP.js.map +1 -0
- package/dist/users-JASXONRY.js +0 -0
- package/dist/validate-MHLPENCM.js +0 -0
- package/dist/vitals-KSNAVN5F.js +0 -0
- package/package.json +17 -17
- package/LICENSE +0 -21
- package/dist/chunk-SIY3HJN6.js.map +0 -1
package/dist/apps-CVBURB5V.js
CHANGED
|
File without changes
|
package/dist/audit-A4BP27DN.js
CHANGED
|
File without changes
|
package/dist/auth-5XAQMZRV.js
CHANGED
|
File without changes
|
package/dist/bin.js
CHANGED
|
@@ -3,7 +3,11 @@ import {
|
|
|
3
3
|
createProgram,
|
|
4
4
|
handleCliError,
|
|
5
5
|
loadPlugins
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5VVYPCDE.js";
|
|
7
|
+
import {
|
|
8
|
+
checkForUpdate,
|
|
9
|
+
formatUpdateNotification
|
|
10
|
+
} from "./chunk-4O4D5SGL.js";
|
|
7
11
|
|
|
8
12
|
// src/networking.ts
|
|
9
13
|
async function setupNetworking() {
|
|
@@ -26,90 +30,11 @@ async function setupNetworking() {
|
|
|
26
30
|
// src/bin.ts
|
|
27
31
|
import { initAudit, sendWebhook } from "@gpc-cli/core";
|
|
28
32
|
import { getConfigDir, loadConfig } from "@gpc-cli/config";
|
|
29
|
-
|
|
30
|
-
// src/update-check.ts
|
|
31
|
-
import { join } from "path";
|
|
32
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
33
|
-
import { getCacheDir } from "@gpc-cli/config";
|
|
34
|
-
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
35
|
-
var FETCH_TIMEOUT_MS = 3e3;
|
|
36
|
-
var REGISTRY_URL = "https://registry.npmjs.org/@gpc-cli/cli/latest";
|
|
37
|
-
function getCacheFilePath() {
|
|
38
|
-
return join(getCacheDir(), "update-check.json");
|
|
39
|
-
}
|
|
40
|
-
function isNewerVersion(current, latest) {
|
|
41
|
-
const a = current.split(".").map(Number);
|
|
42
|
-
const b = latest.split(".").map(Number);
|
|
43
|
-
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
44
|
-
const av = a[i] ?? 0;
|
|
45
|
-
const bv = b[i] ?? 0;
|
|
46
|
-
if (bv > av) return true;
|
|
47
|
-
if (bv < av) return false;
|
|
48
|
-
}
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
async function readCache() {
|
|
52
|
-
try {
|
|
53
|
-
const raw = await readFile(getCacheFilePath(), "utf-8");
|
|
54
|
-
const data = JSON.parse(raw);
|
|
55
|
-
if (typeof data.latest === "string" && typeof data.checkedAt === "number") {
|
|
56
|
-
return data;
|
|
57
|
-
}
|
|
58
|
-
return null;
|
|
59
|
-
} catch {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function writeCache(data) {
|
|
64
|
-
const filePath = getCacheFilePath();
|
|
65
|
-
const dir = join(filePath, "..");
|
|
66
|
-
mkdir(dir, { recursive: true }).then(() => writeFile(filePath, JSON.stringify(data), "utf-8")).catch(() => {
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
async function fetchLatestVersion() {
|
|
70
|
-
try {
|
|
71
|
-
const controller = new AbortController();
|
|
72
|
-
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
73
|
-
const response = await fetch(REGISTRY_URL, { signal: controller.signal });
|
|
74
|
-
clearTimeout(timeout);
|
|
75
|
-
if (!response.ok) return null;
|
|
76
|
-
const body = await response.json();
|
|
77
|
-
if (typeof body.version !== "string") return null;
|
|
78
|
-
return body.version;
|
|
79
|
-
} catch {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
async function checkForUpdate(currentVersion2) {
|
|
84
|
-
if (process.env["GPC_NO_UPDATE_CHECK"] === "1") return null;
|
|
85
|
-
if (process.env["CI"]) return null;
|
|
86
|
-
if (!process.stdout.isTTY) return null;
|
|
87
|
-
const cache = await readCache();
|
|
88
|
-
if (cache && Date.now() - cache.checkedAt < CACHE_TTL_MS) {
|
|
89
|
-
return {
|
|
90
|
-
current: currentVersion2,
|
|
91
|
-
latest: cache.latest,
|
|
92
|
-
updateAvailable: isNewerVersion(currentVersion2, cache.latest)
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
const latest = await fetchLatestVersion();
|
|
96
|
-
if (!latest) return null;
|
|
97
|
-
writeCache({ latest, checkedAt: Date.now() });
|
|
98
|
-
return {
|
|
99
|
-
current: currentVersion2,
|
|
100
|
-
latest,
|
|
101
|
-
updateAvailable: isNewerVersion(currentVersion2, latest)
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
function formatUpdateNotification(result) {
|
|
105
|
-
return `Update available: ${result.current} \u2192 ${result.latest} \u2014 npm install -g @gpc-cli/cli`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// src/bin.ts
|
|
109
33
|
await setupNetworking();
|
|
110
34
|
initAudit(getConfigDir());
|
|
111
35
|
var currentVersion = process.env["__GPC_VERSION"] || "0.0.0";
|
|
112
|
-
var
|
|
36
|
+
var isUpdateCommand = process.argv[2] === "update";
|
|
37
|
+
var updateCheckPromise = isUpdateCommand ? Promise.resolve(null) : checkForUpdate(currentVersion);
|
|
113
38
|
if (process.argv.includes("--ci")) {
|
|
114
39
|
process.env["CI"] = "1";
|
|
115
40
|
if (!process.argv.some((a) => a.startsWith("--output") || a.startsWith("-o"))) {
|
|
@@ -163,7 +88,7 @@ try {
|
|
|
163
88
|
updateCheckPromise,
|
|
164
89
|
new Promise((resolve) => setTimeout(() => resolve(null), 3e3))
|
|
165
90
|
]);
|
|
166
|
-
if (result && result.updateAvailable && process.stdout.isTTY && !process.argv.includes("--json") && program.opts()["output"] !== "json") {
|
|
91
|
+
if (result && result.updateAvailable && !isUpdateCommand && process.stdout.isTTY && !process.argv.includes("--json") && program.opts()["output"] !== "json") {
|
|
167
92
|
process.stderr.write(`
|
|
168
93
|
${formatUpdateNotification(result)}
|
|
169
94
|
`);
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/networking.ts","../src/bin.ts","../src/update-check.ts"],"sourcesContent":["/**\n * Set up proxy and custom CA certificate support.\n * Must be called before any fetch() calls.\n */\nexport async function setupNetworking(): Promise<void> {\n // Map GPC_CA_CERT to NODE_EXTRA_CA_CERTS (works in both Node and Bun)\n const caCert = process.env[\"GPC_CA_CERT\"];\n if (caCert && !process.env[\"NODE_EXTRA_CA_CERTS\"]) {\n process.env[\"NODE_EXTRA_CA_CERTS\"] = caCert;\n }\n\n // In standalone binary mode, Bun handles HTTPS_PROXY/HTTP_PROXY natively\n if (process.env[\"__GPC_BINARY\"] === \"1\") return;\n\n const proxyUrl =\n process.env[\"HTTPS_PROXY\"] ||\n process.env[\"https_proxy\"] ||\n process.env[\"HTTP_PROXY\"] ||\n process.env[\"http_proxy\"];\n if (proxyUrl) {\n try {\n // @ts-expect-error undici types not available in all environments\n const { ProxyAgent, setGlobalDispatcher } = await import(\"undici\");\n setGlobalDispatcher(new ProxyAgent(proxyUrl));\n } catch {\n console.error(\"Warning: Proxy support requires Node.js 20+. HTTPS_PROXY will be ignored.\");\n }\n }\n}\n","import { setupNetworking } from \"./networking.js\";\nimport { createProgram } from \"./program.js\";\nimport { loadPlugins } from \"./plugins.js\";\nimport { handleCliError } from \"./error-handler.js\";\nimport { initAudit, sendWebhook } from \"@gpc-cli/core\";\nimport type { WebhookPayload } from \"@gpc-cli/core\";\nimport { getConfigDir, loadConfig } from \"@gpc-cli/config\";\nimport { checkForUpdate, formatUpdateNotification } from \"./update-check.js\";\n\nawait setupNetworking();\ninitAudit(getConfigDir());\n\nconst currentVersion = process.env[\"__GPC_VERSION\"] || \"0.0.0\";\n\n// Start update check before command execution (non-blocking)\nconst updateCheckPromise = checkForUpdate(currentVersion);\n\n// Handle --ci and --json flags early (before command parsing)\nif (process.argv.includes(\"--ci\")) {\n process.env[\"CI\"] = \"1\";\n // --ci implies --output json --no-interactive --no-color\n if (!process.argv.some((a) => a.startsWith(\"--output\") || a.startsWith(\"-o\"))) {\n process.argv.push(\"--output\", \"json\");\n }\n if (!process.argv.includes(\"--no-interactive\")) {\n process.argv.push(\"--no-interactive\");\n }\n if (!process.argv.includes(\"--no-color\")) {\n process.argv.push(\"--no-color\");\n }\n}\nif (process.argv.includes(\"--json\") || process.argv.includes(\"-j\")) {\n if (!process.argv.some((a) => a.startsWith(\"--output\") || a.startsWith(\"-o\"))) {\n process.argv.push(\"--output\", \"json\");\n }\n}\n\nconst pluginManager = await loadPlugins();\nconst program = await createProgram(pluginManager);\n\nconst startTime = Date.now();\nlet commandSuccess = true;\nlet commandError: string | undefined;\n\nawait program.parseAsync(process.argv).catch((error: unknown) => {\n commandSuccess = false;\n commandError = error instanceof Error ? error.message : String(error);\n const exitCode = handleCliError(error);\n process.exit(exitCode);\n});\n\n// Send webhook notification if --notify was set\nconst notifyOpt = program.opts()[\"notify\"] as string | boolean | undefined;\nif (notifyOpt !== undefined && notifyOpt !== false) {\n try {\n const config = await loadConfig();\n if (config.webhooks) {\n const commandName = process.argv.slice(2).filter((a) => !a.startsWith(\"--notify\")).join(\" \");\n const payload: WebhookPayload = {\n command: commandName || \"unknown\",\n success: commandSuccess,\n duration: Date.now() - startTime,\n app: program.opts()[\"app\"] as string | undefined,\n error: commandError,\n };\n\n const target = typeof notifyOpt === \"string\" ? notifyOpt : undefined;\n // Fire-and-forget — do not block exit\n sendWebhook(config.webhooks, payload, target).catch(() => {});\n }\n } catch {\n // Never let webhook logic break the CLI\n }\n}\n\n// After command completes, show update notification if available\ntry {\n const result = await Promise.race([\n updateCheckPromise,\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 3000)),\n ]);\n\n if (\n result &&\n result.updateAvailable &&\n process.stdout.isTTY &&\n !process.argv.includes(\"--json\") &&\n program.opts()[\"output\"] !== \"json\"\n ) {\n process.stderr.write(`\\n${formatUpdateNotification(result)}\\n`);\n }\n} catch {\n // Silently ignore update check failures\n}\n","import { join } from \"node:path\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { getCacheDir } from \"@gpc-cli/config\";\n\nexport interface UpdateCheckResult {\n current: string;\n latest: string;\n updateAvailable: boolean;\n}\n\ninterface CacheData {\n latest: string;\n checkedAt: number;\n}\n\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\nconst FETCH_TIMEOUT_MS = 3000;\nconst REGISTRY_URL = \"https://registry.npmjs.org/@gpc-cli/cli/latest\";\n\nfunction getCacheFilePath(): string {\n return join(getCacheDir(), \"update-check.json\");\n}\n\n/**\n * Compare two semver strings numerically.\n * Returns true if `b` is newer than `a`.\n */\nexport function isNewerVersion(current: string, latest: string): boolean {\n const a = current.split(\".\").map(Number);\n const b = latest.split(\".\").map(Number);\n for (let i = 0; i < Math.max(a.length, b.length); i++) {\n const av = a[i] ?? 0;\n const bv = b[i] ?? 0;\n if (bv > av) return true;\n if (bv < av) return false;\n }\n return false;\n}\n\nasync function readCache(): Promise<CacheData | null> {\n try {\n const raw = await readFile(getCacheFilePath(), \"utf-8\");\n const data = JSON.parse(raw) as CacheData;\n if (typeof data.latest === \"string\" && typeof data.checkedAt === \"number\") {\n return data;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(data: CacheData): void {\n const filePath = getCacheFilePath();\n const dir = join(filePath, \"..\");\n // Fire-and-forget: ignore write errors\n mkdir(dir, { recursive: true })\n .then(() => writeFile(filePath, JSON.stringify(data), \"utf-8\"))\n .catch(() => {});\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n\n if (!response.ok) return null;\n\n const body = (await response.json()) as { version?: string };\n if (typeof body.version !== \"string\") return null;\n\n return body.version;\n } catch {\n return null;\n }\n}\n\n/**\n * Check for a newer version of @gpc-cli/cli on npm.\n * Returns null if the check is skipped or fails.\n */\nexport async function checkForUpdate(currentVersion: string): Promise<UpdateCheckResult | null> {\n // Skip in non-interactive or CI environments\n if (process.env[\"GPC_NO_UPDATE_CHECK\"] === \"1\") return null;\n if (process.env[\"CI\"]) return null;\n if (!process.stdout.isTTY) return null;\n\n // Check cache first\n const cache = await readCache();\n if (cache && Date.now() - cache.checkedAt < CACHE_TTL_MS) {\n return {\n current: currentVersion,\n latest: cache.latest,\n updateAvailable: isNewerVersion(currentVersion, cache.latest),\n };\n }\n\n // Fetch from registry\n const latest = await fetchLatestVersion();\n if (!latest) return null;\n\n // Write cache (fire-and-forget)\n writeCache({ latest, checkedAt: Date.now() });\n\n return {\n current: currentVersion,\n latest,\n updateAvailable: isNewerVersion(currentVersion, latest),\n };\n}\n\n/**\n * Format a user-facing update notification string.\n */\nexport function formatUpdateNotification(result: UpdateCheckResult): string {\n return `Update available: ${result.current} \\u2192 ${result.latest} \\u2014 npm install -g @gpc-cli/cli`;\n}\n"],"mappings":"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","names":["currentVersion"]}
|
|
1
|
+
{"version":3,"sources":["../src/networking.ts","../src/bin.ts"],"sourcesContent":["/**\n * Set up proxy and custom CA certificate support.\n * Must be called before any fetch() calls.\n */\nexport async function setupNetworking(): Promise<void> {\n // Map GPC_CA_CERT to NODE_EXTRA_CA_CERTS (works in both Node and Bun)\n const caCert = process.env[\"GPC_CA_CERT\"];\n if (caCert && !process.env[\"NODE_EXTRA_CA_CERTS\"]) {\n process.env[\"NODE_EXTRA_CA_CERTS\"] = caCert;\n }\n\n // In standalone binary mode, Bun handles HTTPS_PROXY/HTTP_PROXY natively\n if (process.env[\"__GPC_BINARY\"] === \"1\") return;\n\n const proxyUrl =\n process.env[\"HTTPS_PROXY\"] ||\n process.env[\"https_proxy\"] ||\n process.env[\"HTTP_PROXY\"] ||\n process.env[\"http_proxy\"];\n if (proxyUrl) {\n try {\n // @ts-expect-error undici types not available in all environments\n const { ProxyAgent, setGlobalDispatcher } = await import(\"undici\");\n setGlobalDispatcher(new ProxyAgent(proxyUrl));\n } catch {\n console.error(\"Warning: Proxy support requires Node.js 20+. HTTPS_PROXY will be ignored.\");\n }\n }\n}\n","import { setupNetworking } from \"./networking.js\";\nimport { createProgram } from \"./program.js\";\nimport { loadPlugins } from \"./plugins.js\";\nimport { handleCliError } from \"./error-handler.js\";\nimport { initAudit, sendWebhook } from \"@gpc-cli/core\";\nimport type { WebhookPayload } from \"@gpc-cli/core\";\nimport { getConfigDir, loadConfig } from \"@gpc-cli/config\";\nimport { checkForUpdate, formatUpdateNotification } from \"./update-check.js\";\n\nawait setupNetworking();\ninitAudit(getConfigDir());\n\nconst currentVersion = process.env[\"__GPC_VERSION\"] || \"0.0.0\";\n\n// Skip passive update check when the user is explicitly running `gpc update` —\n// that command does its own check against the GitHub Releases API.\nconst isUpdateCommand = process.argv[2] === \"update\";\n\n// Start update check before command execution (non-blocking)\nconst updateCheckPromise = isUpdateCommand ? Promise.resolve(null) : checkForUpdate(currentVersion);\n\n// Handle --ci and --json flags early (before command parsing)\nif (process.argv.includes(\"--ci\")) {\n process.env[\"CI\"] = \"1\";\n // --ci implies --output json --no-interactive --no-color\n if (!process.argv.some((a) => a.startsWith(\"--output\") || a.startsWith(\"-o\"))) {\n process.argv.push(\"--output\", \"json\");\n }\n if (!process.argv.includes(\"--no-interactive\")) {\n process.argv.push(\"--no-interactive\");\n }\n if (!process.argv.includes(\"--no-color\")) {\n process.argv.push(\"--no-color\");\n }\n}\nif (process.argv.includes(\"--json\") || process.argv.includes(\"-j\")) {\n if (!process.argv.some((a) => a.startsWith(\"--output\") || a.startsWith(\"-o\"))) {\n process.argv.push(\"--output\", \"json\");\n }\n}\n\nconst pluginManager = await loadPlugins();\nconst program = await createProgram(pluginManager);\n\nconst startTime = Date.now();\nlet commandSuccess = true;\nlet commandError: string | undefined;\n\nawait program.parseAsync(process.argv).catch((error: unknown) => {\n commandSuccess = false;\n commandError = error instanceof Error ? error.message : String(error);\n const exitCode = handleCliError(error);\n process.exit(exitCode);\n});\n\n// Send webhook notification if --notify was set\nconst notifyOpt = program.opts()[\"notify\"] as string | boolean | undefined;\nif (notifyOpt !== undefined && notifyOpt !== false) {\n try {\n const config = await loadConfig();\n if (config.webhooks) {\n const commandName = process.argv.slice(2).filter((a) => !a.startsWith(\"--notify\")).join(\" \");\n const payload: WebhookPayload = {\n command: commandName || \"unknown\",\n success: commandSuccess,\n duration: Date.now() - startTime,\n app: program.opts()[\"app\"] as string | undefined,\n error: commandError,\n };\n\n const target = typeof notifyOpt === \"string\" ? notifyOpt : undefined;\n // Fire-and-forget — do not block exit\n sendWebhook(config.webhooks, payload, target).catch(() => {});\n }\n } catch {\n // Never let webhook logic break the CLI\n }\n}\n\n// After command completes, show update notification if available\n// isUpdateCommand is declared above — update check was skipped for this command\ntry {\n const result = await Promise.race([\n updateCheckPromise,\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 3000)),\n ]);\n\n if (\n result &&\n result.updateAvailable &&\n !isUpdateCommand &&\n process.stdout.isTTY &&\n !process.argv.includes(\"--json\") &&\n program.opts()[\"output\"] !== \"json\"\n ) {\n process.stderr.write(`\\n${formatUpdateNotification(result)}\\n`);\n }\n} catch {\n // Silently ignore update check failures\n}\n"],"mappings":"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","names":[]}
|
package/dist/bundle-7IF5FIB4.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/update-check.ts
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
6
|
+
import { getCacheDir } from "@gpc-cli/config";
|
|
7
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8
|
+
var FETCH_TIMEOUT_MS = 3e3;
|
|
9
|
+
var REGISTRY_URL = "https://registry.npmjs.org/@gpc-cli/cli/latest";
|
|
10
|
+
function getCacheFilePath() {
|
|
11
|
+
return join(getCacheDir(), "update-check.json");
|
|
12
|
+
}
|
|
13
|
+
function isNewerVersion(current, latest) {
|
|
14
|
+
const a = current.split(".").map(Number);
|
|
15
|
+
const b = latest.split(".").map(Number);
|
|
16
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
17
|
+
const av = a[i] ?? 0;
|
|
18
|
+
const bv = b[i] ?? 0;
|
|
19
|
+
if (bv > av) return true;
|
|
20
|
+
if (bv < av) return false;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
async function readCache() {
|
|
25
|
+
try {
|
|
26
|
+
const raw = await readFile(getCacheFilePath(), "utf-8");
|
|
27
|
+
const data = JSON.parse(raw);
|
|
28
|
+
if (typeof data.latest === "string" && typeof data.checkedAt === "number") {
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function writeCache(data) {
|
|
37
|
+
const filePath = getCacheFilePath();
|
|
38
|
+
const dir = join(filePath, "..");
|
|
39
|
+
mkdir(dir, { recursive: true }).then(() => writeFile(filePath, JSON.stringify(data), "utf-8")).catch(() => {
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async function fetchLatestVersion() {
|
|
43
|
+
try {
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
46
|
+
const response = await fetch(REGISTRY_URL, { signal: controller.signal });
|
|
47
|
+
clearTimeout(timeout);
|
|
48
|
+
if (!response.ok) return null;
|
|
49
|
+
const body = await response.json();
|
|
50
|
+
if (typeof body.version !== "string") return null;
|
|
51
|
+
return body.version;
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function checkForUpdate(currentVersion) {
|
|
57
|
+
if (process.env["GPC_NO_UPDATE_CHECK"] === "1") return null;
|
|
58
|
+
if (process.env["CI"]) return null;
|
|
59
|
+
if (!process.stdout.isTTY) return null;
|
|
60
|
+
const cache = await readCache();
|
|
61
|
+
if (cache && Date.now() - cache.checkedAt < CACHE_TTL_MS) {
|
|
62
|
+
return {
|
|
63
|
+
current: currentVersion,
|
|
64
|
+
latest: cache.latest,
|
|
65
|
+
updateAvailable: isNewerVersion(currentVersion, cache.latest)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const latest = await fetchLatestVersion();
|
|
69
|
+
if (!latest) return null;
|
|
70
|
+
writeCache({ latest, checkedAt: Date.now() });
|
|
71
|
+
return {
|
|
72
|
+
current: currentVersion,
|
|
73
|
+
latest,
|
|
74
|
+
updateAvailable: isNewerVersion(currentVersion, latest)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function formatUpdateNotification(result) {
|
|
78
|
+
return `Update available: ${result.current} \u2192 ${result.latest} \u2014 Run: gpc update`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
isNewerVersion,
|
|
83
|
+
checkForUpdate,
|
|
84
|
+
formatUpdateNotification
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=chunk-4O4D5SGL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/update-check.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { getCacheDir } from \"@gpc-cli/config\";\n\nexport interface UpdateCheckResult {\n current: string;\n latest: string;\n updateAvailable: boolean;\n}\n\ninterface CacheData {\n latest: string;\n checkedAt: number;\n}\n\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\nconst FETCH_TIMEOUT_MS = 3000;\nconst REGISTRY_URL = \"https://registry.npmjs.org/@gpc-cli/cli/latest\";\n\nfunction getCacheFilePath(): string {\n return join(getCacheDir(), \"update-check.json\");\n}\n\n/**\n * Compare two semver strings numerically.\n * Returns true if `b` is newer than `a`.\n */\nexport function isNewerVersion(current: string, latest: string): boolean {\n const a = current.split(\".\").map(Number);\n const b = latest.split(\".\").map(Number);\n for (let i = 0; i < Math.max(a.length, b.length); i++) {\n const av = a[i] ?? 0;\n const bv = b[i] ?? 0;\n if (bv > av) return true;\n if (bv < av) return false;\n }\n return false;\n}\n\nasync function readCache(): Promise<CacheData | null> {\n try {\n const raw = await readFile(getCacheFilePath(), \"utf-8\");\n const data = JSON.parse(raw) as CacheData;\n if (typeof data.latest === \"string\" && typeof data.checkedAt === \"number\") {\n return data;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction writeCache(data: CacheData): void {\n const filePath = getCacheFilePath();\n const dir = join(filePath, \"..\");\n // Fire-and-forget: ignore write errors\n mkdir(dir, { recursive: true })\n .then(() => writeFile(filePath, JSON.stringify(data), \"utf-8\"))\n .catch(() => {});\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n\n if (!response.ok) return null;\n\n const body = (await response.json()) as { version?: string };\n if (typeof body.version !== \"string\") return null;\n\n return body.version;\n } catch {\n return null;\n }\n}\n\n/**\n * Check for a newer version of @gpc-cli/cli on npm.\n * Returns null if the check is skipped or fails.\n */\nexport async function checkForUpdate(currentVersion: string): Promise<UpdateCheckResult | null> {\n // Skip in non-interactive or CI environments\n if (process.env[\"GPC_NO_UPDATE_CHECK\"] === \"1\") return null;\n if (process.env[\"CI\"]) return null;\n if (!process.stdout.isTTY) return null;\n\n // Check cache first\n const cache = await readCache();\n if (cache && Date.now() - cache.checkedAt < CACHE_TTL_MS) {\n return {\n current: currentVersion,\n latest: cache.latest,\n updateAvailable: isNewerVersion(currentVersion, cache.latest),\n };\n }\n\n // Fetch from registry\n const latest = await fetchLatestVersion();\n if (!latest) return null;\n\n // Write cache (fire-and-forget)\n writeCache({ latest, checkedAt: Date.now() });\n\n return {\n current: currentVersion,\n latest,\n updateAvailable: isNewerVersion(currentVersion, latest),\n };\n}\n\n/**\n * Format a user-facing update notification string.\n */\nexport function formatUpdateNotification(result: UpdateCheckResult): string {\n return `Update available: ${result.current} \\u2192 ${result.latest} \\u2014 Run: gpc update`;\n}\n"],"mappings":";;;AAAA,SAAS,YAAY;AACrB,SAAS,UAAU,WAAW,aAAa;AAC3C,SAAS,mBAAmB;AAa5B,IAAM,eAAe,KAAK,KAAK,KAAK;AACpC,IAAM,mBAAmB;AACzB,IAAM,eAAe;AAErB,SAAS,mBAA2B;AAClC,SAAO,KAAK,YAAY,GAAG,mBAAmB;AAChD;AAMO,SAAS,eAAe,SAAiB,QAAyB;AACvE,QAAM,IAAI,QAAQ,MAAM,GAAG,EAAE,IAAI,MAAM;AACvC,QAAM,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI,MAAM;AACtC,WAAS,IAAI,GAAG,IAAI,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK;AACrD,UAAM,KAAK,EAAE,CAAC,KAAK;AACnB,UAAM,KAAK,EAAE,CAAC,KAAK;AACnB,QAAI,KAAK,GAAI,QAAO;AACpB,QAAI,KAAK,GAAI,QAAO;AAAA,EACtB;AACA,SAAO;AACT;AAEA,eAAe,YAAuC;AACpD,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,iBAAiB,GAAG,OAAO;AACtD,UAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,QAAI,OAAO,KAAK,WAAW,YAAY,OAAO,KAAK,cAAc,UAAU;AACzE,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAW,MAAuB;AACzC,QAAM,WAAW,iBAAiB;AAClC,QAAM,MAAM,KAAK,UAAU,IAAI;AAE/B,QAAM,KAAK,EAAE,WAAW,KAAK,CAAC,EAC3B,KAAK,MAAM,UAAU,UAAU,KAAK,UAAU,IAAI,GAAG,OAAO,CAAC,EAC7D,MAAM,MAAM;AAAA,EAAC,CAAC;AACnB;AAEA,eAAe,qBAA6C;AAC1D,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,gBAAgB;AAErE,UAAM,WAAW,MAAM,MAAM,cAAc,EAAE,QAAQ,WAAW,OAAO,CAAC;AACxE,iBAAa,OAAO;AAEpB,QAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,QAAI,OAAO,KAAK,YAAY,SAAU,QAAO;AAE7C,WAAO,KAAK;AAAA,EACd,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,eAAe,gBAA2D;AAE9F,MAAI,QAAQ,IAAI,qBAAqB,MAAM,IAAK,QAAO;AACvD,MAAI,QAAQ,IAAI,IAAI,EAAG,QAAO;AAC9B,MAAI,CAAC,QAAQ,OAAO,MAAO,QAAO;AAGlC,QAAM,QAAQ,MAAM,UAAU;AAC9B,MAAI,SAAS,KAAK,IAAI,IAAI,MAAM,YAAY,cAAc;AACxD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ,MAAM;AAAA,MACd,iBAAiB,eAAe,gBAAgB,MAAM,MAAM;AAAA,IAC9D;AAAA,EACF;AAGA,QAAM,SAAS,MAAM,mBAAmB;AACxC,MAAI,CAAC,OAAQ,QAAO;AAGpB,aAAW,EAAE,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC;AAE5C,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA,iBAAiB,eAAe,gBAAgB,MAAM;AAAA,EACxD;AACF;AAKO,SAAS,yBAAyB,QAAmC;AAC1E,SAAO,qBAAqB,OAAO,OAAO,WAAW,OAAO,MAAM;AACpE;","names":[]}
|
|
@@ -78,6 +78,9 @@ async function createProgram(pluginManager) {
|
|
|
78
78
|
doctor: async () => {
|
|
79
79
|
(await import("./doctor-UZB2UB5X.js")).registerDoctorCommand(program);
|
|
80
80
|
},
|
|
81
|
+
update: async () => {
|
|
82
|
+
(await import("./update-GC2A2WVP.js")).registerUpdateCommand(program);
|
|
83
|
+
},
|
|
81
84
|
docs: async () => {
|
|
82
85
|
(await import("./docs-HIGQU4UL.js")).registerDocsCommand(program);
|
|
83
86
|
},
|
|
@@ -308,4 +311,4 @@ export {
|
|
|
308
311
|
createProgram,
|
|
309
312
|
handleCliError
|
|
310
313
|
};
|
|
311
|
-
//# sourceMappingURL=chunk-
|
|
314
|
+
//# sourceMappingURL=chunk-5VVYPCDE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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(\"The complete Google Play CLI\")\n .version(process.env[\"__GPC_VERSION\"] || \"0.0.0\", \"-V, --version\")\n .option(\"-o, --output <format>\", \"Output format: table, json, yaml, markdown, 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 .showSuggestionAfterError(true);\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 completion: async () => {\n (await import(\"./commands/completion.js\")).registerCompletionCommand(program);\n },\n apps: async () => {\n (await import(\"./commands/apps.js\")).registerAppsCommands(program);\n },\n releases: async () => {\n (await import(\"./commands/releases.js\")).registerReleasesCommands(program);\n },\n tracks: async () => {\n (await import(\"./commands/tracks.js\")).registerTracksCommands(program);\n },\n status: async () => {\n (await import(\"./commands/status.js\")).registerStatusCommand(program);\n },\n listings: async () => {\n (await import(\"./commands/listings.js\")).registerListingsCommands(program);\n },\n reviews: async () => {\n (await import(\"./commands/reviews.js\")).registerReviewsCommands(program);\n },\n vitals: async () => {\n (await import(\"./commands/vitals.js\")).registerVitalsCommands(program);\n },\n subscriptions: async () => {\n (await import(\"./commands/subscriptions.js\")).registerSubscriptionsCommands(program);\n },\n iap: async () => {\n (await import(\"./commands/iap.js\")).registerIapCommands(program);\n },\n purchases: async () => {\n (await import(\"./commands/purchases.js\")).registerPurchasesCommands(program);\n },\n pricing: async () => {\n (await import(\"./commands/pricing.js\")).registerPricingCommands(program);\n },\n reports: async () => {\n (await import(\"./commands/reports.js\")).registerReportsCommands(program);\n },\n users: async () => {\n (await import(\"./commands/users.js\")).registerUsersCommands(program);\n },\n testers: async () => {\n (await import(\"./commands/testers.js\")).registerTestersCommands(program);\n },\n validate: async () => {\n (await import(\"./commands/validate.js\")).registerValidateCommand(program);\n },\n publish: async () => {\n (await import(\"./commands/publish.js\")).registerPublishCommand(program);\n },\n 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 \"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 \"install-skills\": async () => {\n (await import(\"./commands/install-skills.js\")).registerInstallSkillsCommand(program);\n },\n plugins: async () => {\n registerPluginsCommand(program, pluginManager);\n },\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\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}\n\nfunction isTypedError(error: unknown): error is Error & TypedError {\n return error instanceof Error && \"code\" in error && typeof (error as TypedError).code === \"string\";\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 if (isTypedError(error)) {\n console.error(`Error [${error.code}]: ${error.message}`);\n if (error.suggestion) {\n console.error(`Suggestion: ${error.suggestion}`);\n }\n return error.exitCode ?? 1;\n }\n\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${message}`);\n return 1;\n}\n"],"mappings":"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","names":["loader"]}
|
package/dist/chunk-ELXAK7GI.js
CHANGED
|
File without changes
|
package/dist/chunk-FWKYRLKY.js
CHANGED
|
File without changes
|
package/dist/chunk-NV75I5VP.js
CHANGED
|
File without changes
|
package/dist/chunk-Y3QZDAKS.js
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/config-2L7QUYWP.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/docs-HIGQU4UL.js
CHANGED
|
File without changes
|
package/dist/doctor-UZB2UB5X.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/iap-BBHF7BLZ.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/migrate-XQV7P4R7.js
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/pricing-BYZSLN74.js
CHANGED
|
File without changes
|
package/dist/prompt-BSV22CQZ.js
CHANGED
|
File without changes
|
package/dist/publish-I6WJGR4S.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/dist/reports-N5X66IUN.js
CHANGED
|
File without changes
|
package/dist/reviews-GJAQ5OVC.js
CHANGED
|
File without changes
|
package/dist/status-6Y2CHHVD.js
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/testers-UWSUGGVT.js
CHANGED
|
File without changes
|
package/dist/tracks-XFUN7JJX.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
isNewerVersion
|
|
4
|
+
} from "./chunk-4O4D5SGL.js";
|
|
5
|
+
|
|
6
|
+
// src/updater.ts
|
|
7
|
+
import { createWriteStream } from "fs";
|
|
8
|
+
import { rename, chmod, unlink, stat } from "fs/promises";
|
|
9
|
+
import { realpathSync } from "fs";
|
|
10
|
+
import { join, dirname } from "path";
|
|
11
|
+
import { createHash } from "crypto";
|
|
12
|
+
import { pipeline } from "stream/promises";
|
|
13
|
+
import { Readable, Transform } from "stream";
|
|
14
|
+
import { spawn } from "child_process";
|
|
15
|
+
var GITHUB_API_URL = "https://api.github.com/repos/yasserstudio/gpc/releases/latest";
|
|
16
|
+
var GITHUB_TIMEOUT_MS = 1e4;
|
|
17
|
+
var DOWNLOAD_TIMEOUT_MS = 12e4;
|
|
18
|
+
function detectInstallMethod() {
|
|
19
|
+
if (process.env["__GPC_BINARY"] === "1") return "binary";
|
|
20
|
+
if (process.env["npm_config_prefix"]) return "npm";
|
|
21
|
+
try {
|
|
22
|
+
const resolved = realpathSync(process.argv[1] ?? "").toLowerCase();
|
|
23
|
+
if (resolved.includes("cellar") || resolved.includes("homebrew")) return "homebrew";
|
|
24
|
+
if (resolved.includes("node_modules")) return "npm";
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
return "unknown";
|
|
28
|
+
}
|
|
29
|
+
function getPlatformAsset() {
|
|
30
|
+
const arch = process.arch === "arm64" ? "arm64" : "x64";
|
|
31
|
+
switch (process.platform) {
|
|
32
|
+
case "darwin":
|
|
33
|
+
return `gpc-darwin-${arch}`;
|
|
34
|
+
case "linux":
|
|
35
|
+
return `gpc-linux-${arch}`;
|
|
36
|
+
case "win32":
|
|
37
|
+
return "gpc-windows-x64.exe";
|
|
38
|
+
default:
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function getCurrentBinaryPath() {
|
|
43
|
+
if (process.env["__GPC_BINARY"] === "1") return process.execPath;
|
|
44
|
+
return process.argv[1] ?? process.execPath;
|
|
45
|
+
}
|
|
46
|
+
function githubHeaders() {
|
|
47
|
+
const headers = {
|
|
48
|
+
"User-Agent": "gpc-cli",
|
|
49
|
+
Accept: "application/vnd.github+json",
|
|
50
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
51
|
+
};
|
|
52
|
+
if (process.env["GPC_GITHUB_TOKEN"]) {
|
|
53
|
+
headers["Authorization"] = `Bearer ${process.env["GPC_GITHUB_TOKEN"]}`;
|
|
54
|
+
}
|
|
55
|
+
return headers;
|
|
56
|
+
}
|
|
57
|
+
async function fetchLatestRelease() {
|
|
58
|
+
let response;
|
|
59
|
+
try {
|
|
60
|
+
response = await fetch(GITHUB_API_URL, {
|
|
61
|
+
headers: githubHeaders(),
|
|
62
|
+
signal: AbortSignal.timeout(GITHUB_TIMEOUT_MS)
|
|
63
|
+
});
|
|
64
|
+
} catch (err) {
|
|
65
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
66
|
+
throw Object.assign(new Error(`Network error checking for updates: ${msg}`), {
|
|
67
|
+
code: "NETWORK_ERROR",
|
|
68
|
+
exitCode: 5
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (response.status === 429) {
|
|
72
|
+
throw Object.assign(
|
|
73
|
+
new Error(
|
|
74
|
+
"GitHub API rate limit exceeded. Set GPC_GITHUB_TOKEN to increase the limit."
|
|
75
|
+
),
|
|
76
|
+
{ code: "UPDATE_RATE_LIMITED", exitCode: 4 }
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
throw Object.assign(new Error(`GitHub API returned HTTP ${response.status}`), {
|
|
81
|
+
code: "UPDATE_API_ERROR",
|
|
82
|
+
exitCode: 4
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return await response.json();
|
|
86
|
+
}
|
|
87
|
+
async function fetchChecksums(release) {
|
|
88
|
+
const asset = release.assets.find((a) => a.name === "checksums.txt");
|
|
89
|
+
if (!asset) return /* @__PURE__ */ new Map();
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(asset.browser_download_url, {
|
|
92
|
+
headers: githubHeaders(),
|
|
93
|
+
signal: AbortSignal.timeout(GITHUB_TIMEOUT_MS)
|
|
94
|
+
});
|
|
95
|
+
if (!response.ok) return /* @__PURE__ */ new Map();
|
|
96
|
+
const map = /* @__PURE__ */ new Map();
|
|
97
|
+
for (const line of (await response.text()).split("\n")) {
|
|
98
|
+
const parts = line.trim().split(/\s+/);
|
|
99
|
+
const hash = parts[0];
|
|
100
|
+
const name = parts[1];
|
|
101
|
+
if (hash && name) map.set(name, hash.toLowerCase());
|
|
102
|
+
}
|
|
103
|
+
return map;
|
|
104
|
+
} catch {
|
|
105
|
+
return /* @__PURE__ */ new Map();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async function checkForUpdate(currentVersion) {
|
|
109
|
+
const release = await fetchLatestRelease();
|
|
110
|
+
const latest = release.tag_name.replace(/^v/, "");
|
|
111
|
+
return {
|
|
112
|
+
current: currentVersion,
|
|
113
|
+
latest,
|
|
114
|
+
latestTag: release.tag_name,
|
|
115
|
+
updateAvailable: isNewerVersion(currentVersion, latest),
|
|
116
|
+
installMethod: detectInstallMethod(),
|
|
117
|
+
release
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function updateViaNpm(options = {}) {
|
|
121
|
+
return new Promise((resolve, reject) => {
|
|
122
|
+
const proc = spawn("npm", ["install", "-g", "@gpc-cli/cli@latest"], {
|
|
123
|
+
// In silent (JSON) mode, redirect npm's stdout to stderr so it doesn't
|
|
124
|
+
// pollute the machine-readable JSON that gpc writes to stdout.
|
|
125
|
+
stdio: options.silent ? ["inherit", process.stderr, process.stderr] : "inherit",
|
|
126
|
+
shell: false
|
|
127
|
+
});
|
|
128
|
+
proc.on("close", (code) => {
|
|
129
|
+
if (code === 0) {
|
|
130
|
+
resolve();
|
|
131
|
+
} else {
|
|
132
|
+
reject(
|
|
133
|
+
Object.assign(new Error(`npm exited with code ${code}`), {
|
|
134
|
+
code: "UPDATE_NPM_FAILED",
|
|
135
|
+
exitCode: 1,
|
|
136
|
+
suggestion: "Run manually: npm install -g @gpc-cli/cli@latest"
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
proc.on("error", (err) => {
|
|
142
|
+
reject(
|
|
143
|
+
Object.assign(new Error(`Failed to run npm: ${err.message}`), {
|
|
144
|
+
code: "UPDATE_NPM_SPAWN_FAILED",
|
|
145
|
+
exitCode: 1,
|
|
146
|
+
suggestion: "Ensure npm is in your PATH"
|
|
147
|
+
})
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async function updateViaBrew(options = {}) {
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
const proc = spawn("brew", ["upgrade", "yasserstudio/tap/gpc"], {
|
|
155
|
+
// In silent (JSON) mode, redirect brew's stdout to stderr so it doesn't
|
|
156
|
+
// pollute the machine-readable JSON that gpc writes to stdout.
|
|
157
|
+
stdio: options.silent ? ["inherit", process.stderr, process.stderr] : "inherit",
|
|
158
|
+
shell: false
|
|
159
|
+
});
|
|
160
|
+
proc.on("close", (code) => {
|
|
161
|
+
if (code === 0) {
|
|
162
|
+
resolve();
|
|
163
|
+
} else {
|
|
164
|
+
reject(
|
|
165
|
+
Object.assign(new Error(`brew exited with code ${code}`), {
|
|
166
|
+
code: "UPDATE_BREW_FAILED",
|
|
167
|
+
exitCode: 1,
|
|
168
|
+
suggestion: "Run manually: brew upgrade yasserstudio/tap/gpc"
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
proc.on("error", (err) => {
|
|
174
|
+
reject(
|
|
175
|
+
Object.assign(new Error(`Failed to run brew: ${err.message}`), {
|
|
176
|
+
code: "UPDATE_BREW_SPAWN_FAILED",
|
|
177
|
+
exitCode: 1,
|
|
178
|
+
suggestion: "Ensure Homebrew is installed: https://brew.sh"
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function isPermissionError(err) {
|
|
185
|
+
return err instanceof Error && "code" in err && (err.code === "EACCES" || err.code === "EPERM");
|
|
186
|
+
}
|
|
187
|
+
async function sha256File(filePath) {
|
|
188
|
+
const hash = createHash("sha256");
|
|
189
|
+
const { size } = await stat(filePath);
|
|
190
|
+
if (size === 0) return hash.digest("hex");
|
|
191
|
+
const { createReadStream } = await import("fs");
|
|
192
|
+
const stream = createReadStream(filePath);
|
|
193
|
+
await pipeline(stream, async function* (source) {
|
|
194
|
+
for await (const chunk of source) {
|
|
195
|
+
hash.update(chunk);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
return hash.digest("hex");
|
|
199
|
+
}
|
|
200
|
+
async function updateBinaryInPlace(assetUrl, expectedSha256, currentBinaryPath, options = {}) {
|
|
201
|
+
const dir = dirname(currentBinaryPath);
|
|
202
|
+
const tmpPath = join(dir, `.gpc-update-${process.pid}.tmp`);
|
|
203
|
+
const oldPath = join(dir, `.gpc-old-${process.pid}`);
|
|
204
|
+
try {
|
|
205
|
+
let response;
|
|
206
|
+
try {
|
|
207
|
+
response = await fetch(assetUrl, {
|
|
208
|
+
signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
|
|
209
|
+
});
|
|
210
|
+
} catch (err) {
|
|
211
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
212
|
+
throw Object.assign(new Error(`Download failed: ${msg}`), {
|
|
213
|
+
code: "UPDATE_DOWNLOAD_FAILED",
|
|
214
|
+
exitCode: 5
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
if (!response.ok) {
|
|
218
|
+
throw Object.assign(new Error(`Download failed: HTTP ${response.status}`), {
|
|
219
|
+
code: "UPDATE_DOWNLOAD_FAILED",
|
|
220
|
+
exitCode: 4
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (!response.body) {
|
|
224
|
+
throw Object.assign(new Error("Empty response body"), {
|
|
225
|
+
code: "UPDATE_DOWNLOAD_FAILED",
|
|
226
|
+
exitCode: 4
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const contentLength = response.headers.get("content-length");
|
|
230
|
+
const total = contentLength ? parseInt(contentLength, 10) : 0;
|
|
231
|
+
let downloaded = 0;
|
|
232
|
+
const dest = createWriteStream(tmpPath);
|
|
233
|
+
const { onProgress } = options;
|
|
234
|
+
if (onProgress) {
|
|
235
|
+
const tracker = new Transform({
|
|
236
|
+
transform(chunk, _enc, cb) {
|
|
237
|
+
downloaded += chunk.length;
|
|
238
|
+
onProgress(downloaded, total);
|
|
239
|
+
cb(null, chunk);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
await pipeline(
|
|
243
|
+
Readable.fromWeb(response.body),
|
|
244
|
+
tracker,
|
|
245
|
+
dest
|
|
246
|
+
);
|
|
247
|
+
} else {
|
|
248
|
+
await pipeline(Readable.fromWeb(response.body), dest);
|
|
249
|
+
}
|
|
250
|
+
if (expectedSha256) {
|
|
251
|
+
const actual = await sha256File(tmpPath);
|
|
252
|
+
if (actual !== expectedSha256.toLowerCase()) {
|
|
253
|
+
throw Object.assign(
|
|
254
|
+
new Error(`Checksum mismatch \u2014 expected ${expectedSha256}, got ${actual}`),
|
|
255
|
+
{
|
|
256
|
+
code: "UPDATE_CHECKSUM_MISMATCH",
|
|
257
|
+
exitCode: 1,
|
|
258
|
+
suggestion: "The download may be corrupt. Try again."
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (process.platform !== "win32") {
|
|
264
|
+
await chmod(tmpPath, 493);
|
|
265
|
+
}
|
|
266
|
+
if (process.platform === "win32") {
|
|
267
|
+
await rename(currentBinaryPath, oldPath);
|
|
268
|
+
try {
|
|
269
|
+
await rename(tmpPath, currentBinaryPath);
|
|
270
|
+
} catch (renameErr) {
|
|
271
|
+
await rename(oldPath, currentBinaryPath).catch(() => {
|
|
272
|
+
});
|
|
273
|
+
throw renameErr;
|
|
274
|
+
}
|
|
275
|
+
unlink(oldPath).catch(() => {
|
|
276
|
+
});
|
|
277
|
+
} else {
|
|
278
|
+
await rename(tmpPath, currentBinaryPath);
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
await unlink(tmpPath).catch(() => {
|
|
282
|
+
});
|
|
283
|
+
if (isPermissionError(err)) {
|
|
284
|
+
throw Object.assign(
|
|
285
|
+
new Error(`Permission denied replacing ${currentBinaryPath}`),
|
|
286
|
+
{
|
|
287
|
+
code: "UPDATE_PERMISSION_DENIED",
|
|
288
|
+
exitCode: 1,
|
|
289
|
+
suggestion: `Run with elevated permissions: sudo gpc update`
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
throw err;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/commands/update.ts
|
|
298
|
+
import { createSpinner } from "@gpc-cli/core";
|
|
299
|
+
function registerUpdateCommand(program) {
|
|
300
|
+
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) => {
|
|
301
|
+
const parentOpts = cmd.parent?.opts() ?? {};
|
|
302
|
+
const jsonMode = !!(parentOpts["json"] || parentOpts["output"] === "json");
|
|
303
|
+
const currentVersion = process.env["__GPC_VERSION"] ?? "0.0.0";
|
|
304
|
+
if (currentVersion === "0.0.0") {
|
|
305
|
+
if (jsonMode) {
|
|
306
|
+
console.log(
|
|
307
|
+
JSON.stringify({
|
|
308
|
+
success: false,
|
|
309
|
+
reason: "Cannot update a development build",
|
|
310
|
+
current: currentVersion
|
|
311
|
+
})
|
|
312
|
+
);
|
|
313
|
+
} else {
|
|
314
|
+
console.log("Cannot update a development build (version: 0.0.0).");
|
|
315
|
+
}
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const spinner = createSpinner("Checking for updates...");
|
|
319
|
+
spinner.start();
|
|
320
|
+
let result;
|
|
321
|
+
try {
|
|
322
|
+
result = await checkForUpdate(currentVersion);
|
|
323
|
+
} catch (err) {
|
|
324
|
+
spinner.fail("Failed to check for updates");
|
|
325
|
+
throw err;
|
|
326
|
+
}
|
|
327
|
+
if (opts.check) {
|
|
328
|
+
spinner.stop();
|
|
329
|
+
if (jsonMode) {
|
|
330
|
+
console.log(
|
|
331
|
+
JSON.stringify({
|
|
332
|
+
current: result.current,
|
|
333
|
+
latest: result.latest,
|
|
334
|
+
updateAvailable: result.updateAvailable,
|
|
335
|
+
installMethod: result.installMethod,
|
|
336
|
+
releaseUrl: result.release.html_url
|
|
337
|
+
})
|
|
338
|
+
);
|
|
339
|
+
} else if (result.updateAvailable) {
|
|
340
|
+
console.log(`Update available: ${result.current} \u2192 ${result.latest}`);
|
|
341
|
+
console.log(`Install method: ${result.installMethod}`);
|
|
342
|
+
console.log(`Release: ${result.release.html_url}`);
|
|
343
|
+
console.log(`
|
|
344
|
+
Run: gpc update`);
|
|
345
|
+
} else {
|
|
346
|
+
console.log(`Already on latest version: v${result.current}`);
|
|
347
|
+
}
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (!result.updateAvailable && !opts.force) {
|
|
351
|
+
spinner.stop(`Already on latest version: v${result.current}`);
|
|
352
|
+
if (jsonMode) {
|
|
353
|
+
console.log(
|
|
354
|
+
JSON.stringify({
|
|
355
|
+
success: true,
|
|
356
|
+
current: result.current,
|
|
357
|
+
latest: result.latest,
|
|
358
|
+
updated: false
|
|
359
|
+
})
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
spinner.update(
|
|
365
|
+
`Updating v${result.current} \u2192 v${result.latest} (${result.installMethod})...`
|
|
366
|
+
);
|
|
367
|
+
switch (result.installMethod) {
|
|
368
|
+
case "npm":
|
|
369
|
+
spinner.stop();
|
|
370
|
+
await updateViaNpm({ silent: jsonMode });
|
|
371
|
+
break;
|
|
372
|
+
case "homebrew":
|
|
373
|
+
spinner.stop();
|
|
374
|
+
await updateViaBrew({ silent: jsonMode });
|
|
375
|
+
break;
|
|
376
|
+
case "binary": {
|
|
377
|
+
const assetName = getPlatformAsset();
|
|
378
|
+
if (!assetName) {
|
|
379
|
+
spinner.fail();
|
|
380
|
+
console.error(
|
|
381
|
+
`Error: Unsupported platform: ${process.platform}/${process.arch}`
|
|
382
|
+
);
|
|
383
|
+
console.error(
|
|
384
|
+
`Download manually: ${result.release.html_url}`
|
|
385
|
+
);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
const assetObj = result.release.assets.find((a) => a.name === assetName);
|
|
389
|
+
if (!assetObj) {
|
|
390
|
+
spinner.fail();
|
|
391
|
+
console.error(
|
|
392
|
+
`Error: No binary found for ${assetName} in release ${result.latestTag}`
|
|
393
|
+
);
|
|
394
|
+
console.error(`Check: ${result.release.html_url}`);
|
|
395
|
+
process.exit(1);
|
|
396
|
+
}
|
|
397
|
+
const sizeMB = (assetObj.size / (1024 * 1024)).toFixed(1);
|
|
398
|
+
spinner.stop();
|
|
399
|
+
const checksums = await fetchChecksums(result.release);
|
|
400
|
+
const expectedHash = checksums.get(assetName) ?? "";
|
|
401
|
+
const binaryPath = getCurrentBinaryPath();
|
|
402
|
+
if (jsonMode) {
|
|
403
|
+
await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath);
|
|
404
|
+
} else {
|
|
405
|
+
const label = `Downloading ${assetName} (${sizeMB} MB)`;
|
|
406
|
+
process.stdout.write(`${label}...
|
|
407
|
+
`);
|
|
408
|
+
let lastPct = -1;
|
|
409
|
+
await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath, {
|
|
410
|
+
onProgress(downloaded, total) {
|
|
411
|
+
if (total <= 0) return;
|
|
412
|
+
const pct = Math.min(100, Math.round(downloaded / total * 100));
|
|
413
|
+
if (pct === lastPct) return;
|
|
414
|
+
lastPct = pct;
|
|
415
|
+
const dlMB = (downloaded / (1024 * 1024)).toFixed(1);
|
|
416
|
+
process.stdout.write(
|
|
417
|
+
`\r${label} ${dlMB} / ${sizeMB} MB (${String(pct).padStart(3)}%) `
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
process.stdout.write("\n");
|
|
422
|
+
}
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
case "unknown":
|
|
426
|
+
spinner.fail();
|
|
427
|
+
console.error("Error: Could not detect install method. Update manually:");
|
|
428
|
+
console.error(` npm: npm install -g @gpc-cli/cli@latest`);
|
|
429
|
+
console.error(` Homebrew: brew upgrade yasserstudio/tap/gpc`);
|
|
430
|
+
console.error(` Binary: https://github.com/yasserstudio/gpc/releases/latest`);
|
|
431
|
+
process.exit(1);
|
|
432
|
+
}
|
|
433
|
+
if (jsonMode) {
|
|
434
|
+
console.log(
|
|
435
|
+
JSON.stringify({
|
|
436
|
+
success: true,
|
|
437
|
+
previous: result.current,
|
|
438
|
+
current: result.latest,
|
|
439
|
+
method: result.installMethod
|
|
440
|
+
})
|
|
441
|
+
);
|
|
442
|
+
} else {
|
|
443
|
+
console.log(`
|
|
444
|
+
\u2714 Updated to v${result.latest}`);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
export {
|
|
449
|
+
registerUpdateCommand
|
|
450
|
+
};
|
|
451
|
+
//# sourceMappingURL=update-GC2A2WVP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/updater.ts","../src/commands/update.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, stat } from \"node:fs/promises\";\nimport { realpathSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable, Transform } from \"node:stream\";\nimport { spawn } from \"node:child_process\";\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 — most reliable, baked in at esbuild build time\n if (process.env[\"__GPC_BINARY\"] === \"1\") return \"binary\";\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 githubHeaders(): 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 // Support GPC_GITHUB_TOKEN for authenticated requests (avoids 60 req/hr limit\n // on shared CI runner IPs)\n if (process.env[\"GPC_GITHUB_TOKEN\"]) {\n headers[\"Authorization\"] = `Bearer ${process.env[\"GPC_GITHUB_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: githubHeaders(),\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 (response.status === 429) {\n throw Object.assign(\n new Error(\n \"GitHub API rate limit exceeded. Set GPC_GITHUB_TOKEN to increase the limit.\",\n ),\n { code: \"UPDATE_RATE_LIMITED\", exitCode: 4 },\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: githubHeaders(),\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 (\n err instanceof Error &&\n \"code\" in err &&\n (err.code === \"EACCES\" || err.code === \"EPERM\")\n );\n}\n\nasync function sha256File(filePath: string): Promise<string> {\n const hash = createHash(\"sha256\");\n const { size } = await stat(filePath);\n if (size === 0) return hash.digest(\"hex\");\n\n // Read in 64 KB chunks\n const { createReadStream } = await import(\"node:fs\");\n const stream = createReadStream(filePath);\n await pipeline(stream, async function* (source) {\n for await (const chunk of source) {\n hash.update(chunk as Buffer);\n }\n });\n return hash.digest(\"hex\");\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 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(Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]), dest);\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(\n new Error(`Permission denied replacing ${currentBinaryPath}`),\n {\n code: \"UPDATE_PERMISSION_DENIED\",\n exitCode: 1,\n suggestion: `Run with elevated permissions: sudo gpc update`,\n },\n );\n }\n throw err;\n }\n}\n","import type { Command } from \"commander\";\nimport {\n checkForUpdate,\n fetchChecksums,\n updateViaNpm,\n updateViaBrew,\n updateBinaryInPlace,\n getPlatformAsset,\n getCurrentBinaryPath,\n} from \"../updater.js\";\nimport { createSpinner } from \"@gpc-cli/core\";\n\nexport function registerUpdateCommand(program: Command): void {\n program\n .command(\"update\")\n .description(\"Update gpc to the latest version\")\n .option(\"--check\", \"Check for updates without installing (exits 0 always)\")\n .option(\"--force\", \"Update even if already on the latest version\")\n .action(async (opts: { check?: boolean; force?: boolean }, cmd) => {\n const parentOpts = (cmd.parent?.opts() ?? {}) as Record<string, unknown>;\n const jsonMode = !!(parentOpts[\"json\"] || parentOpts[\"output\"] === \"json\");\n const currentVersion = process.env[\"__GPC_VERSION\"] ?? \"0.0.0\";\n\n // Dev build guard\n if (currentVersion === \"0.0.0\") {\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: false,\n reason: \"Cannot update a development build\",\n current: currentVersion,\n }),\n );\n } else {\n console.log(\"Cannot update a development build (version: 0.0.0).\");\n }\n return;\n }\n\n const spinner = createSpinner(\"Checking for updates...\");\n spinner.start();\n\n let result;\n try {\n result = await checkForUpdate(currentVersion);\n } catch (err) {\n spinner.fail(\"Failed to check for updates\");\n throw err;\n }\n\n // --check mode: always exit 0, communicate via output\n if (opts.check) {\n spinner.stop();\n if (jsonMode) {\n console.log(\n JSON.stringify({\n current: result.current,\n latest: result.latest,\n updateAvailable: result.updateAvailable,\n installMethod: result.installMethod,\n releaseUrl: result.release.html_url,\n }),\n );\n } else if (result.updateAvailable) {\n console.log(`Update available: ${result.current} → ${result.latest}`);\n console.log(`Install method: ${result.installMethod}`);\n console.log(`Release: ${result.release.html_url}`);\n console.log(`\\nRun: gpc update`);\n } else {\n console.log(`Already on latest version: v${result.current}`);\n }\n return;\n }\n\n // Already up to date\n if (!result.updateAvailable && !opts.force) {\n spinner.stop(`Already on latest version: v${result.current}`);\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n current: result.current,\n latest: result.latest,\n updated: false,\n }),\n );\n }\n return;\n }\n\n spinner.update(\n `Updating v${result.current} → v${result.latest} (${result.installMethod})...`,\n );\n\n switch (result.installMethod) {\n case \"npm\":\n spinner.stop();\n await updateViaNpm({ silent: jsonMode });\n break;\n\n case \"homebrew\":\n spinner.stop();\n await updateViaBrew({ silent: jsonMode });\n break;\n\n case \"binary\": {\n const assetName = getPlatformAsset();\n if (!assetName) {\n spinner.fail();\n console.error(\n `Error: Unsupported platform: ${process.platform}/${process.arch}`,\n );\n console.error(\n `Download manually: ${result.release.html_url}`,\n );\n process.exit(1);\n }\n\n const assetObj = result.release.assets.find((a) => a.name === assetName);\n if (!assetObj) {\n spinner.fail();\n console.error(\n `Error: No binary found for ${assetName} in release ${result.latestTag}`,\n );\n console.error(`Check: ${result.release.html_url}`);\n process.exit(1);\n }\n\n const sizeMB = (assetObj.size / (1024 * 1024)).toFixed(1);\n spinner.stop();\n\n const checksums = await fetchChecksums(result.release);\n const expectedHash = checksums.get(assetName) ?? \"\";\n const binaryPath = getCurrentBinaryPath();\n\n if (jsonMode) {\n await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath);\n } else {\n // Show live download progress on a single overwriting line\n const label = `Downloading ${assetName} (${sizeMB} MB)`;\n process.stdout.write(`${label}...\\n`);\n let lastPct = -1;\n await updateBinaryInPlace(assetObj.browser_download_url, expectedHash, binaryPath, {\n onProgress(downloaded, total) {\n if (total <= 0) return;\n const pct = Math.min(100, Math.round((downloaded / total) * 100));\n if (pct === lastPct) return; // avoid redundant writes\n lastPct = pct;\n const dlMB = (downloaded / (1024 * 1024)).toFixed(1);\n process.stdout.write(\n `\\r${label} ${dlMB} / ${sizeMB} MB (${String(pct).padStart(3)}%) `,\n );\n },\n });\n process.stdout.write(\"\\n\");\n }\n break;\n }\n\n case \"unknown\":\n spinner.fail();\n console.error(\"Error: Could not detect install method. Update manually:\");\n console.error(` npm: npm install -g @gpc-cli/cli@latest`);\n console.error(` Homebrew: brew upgrade yasserstudio/tap/gpc`);\n console.error(` Binary: https://github.com/yasserstudio/gpc/releases/latest`);\n process.exit(1);\n }\n\n if (jsonMode) {\n console.log(\n JSON.stringify({\n success: true,\n previous: result.current,\n current: result.latest,\n method: result.installMethod,\n }),\n );\n } else {\n console.log(`\\n✔ Updated to v${result.latest}`);\n }\n });\n}\n"],"mappings":"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","names":[]}
|
package/dist/users-JASXONRY.js
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/vitals-KSNAVN5F.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gpc-cli/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.31",
|
|
4
4
|
"description": "The complete Google Play CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,13 +17,22 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"dev": "tsup --watch",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"lint": "eslint src/",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"clean": "rm -rf dist"
|
|
28
|
+
},
|
|
20
29
|
"dependencies": {
|
|
21
|
-
"
|
|
22
|
-
"@gpc-cli/
|
|
23
|
-
"@gpc-cli/
|
|
24
|
-
"@gpc-cli/
|
|
25
|
-
"@gpc-cli/plugin-sdk": "
|
|
26
|
-
"
|
|
30
|
+
"@gpc-cli/api": "workspace:*",
|
|
31
|
+
"@gpc-cli/auth": "workspace:^",
|
|
32
|
+
"@gpc-cli/config": "workspace:*",
|
|
33
|
+
"@gpc-cli/core": "workspace:*",
|
|
34
|
+
"@gpc-cli/plugin-sdk": "workspace:*",
|
|
35
|
+
"commander": "^14.0.3"
|
|
27
36
|
},
|
|
28
37
|
"keywords": [
|
|
29
38
|
"google-play",
|
|
@@ -41,14 +50,5 @@
|
|
|
41
50
|
},
|
|
42
51
|
"devDependencies": {
|
|
43
52
|
"@types/node": "^25.3.5"
|
|
44
|
-
},
|
|
45
|
-
"scripts": {
|
|
46
|
-
"build": "tsup",
|
|
47
|
-
"dev": "tsup --watch",
|
|
48
|
-
"test": "vitest run",
|
|
49
|
-
"test:watch": "vitest",
|
|
50
|
-
"lint": "eslint src/",
|
|
51
|
-
"typecheck": "tsc --noEmit",
|
|
52
|
-
"clean": "rm -rf dist"
|
|
53
53
|
}
|
|
54
|
-
}
|
|
54
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 GPC Contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -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(\"The complete Google Play CLI\")\n .version(process.env[\"__GPC_VERSION\"] || \"0.0.0\", \"-V, --version\")\n .option(\"-o, --output <format>\", \"Output format: table, json, yaml, markdown, 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 .showSuggestionAfterError(true);\n\n const commandLoaders: Record<string, () => Promise<void>> = {\n auth: async () => {\n (await import(\"./commands/auth.js\")).registerAuthCommands(program);\n },\n config: async () => {\n (await import(\"./commands/config.js\")).registerConfigCommands(program);\n },\n doctor: async () => {\n (await import(\"./commands/doctor.js\")).registerDoctorCommand(program);\n },\n docs: async () => {\n (await import(\"./commands/docs.js\")).registerDocsCommand(program);\n },\n completion: async () => {\n (await import(\"./commands/completion.js\")).registerCompletionCommand(program);\n },\n apps: async () => {\n (await import(\"./commands/apps.js\")).registerAppsCommands(program);\n },\n releases: async () => {\n (await import(\"./commands/releases.js\")).registerReleasesCommands(program);\n },\n tracks: async () => {\n (await import(\"./commands/tracks.js\")).registerTracksCommands(program);\n },\n status: async () => {\n (await import(\"./commands/status.js\")).registerStatusCommand(program);\n },\n listings: async () => {\n (await import(\"./commands/listings.js\")).registerListingsCommands(program);\n },\n reviews: async () => {\n (await import(\"./commands/reviews.js\")).registerReviewsCommands(program);\n },\n vitals: async () => {\n (await import(\"./commands/vitals.js\")).registerVitalsCommands(program);\n },\n subscriptions: async () => {\n (await import(\"./commands/subscriptions.js\")).registerSubscriptionsCommands(program);\n },\n iap: async () => {\n (await import(\"./commands/iap.js\")).registerIapCommands(program);\n },\n purchases: async () => {\n (await import(\"./commands/purchases.js\")).registerPurchasesCommands(program);\n },\n pricing: async () => {\n (await import(\"./commands/pricing.js\")).registerPricingCommands(program);\n },\n reports: async () => {\n (await import(\"./commands/reports.js\")).registerReportsCommands(program);\n },\n users: async () => {\n (await import(\"./commands/users.js\")).registerUsersCommands(program);\n },\n testers: async () => {\n (await import(\"./commands/testers.js\")).registerTestersCommands(program);\n },\n validate: async () => {\n (await import(\"./commands/validate.js\")).registerValidateCommand(program);\n },\n publish: async () => {\n (await import(\"./commands/publish.js\")).registerPublishCommand(program);\n },\n 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 \"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 \"install-skills\": async () => {\n (await import(\"./commands/install-skills.js\")).registerInstallSkillsCommand(program);\n },\n plugins: async () => {\n registerPluginsCommand(program, pluginManager);\n },\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\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}\n\nfunction isTypedError(error: unknown): error is Error & TypedError {\n return error instanceof Error && \"code\" in error && typeof (error as TypedError).code === \"string\";\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 if (isTypedError(error)) {\n console.error(`Error [${error.code}]: ${error.message}`);\n if (error.suggestion) {\n console.error(`Suggestion: ${error.suggestion}`);\n }\n return error.exitCode ?? 1;\n }\n\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${message}`);\n return 1;\n}\n"],"mappings":"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","names":["loader"]}
|