@gpc-cli/core 0.9.52 → 0.9.53
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/index.d.ts +47 -3
- package/dist/index.js +261 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -1323,15 +1323,43 @@ declare function renderJson(g: GeneratedChangelog): string;
|
|
|
1323
1323
|
|
|
1324
1324
|
declare function renderPrompt(g: GeneratedChangelog): string;
|
|
1325
1325
|
|
|
1326
|
+
type Provider = "anthropic" | "openai" | "google";
|
|
1327
|
+
type TranslationPath = "gateway" | "direct";
|
|
1328
|
+
type ErrorReason = "rate_limited" | "auth" | "safety_blocked" | "timeout" | "network" | "no_source" | "unknown";
|
|
1329
|
+
interface TranslationResult {
|
|
1330
|
+
text: string;
|
|
1331
|
+
tokensIn: number;
|
|
1332
|
+
tokensOut: number;
|
|
1333
|
+
}
|
|
1334
|
+
type Translator = (locale: string, sourceText: string) => Promise<TranslationResult>;
|
|
1335
|
+
interface TranslatorConfig {
|
|
1336
|
+
path: TranslationPath;
|
|
1337
|
+
provider: Provider;
|
|
1338
|
+
model: string;
|
|
1339
|
+
runId: string;
|
|
1340
|
+
}
|
|
1341
|
+
interface ResolveAiConfigOptions {
|
|
1342
|
+
provider?: string;
|
|
1343
|
+
model?: string;
|
|
1344
|
+
env?: NodeJS.ProcessEnv;
|
|
1345
|
+
}
|
|
1346
|
+
declare const PROVIDER_WHITELIST: readonly Provider[];
|
|
1347
|
+
declare const DEFAULT_MODELS: Record<Provider, string>;
|
|
1348
|
+
declare function resolveAiConfig(opts?: ResolveAiConfigOptions): TranslatorConfig;
|
|
1349
|
+
declare function classifyError(err: unknown): ErrorReason;
|
|
1350
|
+
declare function createTranslator(config: TranslatorConfig): Promise<Translator>;
|
|
1351
|
+
declare function fetchAggregateCost(runId: string): Promise<number | undefined>;
|
|
1352
|
+
declare function formatPathLabel(config: TranslatorConfig): string;
|
|
1353
|
+
|
|
1326
1354
|
declare const PLAY_STORE_LIMIT = 500;
|
|
1327
|
-
declare const PLACEHOLDER_TEXT = "[needs translation \u2014 pass --ai
|
|
1355
|
+
declare const PLACEHOLDER_TEXT = "[needs translation \u2014 pass --ai, or paste the prompt emitted by --format prompt]";
|
|
1328
1356
|
type PlayStoreFormat = "md" | "json" | "prompt";
|
|
1329
1357
|
interface LocaleEntry {
|
|
1330
1358
|
language: string;
|
|
1331
1359
|
text: string;
|
|
1332
1360
|
chars: number;
|
|
1333
1361
|
limit: number;
|
|
1334
|
-
status: "ok" | "over" | "placeholder" | "empty";
|
|
1362
|
+
status: "ok" | "over" | "placeholder" | "empty" | "failed";
|
|
1335
1363
|
}
|
|
1336
1364
|
interface LocaleBundle {
|
|
1337
1365
|
from: string;
|
|
@@ -1354,6 +1382,22 @@ declare function renderPlayStore(g: GeneratedChangelog, opts: PlayStoreRenderOpt
|
|
|
1354
1382
|
output: string;
|
|
1355
1383
|
bundle: LocaleBundle;
|
|
1356
1384
|
};
|
|
1385
|
+
interface TranslationFailure {
|
|
1386
|
+
language: string;
|
|
1387
|
+
reason: ErrorReason;
|
|
1388
|
+
}
|
|
1389
|
+
interface TranslateBundleOptions {
|
|
1390
|
+
translator: Translator;
|
|
1391
|
+
strict?: boolean;
|
|
1392
|
+
onError?: (failure: TranslationFailure, err: unknown) => void;
|
|
1393
|
+
onTranslated?: (entry: LocaleEntry) => void;
|
|
1394
|
+
}
|
|
1395
|
+
interface TranslatedBundle extends LocaleBundle {
|
|
1396
|
+
tokensIn: number;
|
|
1397
|
+
tokensOut: number;
|
|
1398
|
+
failures: TranslationFailure[];
|
|
1399
|
+
}
|
|
1400
|
+
declare function translateBundle(bundle: LocaleBundle, options: TranslateBundleOptions): Promise<TranslatedBundle>;
|
|
1357
1401
|
|
|
1358
1402
|
type Renderer = (g: GeneratedChangelog) => string;
|
|
1359
1403
|
declare const RENDERERS: Record<OutputMode, Renderer>;
|
|
@@ -1409,4 +1453,4 @@ declare function decodeNotification(base64Payload: string): DecodedNotification;
|
|
|
1409
1453
|
*/
|
|
1410
1454
|
declare function formatNotification(notification: DecodedNotification): Record<string, unknown>;
|
|
1411
1455
|
|
|
1412
|
-
export { ApiError, type AppInfo, type AppStatus, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type ChangelogEntry, type CommandContext, type CommitCluster, ConfigError, type CreateEnterpriseAppParams, DEFAULT_LIMITS, DEFAULT_PREFLIGHT_CONFIG, type DecodedNotification, type DiffToken, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GenerateOptions, type GeneratedChangelog, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, type GitRunner, GpcError, type ImageValidationResult, type InitOptions, type InitResult, type InternalSharingUploadResult, type ListIapOptions, type ListSubscriptionsOptions, type ListUsersOptions, type ListVoidedOptions, type ListingDiff, type ListingFieldLimits, type ListingLintResult, type ListingsResult, type LoadedPlugin, type LocaleBundle, type LocaleEntry, type MigrationResult, NetworkError, type OneTimeProductDiff, type OutputMode, PERMISSION_PROPAGATION_WARNING, PLACEHOLDER_TEXT, PLAY_STORE_LIMIT, type ParsedCommit, type ParsedManifest, type ParsedMonth, type PlayStoreFormat, type PlayStoreRenderOptions, PluginManager, type PreflightConfig, type PreflightFinding, type PreflightOptions, type PreflightResult, type PreflightScanner, type PublishOptions, type PublishResult, type PushResult, type QuotaUsage, RENDERERS, type RawCommit, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type Renderer, type ResolveLocalesOptions, type ReviewAnalysis, type ReviewExportOptions, type ReviewsFilterOptions, type RtdnStatus, SECTION_ORDER, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, SEVERITY_ORDER, type ScaffoldOptions, type ScaffoldResult, type Spinner, type StatusDiff, type StatusRelease, type StatusReviews, type StatusVitalMetric, type SubscriptionAnalytics, type SubscriptionDiff, type SyncResult, type ThresholdResult, type TrainConfig, type TrainState, type UploadResult, type ValidateCheck, type ValidateOptions, type ValidateResult, type VersionVitalsComparison, type VersionVitalsRow, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WatchOptions, type WatchVitalsOptions, type WebhookPayload, abortTrain, acknowledgeProductPurchase, activateBasePlan, activateOffer, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, batchGetOrders, batchSyncInAppProducts, buildLocaleBundle, cancelRecoveryAction, cancelSubscriptionPurchase, cancelSubscriptionV2, checkBundleSize, checkThreshold, clearAuditLog, compareBundles, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createRecoveryAction, createSpinner, createSubscription, createTrack, deactivateBasePlan, deactivateOffer, decodeNotification, defaultGitRunner, deferSubscriptionPurchase, deferSubscriptionV2, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportImages, exportReviews, fetchChangelog, fetchReleaseNotes, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatNotification, formatOutput, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateChangelog, generateMigrationPlan, generateNotesFromGit, getAllScannerNames, getAppInfo, getAppStatus, getCountryAvailability, getDeviceTier, getExternalTransaction, getInAppProduct, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getOrderDetails, getProductPurchase, getProductPurchaseV2, getQuotaUsage, getReleasesStatus, getReview, getRtdnStatus, getSubscription, getSubscriptionAnalytics, getSubscriptionPurchase, getTrainStatus, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsErrorCount, getVitalsLmk, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, lintListing, lintListings, lintLocalListings, listAchievements, listAuditEvents, listDeviceTiers, listEvents, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, parseAppfile, parseCommit, parseFastfile, parseGrantArg, parseMonth, parseRemoteUrl, pauseTrain, promoteRelease, publish, publishEnterpriseApp, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, relativeTime, removeTesters, removeUser, renderJson, renderMarkdown, renderPlayStore, renderPlayStoreJson, renderPlayStoreMd, renderPlayStorePrompt, renderPrompt, replyToReview, resolveLocales, revokeSubscriptionPurchase, runPreflight, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, sortResults, startTrain, statusHasBreach, syncInAppProducts, topFiles, trackBreachState, updateAppDetails, updateDataSafety, updateGrant, updateInAppProduct, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateImage, validateLanguageCode, validatePackageName, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, watchVitalsWithAutoHalt, wordDiff, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
|
1456
|
+
export { ApiError, type AppInfo, type AppStatus, type AuditEntry, type BatchSyncResult, type BundleAnalysis, type BundleComparison, type BundleEntry, type BundleSizeCheckResult, type BundleSizeConfig, type ChangelogEntry, type CommandContext, type CommitCluster, ConfigError, type CreateEnterpriseAppParams, DEFAULT_LIMITS, DEFAULT_MODELS, DEFAULT_PREFLIGHT_CONFIG, type DecodedNotification, type DiffToken, type DiscoverPluginsOptions, type DryRunPublishResult, type DryRunResult, type DryRunUploadResult, type ErrorReason, type ExportImagesOptions, type ExportImagesSummary, type FastlaneDetection, type FastlaneLane, type FetchChangelogOptions, type FieldLintResult, type FileValidationResult, type FindingSeverity, GOOGLE_PLAY_LANGUAGES, type GenerateOptions, type GeneratedChangelog, type GetAppStatusOptions, type GitNotesOptions, type GitReleaseNotes, type GitRunner, GpcError, type ImageValidationResult, type InitOptions, type InitResult, type InternalSharingUploadResult, type ListIapOptions, type ListSubscriptionsOptions, type ListUsersOptions, type ListVoidedOptions, type ListingDiff, type ListingFieldLimits, type ListingLintResult, type ListingsResult, type LoadedPlugin, type LocaleBundle, type LocaleEntry, type MigrationResult, NetworkError, type OneTimeProductDiff, type OutputMode, PERMISSION_PROPAGATION_WARNING, PLACEHOLDER_TEXT, PLAY_STORE_LIMIT, PROVIDER_WHITELIST, type ParsedCommit, type ParsedManifest, type ParsedMonth, type PlayStoreFormat, type PlayStoreRenderOptions, PluginManager, type PreflightConfig, type PreflightFinding, type PreflightOptions, type PreflightResult, type PreflightScanner, type Provider, type PublishOptions, type PublishResult, type PushResult, type QuotaUsage, RENDERERS, type RawCommit, type ReleaseDiff, type ReleaseNotesValidation, type ReleaseStatusResult, type Renderer, type ResolveAiConfigOptions, type ResolveLocalesOptions, type ReviewAnalysis, type ReviewExportOptions, type ReviewsFilterOptions, type RtdnStatus, SECTION_ORDER, SENSITIVE_ARG_KEYS, SENSITIVE_KEYS, SEVERITY_ORDER, type ScaffoldOptions, type ScaffoldResult, type Spinner, type StatusDiff, type StatusRelease, type StatusReviews, type StatusVitalMetric, type SubscriptionAnalytics, type SubscriptionDiff, type SyncResult, type ThresholdResult, type TrainConfig, type TrainState, type TranslateBundleOptions, type TranslatedBundle, type TranslationFailure, type TranslationPath, type TranslationResult, type Translator, type TranslatorConfig, type UploadResult, type ValidateCheck, type ValidateOptions, type ValidateResult, type VersionVitalsComparison, type VersionVitalsRow, type VitalsOverview, type VitalsQueryOptions, type VitalsTrendComparison, type WatchOptions, type WatchVitalsOptions, type WebhookPayload, abortTrain, acknowledgeProductPurchase, activateBasePlan, activateOffer, addRecoveryTargeting, addTesters, advanceTrain, analyzeBundle, analyzeRemoteListings, analyzeReviews, batchGetOrders, batchSyncInAppProducts, buildLocaleBundle, cancelRecoveryAction, cancelSubscriptionPurchase, cancelSubscriptionV2, checkBundleSize, checkThreshold, classifyError, clearAuditLog, compareBundles, compareVersionVitals, compareVitalsTrend, computeStatusDiff, consumeProductPurchase, convertRegionPrices, createAuditEntry, createDeviceTier, createEnterpriseApp, createExternalTransaction, createGrant, createInAppProduct, createOffer, createOneTimeOffer, createOneTimeProduct, createRecoveryAction, createSpinner, createSubscription, createTrack, createTranslator, deactivateBasePlan, deactivateOffer, decodeNotification, defaultGitRunner, deferSubscriptionPurchase, deferSubscriptionV2, deleteBasePlan, deleteGrant, deleteImage, deleteInAppProduct, deleteListing, deleteOffer, deleteOneTimeOffer, deleteOneTimeProduct, deleteSubscription, deployRecoveryAction, detectFastlane, detectOutputFormat, diffListings, diffListingsCommand, diffListingsEnhanced, diffOneTimeProduct, diffReleases, diffSubscription, discoverPlugins, downloadGeneratedApk, downloadReport, exportImages, exportReviews, fetchAggregateCost, fetchChangelog, fetchReleaseNotes, formatChangelogEntry, formatCustomPayload, formatDiscordPayload, formatJunit, formatNotification, formatOutput, formatPathLabel, formatSlackPayload, formatStatusDiff, formatStatusSummary, formatStatusTable, formatWordDiff, generateChangelog, generateMigrationPlan, generateNotesFromGit, getAllScannerNames, getAppInfo, getAppStatus, getCountryAvailability, getDeviceTier, getExternalTransaction, getInAppProduct, getListings, getOffer, getOneTimeOffer, getOneTimeProduct, getOrderDetails, getProductPurchase, getProductPurchaseV2, getQuotaUsage, getReleasesStatus, getReview, getRtdnStatus, getSubscription, getSubscriptionAnalytics, getSubscriptionPurchase, getTrainStatus, getUser, getVitalsAnomalies, getVitalsAnr, getVitalsBattery, getVitalsCrashes, getVitalsErrorCount, getVitalsLmk, getVitalsMemory, getVitalsOverview, getVitalsRendering, getVitalsStartup, importDataSafety, importTestersFromCsv, initAudit, initProject, inviteUser, isFinancialReportType, isStatsReportType, isValidBcp47, isValidReportType, isValidStatsDimension, lintListing, lintListings, lintLocalListings, listAchievements, listAuditEvents, listDeviceTiers, listEvents, listGeneratedApks, listGrants, listImages, listInAppProducts, listLeaderboards, listOffers, listOneTimeOffers, listOneTimeProducts, listRecoveryActions, listReports, listReviews, listSubscriptions, listTesters, listTracks, listUsers, listVoidedPurchases, loadPreflightConfig, loadStatusCache, maybePaginate, migratePrices, parseAppfile, parseCommit, parseFastfile, parseGrantArg, parseMonth, parseRemoteUrl, pauseTrain, promoteRelease, publish, publishEnterpriseApp, pullListings, pushListings, readListingsFromDir, readReleaseNotesFromDir, redactAuditArgs, redactSensitive, refundExternalTransaction, refundOrder, relativeTime, removeTesters, removeUser, renderJson, renderMarkdown, renderPlayStore, renderPlayStoreJson, renderPlayStoreMd, renderPlayStorePrompt, renderPrompt, replyToReview, resolveAiConfig, resolveLocales, revokeSubscriptionPurchase, runPreflight, runWatchLoop, safePath, safePathWithin, saveStatusCache, scaffoldPlugin, searchAuditEvents, searchVitalsErrors, sendNotification, sendWebhook, sortResults, startTrain, statusHasBreach, syncInAppProducts, topFiles, trackBreachState, translateBundle, updateAppDetails, updateDataSafety, updateGrant, updateInAppProduct, updateListing, updateOffer, updateOneTimeOffer, updateOneTimeProduct, updateRollout, updateSubscription, updateTrackConfig, updateUser, uploadExternallyHosted, uploadImage, uploadInternalSharing, uploadRelease, validateImage, validateLanguageCode, validatePackageName, validatePreSubmission, validateReleaseNotes, validateSku, validateTrackName, validateUploadFile, validateVersionCode, watchVitalsWithAutoHalt, wordDiff, writeAuditLog, writeListingsToDir, writeMigrationOutput };
|
package/dist/index.js
CHANGED
|
@@ -7881,9 +7881,179 @@ function renderPrompt(g) {
|
|
|
7881
7881
|
return lines.join("\n");
|
|
7882
7882
|
}
|
|
7883
7883
|
|
|
7884
|
+
// src/commands/changelog-ai.ts
|
|
7885
|
+
import { randomUUID } from "crypto";
|
|
7886
|
+
var PROVIDER_WHITELIST = ["anthropic", "openai", "google"];
|
|
7887
|
+
var DEFAULT_MODELS = {
|
|
7888
|
+
anthropic: "claude-sonnet-4-6",
|
|
7889
|
+
openai: "gpt-4o-mini",
|
|
7890
|
+
google: "gemini-2.5-flash"
|
|
7891
|
+
};
|
|
7892
|
+
function resolveAiConfig(opts = {}) {
|
|
7893
|
+
const env = opts.env ?? process.env;
|
|
7894
|
+
const hasGateway = typeof env["AI_GATEWAY_API_KEY"] === "string" && env["AI_GATEWAY_API_KEY"].length > 0;
|
|
7895
|
+
let provider;
|
|
7896
|
+
if (opts.provider) {
|
|
7897
|
+
const normalized = opts.provider.toLowerCase();
|
|
7898
|
+
if (!PROVIDER_WHITELIST.includes(normalized)) {
|
|
7899
|
+
throw new GpcError(
|
|
7900
|
+
`Unknown --provider "${opts.provider}"`,
|
|
7901
|
+
"CHANGELOG_AI_UNKNOWN_PROVIDER",
|
|
7902
|
+
2,
|
|
7903
|
+
`Valid providers: ${PROVIDER_WHITELIST.join(", ")}`
|
|
7904
|
+
);
|
|
7905
|
+
}
|
|
7906
|
+
provider = normalized;
|
|
7907
|
+
} else if (hasGateway || env["ANTHROPIC_API_KEY"]) {
|
|
7908
|
+
provider = "anthropic";
|
|
7909
|
+
} else if (env["OPENAI_API_KEY"]) {
|
|
7910
|
+
provider = "openai";
|
|
7911
|
+
} else if (env["GOOGLE_GENERATIVE_AI_API_KEY"]) {
|
|
7912
|
+
provider = "google";
|
|
7913
|
+
} else {
|
|
7914
|
+
throw new GpcError(
|
|
7915
|
+
"No AI provider credentials found in env",
|
|
7916
|
+
"CHANGELOG_AI_NO_CREDENTIALS",
|
|
7917
|
+
3,
|
|
7918
|
+
"Set one of: AI_GATEWAY_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY."
|
|
7919
|
+
);
|
|
7920
|
+
}
|
|
7921
|
+
const model = opts.model ?? DEFAULT_MODELS[provider];
|
|
7922
|
+
const path = hasGateway ? "gateway" : "direct";
|
|
7923
|
+
const runId = randomUUID();
|
|
7924
|
+
return { path, provider, model, runId };
|
|
7925
|
+
}
|
|
7926
|
+
function classifyError(err) {
|
|
7927
|
+
if (!err || typeof err !== "object") return "unknown";
|
|
7928
|
+
const e = err;
|
|
7929
|
+
const name = typeof e["name"] === "string" ? e["name"] : "";
|
|
7930
|
+
const statusCode = typeof e["statusCode"] === "number" ? e["statusCode"] : typeof e["status"] === "number" ? e["status"] : 0;
|
|
7931
|
+
const message = typeof e["message"] === "string" ? e["message"].toLowerCase() : "";
|
|
7932
|
+
const finishReason = typeof e["finishReason"] === "string" ? e["finishReason"] : "";
|
|
7933
|
+
if (name === "RateLimitError" || statusCode === 429 || statusCode === 529) return "rate_limited";
|
|
7934
|
+
if (statusCode === 401 || statusCode === 403) return "auth";
|
|
7935
|
+
if (message.includes("api key invalid") || message.includes("invalid api key")) return "auth";
|
|
7936
|
+
if (finishReason === "SAFETY") return "safety_blocked";
|
|
7937
|
+
if (statusCode === 400 && (message.includes("content_policy") || message.includes("content policy") || message.includes("safety"))) {
|
|
7938
|
+
return "safety_blocked";
|
|
7939
|
+
}
|
|
7940
|
+
if (name === "AbortError" || name === "TimeoutError") return "timeout";
|
|
7941
|
+
if (message.includes("timeout") || message.includes("timed out")) return "timeout";
|
|
7942
|
+
if (message.includes("econnrefused") || message.includes("enotfound") || message.includes("etimedout") || message.includes("network") || name === "TypeError" && message.includes("fetch")) {
|
|
7943
|
+
return "network";
|
|
7944
|
+
}
|
|
7945
|
+
return "unknown";
|
|
7946
|
+
}
|
|
7947
|
+
function buildSystemPrompt() {
|
|
7948
|
+
return [
|
|
7949
|
+
`You translate Play Store "What's new" release notes for Android apps.`,
|
|
7950
|
+
"Rules:",
|
|
7951
|
+
"- Translation MUST be at most 500 Unicode code points.",
|
|
7952
|
+
'- Preserve bullet format (one item per line, starts with "- ").',
|
|
7953
|
+
"- User-facing tone. Avoid internal jargon.",
|
|
7954
|
+
'- Do not translate technical names (package names, CLI flags, "GPC").',
|
|
7955
|
+
"- Drop the conventional-commit prefix (feat:/fix:/docs:) if it feels unnatural in the target language.",
|
|
7956
|
+
"Respond with the translated text only. No explanations, no markdown headings."
|
|
7957
|
+
].join("\n");
|
|
7958
|
+
}
|
|
7959
|
+
function buildUserPrompt(locale, sourceText) {
|
|
7960
|
+
return `Translate the following release notes into ${locale}:
|
|
7961
|
+
|
|
7962
|
+
${sourceText}`;
|
|
7963
|
+
}
|
|
7964
|
+
function providerSpecificOptions(provider) {
|
|
7965
|
+
if (provider === "google") {
|
|
7966
|
+
return { google: { thinkingConfig: { thinkingBudget: 0 } } };
|
|
7967
|
+
}
|
|
7968
|
+
return {};
|
|
7969
|
+
}
|
|
7970
|
+
function readUsage(usage) {
|
|
7971
|
+
if (!usage || typeof usage !== "object") return { tokensIn: 0, tokensOut: 0 };
|
|
7972
|
+
const u = usage;
|
|
7973
|
+
const tokensIn = typeof u["inputTokens"] === "number" ? u["inputTokens"] : typeof u["promptTokens"] === "number" ? u["promptTokens"] : 0;
|
|
7974
|
+
const tokensOut = typeof u["outputTokens"] === "number" ? u["outputTokens"] : typeof u["completionTokens"] === "number" ? u["completionTokens"] : 0;
|
|
7975
|
+
return { tokensIn, tokensOut };
|
|
7976
|
+
}
|
|
7977
|
+
async function createTranslator(config) {
|
|
7978
|
+
const ai = await import("ai");
|
|
7979
|
+
const generateText = ai.generateText;
|
|
7980
|
+
if (config.path === "gateway") {
|
|
7981
|
+
const modelString = `${config.provider}/${config.model}`;
|
|
7982
|
+
return async (locale, sourceText) => {
|
|
7983
|
+
const result = await generateText({
|
|
7984
|
+
model: ai.gateway(modelString),
|
|
7985
|
+
system: buildSystemPrompt(),
|
|
7986
|
+
prompt: buildUserPrompt(locale, sourceText),
|
|
7987
|
+
temperature: 0.2,
|
|
7988
|
+
providerOptions: {
|
|
7989
|
+
gateway: { tags: [`gpc-changelog-${config.runId}`] },
|
|
7990
|
+
...providerSpecificOptions(config.provider)
|
|
7991
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7992
|
+
}
|
|
7993
|
+
});
|
|
7994
|
+
const { tokensIn, tokensOut } = readUsage(result.usage);
|
|
7995
|
+
return { text: result.text, tokensIn, tokensOut };
|
|
7996
|
+
};
|
|
7997
|
+
}
|
|
7998
|
+
let modelFactory;
|
|
7999
|
+
if (config.provider === "anthropic") {
|
|
8000
|
+
const mod = await import("@ai-sdk/anthropic");
|
|
8001
|
+
modelFactory = (id) => mod.anthropic(id);
|
|
8002
|
+
} else if (config.provider === "openai") {
|
|
8003
|
+
const mod = await import("@ai-sdk/openai");
|
|
8004
|
+
modelFactory = (id) => mod.openai(id);
|
|
8005
|
+
} else {
|
|
8006
|
+
const mod = await import("@ai-sdk/google");
|
|
8007
|
+
modelFactory = (id) => mod.google(id);
|
|
8008
|
+
}
|
|
8009
|
+
return async (locale, sourceText) => {
|
|
8010
|
+
const result = await generateText({
|
|
8011
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8012
|
+
model: modelFactory(config.model),
|
|
8013
|
+
system: buildSystemPrompt(),
|
|
8014
|
+
prompt: buildUserPrompt(locale, sourceText),
|
|
8015
|
+
temperature: 0.2,
|
|
8016
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8017
|
+
providerOptions: providerSpecificOptions(config.provider)
|
|
8018
|
+
});
|
|
8019
|
+
const { tokensIn, tokensOut } = readUsage(result.usage);
|
|
8020
|
+
return { text: result.text, tokensIn, tokensOut };
|
|
8021
|
+
};
|
|
8022
|
+
}
|
|
8023
|
+
async function fetchAggregateCost(runId) {
|
|
8024
|
+
try {
|
|
8025
|
+
const { gateway } = await import("ai");
|
|
8026
|
+
const now = /* @__PURE__ */ new Date();
|
|
8027
|
+
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
|
|
8028
|
+
const today = now.toISOString().slice(0, 10);
|
|
8029
|
+
const startDate = yesterday.toISOString().slice(0, 10);
|
|
8030
|
+
const report = await gateway.getSpendReport({
|
|
8031
|
+
startDate,
|
|
8032
|
+
endDate: today,
|
|
8033
|
+
groupBy: "tag",
|
|
8034
|
+
tags: [`gpc-changelog-${runId}`]
|
|
8035
|
+
});
|
|
8036
|
+
const results = report.results ?? [];
|
|
8037
|
+
return results.reduce((sum, row) => sum + (row.totalCost ?? 0), 0);
|
|
8038
|
+
} catch {
|
|
8039
|
+
return void 0;
|
|
8040
|
+
}
|
|
8041
|
+
}
|
|
8042
|
+
var PROVIDER_BRAND = {
|
|
8043
|
+
anthropic: "Anthropic",
|
|
8044
|
+
openai: "OpenAI",
|
|
8045
|
+
google: "Google"
|
|
8046
|
+
};
|
|
8047
|
+
function formatPathLabel(config) {
|
|
8048
|
+
if (config.path === "gateway") {
|
|
8049
|
+
return `routing via AI Gateway (${config.provider}/${config.model})`;
|
|
8050
|
+
}
|
|
8051
|
+
return `direct ${PROVIDER_BRAND[config.provider]} SDK (${config.model})`;
|
|
8052
|
+
}
|
|
8053
|
+
|
|
7884
8054
|
// src/commands/changelog-renderers/play-store.ts
|
|
7885
8055
|
var PLAY_STORE_LIMIT = 500;
|
|
7886
|
-
var PLACEHOLDER_TEXT = "[needs translation \u2014 pass --ai
|
|
8056
|
+
var PLACEHOLDER_TEXT = "[needs translation \u2014 pass --ai, or paste the prompt emitted by --format prompt]";
|
|
7887
8057
|
function safeLine2(s) {
|
|
7888
8058
|
return s.replace(/[\r\n]+/g, " ").trim();
|
|
7889
8059
|
}
|
|
@@ -8038,6 +8208,88 @@ function renderPlayStore(g, opts) {
|
|
|
8038
8208
|
return { output: renderPlayStorePrompt(bundle, g), bundle };
|
|
8039
8209
|
}
|
|
8040
8210
|
}
|
|
8211
|
+
async function translateBundle(bundle, options) {
|
|
8212
|
+
const source = bundle.locales.find((e) => e.language === bundle.sourceLanguage);
|
|
8213
|
+
const sourceText = source?.text ?? "";
|
|
8214
|
+
const hasSource = source !== void 0 && sourceText.trim().length > 0;
|
|
8215
|
+
let tokensIn = 0;
|
|
8216
|
+
let tokensOut = 0;
|
|
8217
|
+
const failures = [];
|
|
8218
|
+
const newLocales = [];
|
|
8219
|
+
for (const entry of bundle.locales) {
|
|
8220
|
+
if (entry.status !== "placeholder") {
|
|
8221
|
+
newLocales.push(entry);
|
|
8222
|
+
continue;
|
|
8223
|
+
}
|
|
8224
|
+
if (!hasSource) {
|
|
8225
|
+
const failure = { language: entry.language, reason: "no_source" };
|
|
8226
|
+
failures.push(failure);
|
|
8227
|
+
options.onError?.(failure, new Error("source locale missing or empty"));
|
|
8228
|
+
const failedText = `[translation failed: no_source]`;
|
|
8229
|
+
newLocales.push({
|
|
8230
|
+
language: entry.language,
|
|
8231
|
+
text: failedText,
|
|
8232
|
+
chars: countChars(failedText),
|
|
8233
|
+
limit: PLAY_STORE_LIMIT,
|
|
8234
|
+
status: "failed"
|
|
8235
|
+
});
|
|
8236
|
+
continue;
|
|
8237
|
+
}
|
|
8238
|
+
try {
|
|
8239
|
+
const result = await options.translator(entry.language, sourceText);
|
|
8240
|
+
tokensIn += result.tokensIn;
|
|
8241
|
+
tokensOut += result.tokensOut;
|
|
8242
|
+
let text = result.text.trim();
|
|
8243
|
+
let chars = countChars(text);
|
|
8244
|
+
let status = "ok";
|
|
8245
|
+
if (chars > PLAY_STORE_LIMIT) {
|
|
8246
|
+
text = truncateToLimit(text, PLAY_STORE_LIMIT);
|
|
8247
|
+
chars = countChars(text);
|
|
8248
|
+
status = "over";
|
|
8249
|
+
}
|
|
8250
|
+
const translated2 = {
|
|
8251
|
+
language: entry.language,
|
|
8252
|
+
text,
|
|
8253
|
+
chars,
|
|
8254
|
+
limit: PLAY_STORE_LIMIT,
|
|
8255
|
+
status
|
|
8256
|
+
};
|
|
8257
|
+
newLocales.push(translated2);
|
|
8258
|
+
options.onTranslated?.(translated2);
|
|
8259
|
+
} catch (err) {
|
|
8260
|
+
const reason = classifyError(err);
|
|
8261
|
+
const failure = { language: entry.language, reason };
|
|
8262
|
+
failures.push(failure);
|
|
8263
|
+
options.onError?.(failure, err);
|
|
8264
|
+
const failedText = `[translation failed: ${reason}]`;
|
|
8265
|
+
newLocales.push({
|
|
8266
|
+
language: entry.language,
|
|
8267
|
+
text: failedText,
|
|
8268
|
+
chars: countChars(failedText),
|
|
8269
|
+
limit: PLAY_STORE_LIMIT,
|
|
8270
|
+
status: "failed"
|
|
8271
|
+
});
|
|
8272
|
+
}
|
|
8273
|
+
}
|
|
8274
|
+
const overflows = newLocales.filter((e) => e.status === "over").map((e) => e.language);
|
|
8275
|
+
const translated = {
|
|
8276
|
+
...bundle,
|
|
8277
|
+
locales: newLocales,
|
|
8278
|
+
overflows,
|
|
8279
|
+
tokensIn,
|
|
8280
|
+
tokensOut,
|
|
8281
|
+
failures
|
|
8282
|
+
};
|
|
8283
|
+
if (options.strict && failures.length > 0) {
|
|
8284
|
+
throw new GpcError(
|
|
8285
|
+
`${failures.length} locale${failures.length === 1 ? "" : "s"} failed to translate: ${failures.map((f) => `${f.language}=${f.reason}`).join(", ")}`,
|
|
8286
|
+
"CHANGELOG_AI_TRANSLATION_FAILED",
|
|
8287
|
+
1,
|
|
8288
|
+
"Remove --strict to continue on errors, or check credentials and retry."
|
|
8289
|
+
);
|
|
8290
|
+
}
|
|
8291
|
+
return translated;
|
|
8292
|
+
}
|
|
8041
8293
|
|
|
8042
8294
|
// src/commands/changelog-renderers/index.ts
|
|
8043
8295
|
var RENDERERS = {
|
|
@@ -8204,6 +8456,7 @@ export {
|
|
|
8204
8456
|
ApiError,
|
|
8205
8457
|
ConfigError,
|
|
8206
8458
|
DEFAULT_LIMITS,
|
|
8459
|
+
DEFAULT_MODELS,
|
|
8207
8460
|
DEFAULT_PREFLIGHT_CONFIG,
|
|
8208
8461
|
GOOGLE_PLAY_LANGUAGES,
|
|
8209
8462
|
GpcError,
|
|
@@ -8211,6 +8464,7 @@ export {
|
|
|
8211
8464
|
PERMISSION_PROPAGATION_WARNING,
|
|
8212
8465
|
PLACEHOLDER_TEXT,
|
|
8213
8466
|
PLAY_STORE_LIMIT,
|
|
8467
|
+
PROVIDER_WHITELIST,
|
|
8214
8468
|
PluginManager,
|
|
8215
8469
|
RENDERERS,
|
|
8216
8470
|
SECTION_ORDER,
|
|
@@ -8235,6 +8489,7 @@ export {
|
|
|
8235
8489
|
cancelSubscriptionV2,
|
|
8236
8490
|
checkBundleSize,
|
|
8237
8491
|
checkThreshold,
|
|
8492
|
+
classifyError,
|
|
8238
8493
|
clearAuditLog,
|
|
8239
8494
|
compareBundles,
|
|
8240
8495
|
compareVersionVitals,
|
|
@@ -8255,6 +8510,7 @@ export {
|
|
|
8255
8510
|
createSpinner,
|
|
8256
8511
|
createSubscription,
|
|
8257
8512
|
createTrack,
|
|
8513
|
+
createTranslator,
|
|
8258
8514
|
deactivateBasePlan,
|
|
8259
8515
|
deactivateOffer,
|
|
8260
8516
|
decodeNotification,
|
|
@@ -8284,6 +8540,7 @@ export {
|
|
|
8284
8540
|
downloadReport,
|
|
8285
8541
|
exportImages,
|
|
8286
8542
|
exportReviews,
|
|
8543
|
+
fetchAggregateCost,
|
|
8287
8544
|
fetchChangelog,
|
|
8288
8545
|
fetchReleaseNotes,
|
|
8289
8546
|
formatChangelogEntry,
|
|
@@ -8292,6 +8549,7 @@ export {
|
|
|
8292
8549
|
formatJunit,
|
|
8293
8550
|
formatNotification,
|
|
8294
8551
|
formatOutput,
|
|
8552
|
+
formatPathLabel,
|
|
8295
8553
|
formatSlackPayload,
|
|
8296
8554
|
formatStatusDiff,
|
|
8297
8555
|
formatStatusSummary,
|
|
@@ -8399,6 +8657,7 @@ export {
|
|
|
8399
8657
|
renderPlayStorePrompt,
|
|
8400
8658
|
renderPrompt,
|
|
8401
8659
|
replyToReview,
|
|
8660
|
+
resolveAiConfig,
|
|
8402
8661
|
resolveLocales,
|
|
8403
8662
|
revokeSubscriptionPurchase,
|
|
8404
8663
|
runPreflight,
|
|
@@ -8417,6 +8676,7 @@ export {
|
|
|
8417
8676
|
syncInAppProducts,
|
|
8418
8677
|
topFiles,
|
|
8419
8678
|
trackBreachState,
|
|
8679
|
+
translateBundle,
|
|
8420
8680
|
updateAppDetails,
|
|
8421
8681
|
updateDataSafety,
|
|
8422
8682
|
updateGrant,
|