@gpc-cli/cli 0.9.62 → 0.9.64

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.
Files changed (66) hide show
  1. package/README.md +12 -8
  2. package/dist/{__complete-QFD3SUAO.js → __complete-AZXI2O25.js} +2 -4
  3. package/dist/__complete-AZXI2O25.js.map +1 -0
  4. package/dist/{audit-M7GYID74.js → audit-BDPS5ODN.js} +4 -4
  5. package/dist/bin.js +2 -2
  6. package/dist/changelog-EHQYZP22.js +365 -0
  7. package/dist/changelog-EHQYZP22.js.map +1 -0
  8. package/dist/{chunk-QM5RTQ6R.js → chunk-I3SFXLIY.js} +29 -29
  9. package/dist/{completion-4I3IJK3M.js → completion-ZK7RPPFD.js} +7 -3
  10. package/dist/{completion-4I3IJK3M.js.map → completion-ZK7RPPFD.js.map} +1 -1
  11. package/dist/{config-B76LNM7C.js → config-SK7BOURM.js} +5 -5
  12. package/dist/docs-WVJCDX5X.js +378 -0
  13. package/dist/docs-WVJCDX5X.js.map +1 -0
  14. package/dist/{doctor-6SNZEFME.js → doctor-FSUI44DD.js} +5 -5
  15. package/dist/{enterprise-SIKXDT64.js → enterprise-L7DTIX2O.js} +4 -4
  16. package/dist/{external-transactions-JL3G4IG5.js → external-transactions-BP42CK3H.js} +4 -4
  17. package/dist/{feedback-JRTQBJUP.js → feedback-PDQU5E6S.js} +2 -2
  18. package/dist/generated/docs-bundle.json +1 -0
  19. package/dist/{grants-UHNBPIFD.js → grants-32DED5QL.js} +4 -4
  20. package/dist/{iap-ETOL7OAC.js → iap-EPJ76IAC.js} +4 -4
  21. package/dist/index.js +1 -1
  22. package/dist/{init-6CCSVJC2.js → init-OCBFI4VH.js} +6 -6
  23. package/dist/{listings-2Z6DSO3D.js → listings-QKRIVZG6.js} +6 -6
  24. package/dist/{one-time-products-Y5RNIPV2.js → one-time-products-OIDBVCFE.js} +4 -4
  25. package/dist/{publish-5HZAJEDZ.js → publish-H2IAOKP7.js} +4 -4
  26. package/dist/{purchases-AHWGLW6V.js → purchases-GFLYTKR3.js} +4 -4
  27. package/dist/{recovery-B7DZQ6XG.js → recovery-2VJJLAIQ.js} +4 -4
  28. package/dist/{releases-XY57V22L.js → releases-RTF5NPTD.js} +4 -4
  29. package/dist/{reviews-P4M6BEJI.js → reviews-GZ2VOIRN.js} +4 -4
  30. package/dist/{subscriptions-GTVJB4HX.js → subscriptions-JPHFBREY.js} +4 -4
  31. package/dist/{system-apks-L6M7QYB3.js → system-apks-KWTN5LHO.js} +4 -4
  32. package/dist/{testers-FGLBJAXL.js → testers-7ILUCKYB.js} +4 -4
  33. package/dist/{train-D2NKUW3M.js → train-G44NEK43.js} +4 -4
  34. package/dist/{update-6AGIO5DW.js → update-E4VGHQUR.js} +2 -2
  35. package/dist/{users-FOMAT7DY.js → users-W66YCFDX.js} +4 -4
  36. package/dist/{version-JL66BIVI.js → version-HXUIOHCL.js} +2 -2
  37. package/package.json +5 -3
  38. package/dist/__complete-QFD3SUAO.js.map +0 -1
  39. package/dist/changelog-OHZ4M7D6.js +0 -172
  40. package/dist/changelog-OHZ4M7D6.js.map +0 -1
  41. package/dist/docs-GP6AEX4N.js +0 -115
  42. package/dist/docs-GP6AEX4N.js.map +0 -1
  43. /package/dist/{audit-M7GYID74.js.map → audit-BDPS5ODN.js.map} +0 -0
  44. /package/dist/{chunk-QM5RTQ6R.js.map → chunk-I3SFXLIY.js.map} +0 -0
  45. /package/dist/{config-B76LNM7C.js.map → config-SK7BOURM.js.map} +0 -0
  46. /package/dist/{doctor-6SNZEFME.js.map → doctor-FSUI44DD.js.map} +0 -0
  47. /package/dist/{enterprise-SIKXDT64.js.map → enterprise-L7DTIX2O.js.map} +0 -0
  48. /package/dist/{external-transactions-JL3G4IG5.js.map → external-transactions-BP42CK3H.js.map} +0 -0
  49. /package/dist/{feedback-JRTQBJUP.js.map → feedback-PDQU5E6S.js.map} +0 -0
  50. /package/dist/{grants-UHNBPIFD.js.map → grants-32DED5QL.js.map} +0 -0
  51. /package/dist/{iap-ETOL7OAC.js.map → iap-EPJ76IAC.js.map} +0 -0
  52. /package/dist/{init-6CCSVJC2.js.map → init-OCBFI4VH.js.map} +0 -0
  53. /package/dist/{listings-2Z6DSO3D.js.map → listings-QKRIVZG6.js.map} +0 -0
  54. /package/dist/{one-time-products-Y5RNIPV2.js.map → one-time-products-OIDBVCFE.js.map} +0 -0
  55. /package/dist/{publish-5HZAJEDZ.js.map → publish-H2IAOKP7.js.map} +0 -0
  56. /package/dist/{purchases-AHWGLW6V.js.map → purchases-GFLYTKR3.js.map} +0 -0
  57. /package/dist/{recovery-B7DZQ6XG.js.map → recovery-2VJJLAIQ.js.map} +0 -0
  58. /package/dist/{releases-XY57V22L.js.map → releases-RTF5NPTD.js.map} +0 -0
  59. /package/dist/{reviews-P4M6BEJI.js.map → reviews-GZ2VOIRN.js.map} +0 -0
  60. /package/dist/{subscriptions-GTVJB4HX.js.map → subscriptions-JPHFBREY.js.map} +0 -0
  61. /package/dist/{system-apks-L6M7QYB3.js.map → system-apks-KWTN5LHO.js.map} +0 -0
  62. /package/dist/{testers-FGLBJAXL.js.map → testers-7ILUCKYB.js.map} +0 -0
  63. /package/dist/{train-D2NKUW3M.js.map → train-G44NEK43.js.map} +0 -0
  64. /package/dist/{update-6AGIO5DW.js.map → update-E4VGHQUR.js.map} +0 -0
  65. /package/dist/{users-FOMAT7DY.js.map → users-W66YCFDX.js.map} +0 -0
  66. /package/dist/{version-JL66BIVI.js.map → version-HXUIOHCL.js.map} +0 -0
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Ship Android apps from your terminal.** The complete CLI for the Google Play Developer API.
4
4
 
5
- 217 API endpoints. No Ruby. No browser. No ceremony. First publishing CLI with Managed Google Play support.
5
+ 217 API endpoints. No Ruby. No browser. No ceremony. First publishing CLI with Managed Google Play support and AI-assisted Play Store release notes in 80+ locales.
6
6
 
7
7
  ```bash
8
8
  npm install -g @gpc-cli/cli
@@ -14,11 +14,14 @@ npm install -g @gpc-cli/cli
14
14
  gpc status # Releases + vitals + reviews in 3 seconds
15
15
  gpc releases upload app.aab --track beta # Upload to any track
16
16
  gpc releases promote --from beta --to production --rollout 10
17
+ gpc publish app.aab --track beta --notes "Bug fixes" # One-shot upload + release
17
18
  gpc preflight app.aab # 9 offline policy scanners
18
19
  gpc vitals crashes --threshold 2.0 # Exit code 6 if breached
19
- gpc reviews list --stars 1-2 --since 7d # Filter and reply to reviews
20
- gpc listings push --dir metadata/ # Sync store metadata
21
- gpc enterprise publish app.aab --account 123 --title "Private App" # Managed Google Play (v0.9.56+)
20
+ gpc reviews list --stars 1-2 --since 7d # Filter reviews
21
+ gpc reviews reply <review-id> --text "Thanks for the feedback!"
22
+ gpc listings push --dir metadata/ # Sync store metadata (Fastlane-compatible)
23
+ gpc changelog generate --target play-store --locales auto --ai # AI-translated "What's new" in every locale
24
+ gpc enterprise publish app.aab --account 123 --title "Private App" # Managed Google Play
22
25
  gpc doctor # 20 setup checks
23
26
  ```
24
27
 
@@ -31,9 +34,10 @@ gpc doctor # 20 setup checks
31
34
  | Cold start | <500ms | 2-3s |
32
35
  | Reviews & Vitals | Yes | No |
33
36
  | Subscriptions | Yes | No |
34
- | **Managed Google Play** | **Yes (Play Custom App API)** | No |
35
- | Preflight scanner | 9 offline checks | No |
36
- | CI/CD native | JSON + exit codes | Partial |
37
+ | **Managed Google Play** | **Yes (Play Custom App API)** | No |
38
+ | **AI-translated release notes** | **Yes (80+ locales, BYO key)** | No |
39
+ | Preflight scanner | 9 offline checks | No |
40
+ | CI/CD native | JSON + exit codes | Partial |
37
41
 
38
42
  [Migration guide](https://yasserstudio.github.io/gpc/migration/from-fastlane) with one-to-one command mapping.
39
43
 
@@ -87,7 +91,7 @@ curl -fsSL https://raw.githubusercontent.com/yasserstudio/gpc/main/scripts/insta
87
91
  - [Commands reference](https://yasserstudio.github.io/gpc/commands/)
88
92
  - [CI/CD recipes](https://yasserstudio.github.io/gpc/ci-cd/)
89
93
 
90
- Free to use. 1,999 tests. 90%+ coverage. Every write operation supports `--dry-run`.
94
+ Free to use. 2,076 tests. 90%+ coverage. Every write operation supports `--dry-run`.
91
95
 
92
96
  ## Licensing
93
97
 
@@ -58,9 +58,7 @@ async function cachedPackageNames() {
58
58
  }
59
59
  }
60
60
  async function readFreshStatusCache(packageName) {
61
- const entry = await readJson(
62
- join(getCacheDir(), `status-${packageName}.json`)
63
- );
61
+ const entry = await readJson(join(getCacheDir(), `status-${packageName}.json`));
64
62
  if (!entry?.fetchedAt) return null;
65
63
  const ttl = entry.ttl ?? 3600;
66
64
  const ageSec = (Date.now() - new Date(entry.fetchedAt).getTime()) / 1e3;
@@ -143,4 +141,4 @@ export {
143
141
  registerCompleteCommand,
144
142
  runContext
145
143
  };
146
- //# sourceMappingURL=__complete-QFD3SUAO.js.map
144
+ //# sourceMappingURL=__complete-AZXI2O25.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/__complete.ts"],"sourcesContent":["import { readFile, readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { Command } from \"commander\";\nimport { getCacheDir, getUserConfigPath, listProfiles } from \"@gpc-cli/config\";\n\n// Keep this file dependency-light on purpose.\n// It is called on every TAB press; loading @gpc-cli/api or @gpc-cli/auth would\n// blow the <100ms cold-start budget. Only pull from @gpc-cli/config + node:fs.\n\nconst STATIC_TRACKS = [\"production\", \"beta\", \"alpha\", \"internal\"] as const;\n\nconst DEBUG = process.env[\"GPC_DEBUG\"] === \"1\";\n\nfunction debug(msg: string): void {\n if (DEBUG) process.stderr.write(`[gpc __complete] ${msg}\\n`);\n}\n\n/** Emit one value per line; silent on any error. */\nfunction emit(values: readonly string[]): void {\n for (const v of values) {\n if (v) console.log(v);\n }\n}\n\n// Prototype-pollution defense: strip __proto__/constructor/prototype from\n// parsed JSON. Mirrors packages/config/src/loader.ts:92 so cache and config\n// files are treated consistently.\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\nfunction sanitize(obj: unknown): void {\n if (!obj || typeof obj !== \"object\") return;\n if (Array.isArray(obj)) {\n for (const item of obj) sanitize(item);\n return;\n }\n const record = obj as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n if (DANGEROUS_KEYS.has(key)) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete record[key];\n } else if (typeof record[key] === \"object\" && record[key] !== null) {\n sanitize(record[key]);\n }\n }\n}\n\nasync function readJson<T>(path: string): Promise<T | null> {\n try {\n const raw = await readFile(path, \"utf-8\");\n const parsed = JSON.parse(raw) as T;\n sanitize(parsed);\n return parsed;\n } catch (err) {\n // Silent fallback is by design (empty/stale cache is indistinguishable\n // from corrupt from the user's POV), but under GPC_DEBUG=1 surface the\n // error so authors can diagnose bad config or cache files.\n debug(`readJson(${path}) failed: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n}\n\ninterface ProfileEntry {\n app?: string;\n}\ninterface RawConfig {\n app?: string;\n profiles?: Record<string, ProfileEntry>;\n}\n\nasync function readProjectConfig(): Promise<RawConfig | null> {\n return readJson<RawConfig>(join(process.cwd(), \".gpcrc.json\"));\n}\n\nasync function readUserConfig(): Promise<RawConfig | null> {\n return readJson<RawConfig>(getUserConfigPath());\n}\n\nasync function cachedPackageNames(): Promise<string[]> {\n try {\n const entries = await readdir(getCacheDir());\n return entries\n .filter((f) => f.startsWith(\"status-\") && f.endsWith(\".json\"))\n .map((f) => f.slice(\"status-\".length, -\".json\".length));\n } catch {\n return [];\n }\n}\n\ninterface StatusCacheEntry {\n fetchedAt?: string;\n ttl?: number;\n data?: {\n releases?: Array<{ track?: string; versionCode?: string }>;\n };\n}\n\nasync function readFreshStatusCache(packageName: string): Promise<StatusCacheEntry | null> {\n const entry = await readJson<StatusCacheEntry>(join(getCacheDir(), `status-${packageName}.json`));\n if (!entry?.fetchedAt) return null;\n const ttl = entry.ttl ?? 3600;\n const ageSec = (Date.now() - new Date(entry.fetchedAt).getTime()) / 1000;\n if (ageSec > ttl) return null;\n return entry;\n}\n\nexport async function runContext(context: string, args: readonly string[] = []): Promise<string[]> {\n switch (context) {\n case \"profiles\":\n return completeProfiles();\n case \"packages\":\n return completePackages();\n case \"tracks-for-app\":\n return completeTracksForApp(args[0]);\n case \"releases-for-track\":\n return completeReleasesForTrack(args[0], args[1]);\n default:\n return [];\n }\n}\n\nexport async function completeProfiles(): Promise<string[]> {\n return listProfiles();\n}\n\nexport async function completePackages(): Promise<string[]> {\n const seen = new Set<string>();\n const [proj, user, cached] = await Promise.all([\n readProjectConfig(),\n readUserConfig(),\n cachedPackageNames(),\n ]);\n for (const cfg of [proj, user]) {\n if (cfg?.app) seen.add(cfg.app);\n if (cfg?.profiles) {\n for (const p of Object.values(cfg.profiles)) {\n if (p?.app) seen.add(p.app);\n }\n }\n }\n for (const pkg of cached) seen.add(pkg);\n return [...seen].sort();\n}\n\nexport async function completeTracksForApp(packageName: string | undefined): Promise<string[]> {\n const tracks = new Set<string>(STATIC_TRACKS);\n if (packageName) {\n const entry = await readFreshStatusCache(packageName);\n for (const r of entry?.data?.releases ?? []) {\n if (r.track) tracks.add(r.track);\n }\n } else {\n // No package arg: shell scripts don't currently parse the already-typed\n // --app value. As a best-effort, aggregate custom track names from every\n // fresh status cache so `gpc --track <TAB>` still surfaces non-standard\n // tracks the user has published to recently.\n const packages = await cachedPackageNames();\n const entries = await Promise.all(packages.map((p) => readFreshStatusCache(p)));\n for (const entry of entries) {\n for (const r of entry?.data?.releases ?? []) {\n if (r.track) tracks.add(r.track);\n }\n }\n }\n return [...tracks];\n}\n\nexport async function completeReleasesForTrack(\n packageName: string | undefined,\n track: string | undefined,\n): Promise<string[]> {\n if (!packageName || !track) return [];\n const entry = await readFreshStatusCache(packageName);\n return (entry?.data?.releases ?? [])\n .filter((r) => r.track === track && r.versionCode)\n .map((r) => r.versionCode as string);\n}\n\n/** Register the hidden `__complete` subcommand on the program. */\nexport function registerCompleteCommand(program: Command): void {\n const complete = new Command(\"__complete\")\n .description(\"Internal: shell completion value provider (hidden)\")\n .argument(\"<context>\", \"profiles | packages | tracks-for-app | releases-for-track\")\n .argument(\"[args...]\", \"Context-specific positional args\")\n .allowUnknownOption(true)\n .action(async (context: string, args: string[]) => {\n try {\n const values = await runContext(context, args);\n emit(values);\n } catch {\n // Never throw from a completion handler.\n }\n });\n\n program.addCommand(complete, { hidden: true });\n}\n"],"mappings":";;;AAAA,SAAS,UAAU,eAAe;AAClC,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,aAAa,mBAAmB,oBAAoB;AAM7D,IAAM,gBAAgB,CAAC,cAAc,QAAQ,SAAS,UAAU;AAEhE,IAAM,QAAQ,QAAQ,IAAI,WAAW,MAAM;AAE3C,SAAS,MAAM,KAAmB;AAChC,MAAI,MAAO,SAAQ,OAAO,MAAM,oBAAoB,GAAG;AAAA,CAAI;AAC7D;AAGA,SAAS,KAAK,QAAiC;AAC7C,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAG,SAAQ,IAAI,CAAC;AAAA,EACtB;AACF;AAKA,IAAM,iBAAiB,oBAAI,IAAI,CAAC,aAAa,eAAe,WAAW,CAAC;AACxE,SAAS,SAAS,KAAoB;AACpC,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU;AACrC,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,eAAW,QAAQ,IAAK,UAAS,IAAI;AACrC;AAAA,EACF;AACA,QAAM,SAAS;AACf,aAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,QAAI,eAAe,IAAI,GAAG,GAAG;AAE3B,aAAO,OAAO,GAAG;AAAA,IACnB,WAAW,OAAO,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,MAAM,MAAM;AAClE,eAAS,OAAO,GAAG,CAAC;AAAA,IACtB;AAAA,EACF;AACF;AAEA,eAAe,SAAY,MAAiC;AAC1D,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,MAAM,OAAO;AACxC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,aAAS,MAAM;AACf,WAAO;AAAA,EACT,SAAS,KAAK;AAIZ,UAAM,YAAY,IAAI,aAAa,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AACrF,WAAO;AAAA,EACT;AACF;AAUA,eAAe,oBAA+C;AAC5D,SAAO,SAAoB,KAAK,QAAQ,IAAI,GAAG,aAAa,CAAC;AAC/D;AAEA,eAAe,iBAA4C;AACzD,SAAO,SAAoB,kBAAkB,CAAC;AAChD;AAEA,eAAe,qBAAwC;AACrD,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,YAAY,CAAC;AAC3C,WAAO,QACJ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,KAAK,EAAE,SAAS,OAAO,CAAC,EAC5D,IAAI,CAAC,MAAM,EAAE,MAAM,UAAU,QAAQ,CAAC,QAAQ,MAAM,CAAC;AAAA,EAC1D,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAUA,eAAe,qBAAqB,aAAuD;AACzF,QAAM,QAAQ,MAAM,SAA2B,KAAK,YAAY,GAAG,UAAU,WAAW,OAAO,CAAC;AAChG,MAAI,CAAC,OAAO,UAAW,QAAO;AAC9B,QAAM,MAAM,MAAM,OAAO;AACzB,QAAM,UAAU,KAAK,IAAI,IAAI,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ,KAAK;AACpE,MAAI,SAAS,IAAK,QAAO;AACzB,SAAO;AACT;AAEA,eAAsB,WAAW,SAAiB,OAA0B,CAAC,GAAsB;AACjG,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO,iBAAiB;AAAA,IAC1B,KAAK;AACH,aAAO,iBAAiB;AAAA,IAC1B,KAAK;AACH,aAAO,qBAAqB,KAAK,CAAC,CAAC;AAAA,IACrC,KAAK;AACH,aAAO,yBAAyB,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC;AAAA,IAClD;AACE,aAAO,CAAC;AAAA,EACZ;AACF;AAEA,eAAsB,mBAAsC;AAC1D,SAAO,aAAa;AACtB;AAEA,eAAsB,mBAAsC;AAC1D,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,CAAC,MAAM,MAAM,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC7C,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,mBAAmB;AAAA,EACrB,CAAC;AACD,aAAW,OAAO,CAAC,MAAM,IAAI,GAAG;AAC9B,QAAI,KAAK,IAAK,MAAK,IAAI,IAAI,GAAG;AAC9B,QAAI,KAAK,UAAU;AACjB,iBAAW,KAAK,OAAO,OAAO,IAAI,QAAQ,GAAG;AAC3C,YAAI,GAAG,IAAK,MAAK,IAAI,EAAE,GAAG;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AACA,aAAW,OAAO,OAAQ,MAAK,IAAI,GAAG;AACtC,SAAO,CAAC,GAAG,IAAI,EAAE,KAAK;AACxB;AAEA,eAAsB,qBAAqB,aAAoD;AAC7F,QAAM,SAAS,IAAI,IAAY,aAAa;AAC5C,MAAI,aAAa;AACf,UAAM,QAAQ,MAAM,qBAAqB,WAAW;AACpD,eAAW,KAAK,OAAO,MAAM,YAAY,CAAC,GAAG;AAC3C,UAAI,EAAE,MAAO,QAAO,IAAI,EAAE,KAAK;AAAA,IACjC;AAAA,EACF,OAAO;AAKL,UAAM,WAAW,MAAM,mBAAmB;AAC1C,UAAM,UAAU,MAAM,QAAQ,IAAI,SAAS,IAAI,CAAC,MAAM,qBAAqB,CAAC,CAAC,CAAC;AAC9E,eAAW,SAAS,SAAS;AAC3B,iBAAW,KAAK,OAAO,MAAM,YAAY,CAAC,GAAG;AAC3C,YAAI,EAAE,MAAO,QAAO,IAAI,EAAE,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,SAAO,CAAC,GAAG,MAAM;AACnB;AAEA,eAAsB,yBACpB,aACA,OACmB;AACnB,MAAI,CAAC,eAAe,CAAC,MAAO,QAAO,CAAC;AACpC,QAAM,QAAQ,MAAM,qBAAqB,WAAW;AACpD,UAAQ,OAAO,MAAM,YAAY,CAAC,GAC/B,OAAO,CAAC,MAAM,EAAE,UAAU,SAAS,EAAE,WAAW,EAChD,IAAI,CAAC,MAAM,EAAE,WAAqB;AACvC;AAGO,SAAS,wBAAwB,SAAwB;AAC9D,QAAM,WAAW,IAAI,QAAQ,YAAY,EACtC,YAAY,oDAAoD,EAChE,SAAS,aAAa,2DAA2D,EACjF,SAAS,aAAa,kCAAkC,EACxD,mBAAmB,IAAI,EACvB,OAAO,OAAO,SAAiB,SAAmB;AACjD,QAAI;AACF,YAAM,SAAS,MAAM,WAAW,SAAS,IAAI;AAC7C,WAAK,MAAM;AAAA,IACb,QAAQ;AAAA,IAER;AAAA,EACF,CAAC;AAEH,UAAQ,WAAW,UAAU,EAAE,QAAQ,KAAK,CAAC;AAC/C;","names":[]}
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  isDryRun
4
4
  } from "./chunk-Y3QZDAKS.js";
5
- import {
6
- getOutputFormat
7
- } from "./chunk-ELXAK7GI.js";
8
5
  import {
9
6
  requireConfirm
10
7
  } from "./chunk-RZQSEDKI.js";
8
+ import {
9
+ getOutputFormat
10
+ } from "./chunk-ELXAK7GI.js";
11
11
 
12
12
  // src/commands/audit.ts
13
13
  import { loadConfig } from "@gpc-cli/config";
@@ -122,4 +122,4 @@ function registerAuditCommands(program) {
122
122
  export {
123
123
  registerAuditCommands
124
124
  };
125
- //# sourceMappingURL=audit-M7GYID74.js.map
125
+ //# sourceMappingURL=audit-BDPS5ODN.js.map
package/dist/bin.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  createProgram,
4
4
  handleCliError,
5
5
  loadPlugins
6
- } from "./chunk-QM5RTQ6R.js";
6
+ } from "./chunk-I3SFXLIY.js";
7
7
  import {
8
8
  checkForUpdate,
9
9
  formatUpdateNotification
@@ -57,7 +57,7 @@ if (!_isJsonMode && !_isQuiet && !_isSetupCommand && !existsSync(getUserConfigPa
57
57
  }
58
58
  await setupNetworking();
59
59
  initAudit(getConfigDir());
60
- var currentVersion = "0.9.62";
60
+ var currentVersion = "0.9.64";
61
61
  var isUpdateCommand = process.argv[2] === "update";
62
62
  var isCompletionProvider = process.argv[2] === "__complete";
63
63
  var updateCheckPromise = isUpdateCommand || isCompletionProvider ? Promise.resolve(null) : checkForUpdate(currentVersion);
@@ -0,0 +1,365 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getClient,
4
+ resolvePackageName
5
+ } from "./chunk-JDRY7HK5.js";
6
+ import {
7
+ dim,
8
+ yellow
9
+ } from "./chunk-FAN4ZITI.js";
10
+ import {
11
+ getOutputFormat
12
+ } from "./chunk-ELXAK7GI.js";
13
+
14
+ // src/commands/changelog.ts
15
+ import {
16
+ fetchChangelog,
17
+ formatChangelogEntry,
18
+ formatOutput,
19
+ generateChangelog,
20
+ RENDERERS,
21
+ renderPlayStore,
22
+ renderPlayStoreMd,
23
+ renderPlayStorePrompt,
24
+ buildLocaleBundle,
25
+ translateBundle,
26
+ resolveAiConfig,
27
+ createTranslator,
28
+ fetchAggregateCost,
29
+ formatPathLabel,
30
+ PROVIDER_WHITELIST,
31
+ resolveLocales,
32
+ validateBundleForApply,
33
+ bundleToReleaseNotes,
34
+ applyReleaseNotes,
35
+ GpcError
36
+ } from "@gpc-cli/core";
37
+ import { loadConfig } from "@gpc-cli/config";
38
+ var VALID_OUTPUT_MODES = ["md", "json", "prompt"];
39
+ var VALID_TARGETS = ["github", "play-store"];
40
+ var REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
41
+ async function performApply(ctx) {
42
+ const blocked = validateBundleForApply(ctx.bundle);
43
+ if (blocked.length > 0) {
44
+ process.stderr.write(
45
+ `Cannot --apply: ${blocked.length} locale(s) blocked:
46
+ ` + blocked.map((b) => ` ${b}`).join("\n") + "\n"
47
+ );
48
+ process.exitCode = 1;
49
+ return false;
50
+ }
51
+ const notes = bundleToReleaseNotes(ctx.bundle);
52
+ const config = await loadConfig();
53
+ const packageName = resolvePackageName(ctx.program.opts()["app"], config);
54
+ if (ctx.dryRun) {
55
+ const payload = {
56
+ dryRun: true,
57
+ action: "apply release notes",
58
+ track: ctx.track,
59
+ packageName,
60
+ localeCount: notes.length,
61
+ releaseNotes: notes
62
+ };
63
+ if (ctx.aiBlock) payload["ai"] = ctx.aiBlock;
64
+ console.log(JSON.stringify(payload, null, 2));
65
+ return false;
66
+ }
67
+ const client = await getClient(config);
68
+ const result = await applyReleaseNotes(client, packageName, ctx.track, notes);
69
+ process.stderr.write(
70
+ `${dim(`\u2192 Applied ${result.localeCount} locale(s) to draft on ${result.track} (${packageName})`)}
71
+ `
72
+ );
73
+ return true;
74
+ }
75
+ function registerChangelogCommand(program) {
76
+ const changelog = program.command("changelog").description("Show release history").option("-n, --limit <count>", "Number of releases to show", parseInt, 5).option("--tag <tag>", "Show a specific release (e.g., v0.9.43)").option("--all", "Show all releases").action(async (opts) => {
77
+ const config = await loadConfig();
78
+ const format = getOutputFormat(program, config);
79
+ const entries = await fetchChangelog({
80
+ limit: opts.all ? 100 : opts.limit,
81
+ version: opts.tag
82
+ });
83
+ if (entries.length === 0) {
84
+ console.log("No releases found.");
85
+ return;
86
+ }
87
+ if (format === "json") {
88
+ console.log(formatOutput(entries, "json"));
89
+ return;
90
+ }
91
+ if (opts.tag || entries.length === 1) {
92
+ console.log(formatChangelogEntry(entries[0]));
93
+ return;
94
+ }
95
+ const header = "VERSION DATE TITLE";
96
+ const separator = "\u2500".repeat(header.length);
97
+ console.log(header);
98
+ console.log(separator);
99
+ for (const entry of entries) {
100
+ const version = entry.version.padEnd(12);
101
+ const date = entry.date.padEnd(12);
102
+ console.log(`${version} ${date} ${entry.title}`);
103
+ }
104
+ console.log("");
105
+ console.log(
106
+ `Showing ${entries.length} releases. Use --tag <tag> for details, or --all for full history.`
107
+ );
108
+ });
109
+ changelog.command("generate").description("Generate release notes from local git commits").option("--from <ref>", "Starting ref (default: latest v* tag)").option("--to <ref>", "Ending ref (default: HEAD)").option("--format <mode>", "Renderer: md, json, or prompt", "md").option("--repo <owner/name>", "Override auto-detected repo (e.g., yasserstudio/gpc)").option("--target <mode>", "Output target: github or play-store", "github").option(
110
+ "--locales <csv|auto>",
111
+ "Comma-separated BCP 47 locales, or 'auto' (play-store target only)"
112
+ ).option("--ai", "Translate non-source locales via LLM (play-store target only, BYO key)").option(
113
+ "--provider <name>",
114
+ `AI provider (${PROVIDER_WHITELIST.join("|")}). Defaults to first env key detected`
115
+ ).option("--model <id>", "Override default model for the chosen provider").option("--strict", "Exit non-zero if warnings, overflows, or translation failures occur").option("--apply", "Write notes into the draft release on --track (play-store target only)").option("--track <name>", "Play Store track for --apply (default: production)", "production").action(
116
+ async (opts) => {
117
+ const dryRun = !!program.opts()["dryRun"];
118
+ const mode = opts.format;
119
+ if (!VALID_OUTPUT_MODES.includes(mode)) {
120
+ process.stderr.write(
121
+ `Invalid --format "${opts.format}". Valid: ${VALID_OUTPUT_MODES.join(", ")}
122
+ `
123
+ );
124
+ process.exitCode = 2;
125
+ return;
126
+ }
127
+ if (!VALID_TARGETS.includes(opts.target)) {
128
+ process.stderr.write(
129
+ `Invalid --target "${opts.target}". Valid: ${VALID_TARGETS.join(", ")}
130
+ `
131
+ );
132
+ process.exitCode = 2;
133
+ return;
134
+ }
135
+ const target = opts.target;
136
+ if (opts.repo && !REPO_RE.test(opts.repo)) {
137
+ process.stderr.write(
138
+ `Invalid --repo "${opts.repo}". Expected "owner/name" (e.g., yasserstudio/gpc).
139
+ `
140
+ );
141
+ process.exitCode = 2;
142
+ return;
143
+ }
144
+ if (target === "github" && opts.locales) {
145
+ process.stderr.write(
146
+ `--locales only applies to --target play-store (current target: github)
147
+ `
148
+ );
149
+ process.exitCode = 2;
150
+ return;
151
+ }
152
+ if (target === "github" && (opts.ai || opts.provider || opts.model)) {
153
+ process.stderr.write("--ai / --provider / --model only apply to --target play-store\n");
154
+ process.exitCode = 2;
155
+ return;
156
+ }
157
+ if (opts.ai && opts.format === "prompt" && !dryRun) {
158
+ process.stderr.write(
159
+ "--ai with --format prompt only makes sense with --dry-run\n (otherwise it would re-wrap translated text in a translation prompt).\n Hint: use --format md or --format json for live translation, or add --dry-run to inspect the prompt.\n"
160
+ );
161
+ process.exitCode = 2;
162
+ return;
163
+ }
164
+ if (opts.apply && target !== "play-store") {
165
+ process.stderr.write("--apply only applies to --target play-store\n");
166
+ process.exitCode = 2;
167
+ return;
168
+ }
169
+ if (opts.apply && mode === "prompt") {
170
+ process.stderr.write(
171
+ "--apply cannot be combined with --format prompt\n Hint: use --format md or --format json.\n"
172
+ );
173
+ process.exitCode = 2;
174
+ return;
175
+ }
176
+ if (target === "play-store" && !opts.locales) {
177
+ process.stderr.write(
178
+ "--target play-store requires --locales <csv|auto>\n Example: --locales en-US,fr-FR,de-DE\n Example: --locales auto (reads current Play Store listing \u2014 requires --app)\n"
179
+ );
180
+ process.exitCode = 2;
181
+ return;
182
+ }
183
+ const generated = await generateChangelog({
184
+ from: opts.from,
185
+ to: opts.to,
186
+ repo: opts.repo
187
+ });
188
+ for (const w of generated.warnings) {
189
+ process.stderr.write(`${yellow("warn:")} ${w}
190
+ `);
191
+ }
192
+ if (generated.warnings.length > 0) {
193
+ process.stderr.write(
194
+ `${dim(`(${generated.warnings.length} warning${generated.warnings.length === 1 ? "" : "s"} \u2014 review before publishing)`)}
195
+ `
196
+ );
197
+ }
198
+ if (target === "github") {
199
+ const output = RENDERERS[mode](generated);
200
+ console.log(output);
201
+ if (opts.strict && generated.warnings.length > 0) {
202
+ process.exitCode = 1;
203
+ }
204
+ return;
205
+ }
206
+ let locales;
207
+ try {
208
+ if (opts.locales === "auto") {
209
+ const config = await loadConfig();
210
+ const packageName = resolvePackageName(program.opts()["app"], config);
211
+ const client = await getClient(config);
212
+ locales = await resolveLocales("auto", { client, packageName });
213
+ } else {
214
+ locales = await resolveLocales(opts.locales);
215
+ }
216
+ } catch (error) {
217
+ if (error instanceof GpcError) {
218
+ process.stderr.write(`${error.message}
219
+ `);
220
+ if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}
221
+ `);
222
+ process.exitCode = error.exitCode;
223
+ return;
224
+ }
225
+ throw error;
226
+ }
227
+ const playStoreFormat = mode;
228
+ if (!opts.ai) {
229
+ const { output, bundle } = renderPlayStore(generated, {
230
+ locales,
231
+ format: playStoreFormat
232
+ });
233
+ console.log(output);
234
+ for (const lang of bundle.overflows) {
235
+ process.stderr.write(
236
+ `${yellow("warn:")} ${lang} exceeds ${bundle.limit} chars (truncated)
237
+ `
238
+ );
239
+ }
240
+ if (opts.apply) {
241
+ const ok = await performApply({ bundle, program, track: opts.track, dryRun });
242
+ if (!ok) return;
243
+ }
244
+ const hasOverflow2 = bundle.overflows.length > 0;
245
+ const hasWarnings2 = generated.warnings.length > 0;
246
+ if (opts.strict && (hasWarnings2 || hasOverflow2)) {
247
+ process.exitCode = 1;
248
+ }
249
+ return;
250
+ }
251
+ let aiConfig;
252
+ try {
253
+ aiConfig = resolveAiConfig({ provider: opts.provider, model: opts.model });
254
+ } catch (error) {
255
+ if (error instanceof GpcError) {
256
+ process.stderr.write(`${error.message}
257
+ `);
258
+ if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}
259
+ `);
260
+ process.exitCode = error.exitCode;
261
+ return;
262
+ }
263
+ throw error;
264
+ }
265
+ process.stderr.write(`${dim(`\u2192 ${formatPathLabel(aiConfig)}`)}
266
+ `);
267
+ const baseBundle = buildLocaleBundle(generated, {
268
+ locales,
269
+ format: playStoreFormat
270
+ });
271
+ if (dryRun) {
272
+ const preview = renderPlayStorePrompt(baseBundle, generated);
273
+ console.log(preview);
274
+ process.stderr.write(
275
+ `${dim("(--dry-run: no API call was made; the prompt above is what would be sent per locale)")}
276
+ `
277
+ );
278
+ return;
279
+ }
280
+ const translator = await createTranslator(aiConfig);
281
+ let translated;
282
+ try {
283
+ translated = await translateBundle(baseBundle, {
284
+ translator,
285
+ strict: opts.strict,
286
+ onError: ({ language, reason }) => {
287
+ process.stderr.write(
288
+ `${yellow("warn:")} ${language} translation failed: ${reason}
289
+ `
290
+ );
291
+ }
292
+ });
293
+ } catch (error) {
294
+ if (error instanceof GpcError) {
295
+ process.stderr.write(`${error.message}
296
+ `);
297
+ if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}
298
+ `);
299
+ process.exitCode = error.exitCode;
300
+ return;
301
+ }
302
+ throw error;
303
+ }
304
+ const costUsd = aiConfig.path === "gateway" ? await fetchAggregateCost(aiConfig.runId) : void 0;
305
+ const aiBlock = {
306
+ path: aiConfig.path,
307
+ provider: aiConfig.provider,
308
+ model: aiConfig.model,
309
+ tokensIn: translated.tokensIn,
310
+ tokensOut: translated.tokensOut
311
+ };
312
+ if (aiConfig.path === "gateway") {
313
+ aiBlock["runId"] = aiConfig.runId;
314
+ if (typeof costUsd === "number") aiBlock["costUsd"] = costUsd;
315
+ }
316
+ if (playStoreFormat === "json") {
317
+ const payload = {
318
+ from: translated.from,
319
+ to: translated.to,
320
+ limit: translated.limit,
321
+ sourceLanguage: translated.sourceLanguage,
322
+ ai: aiBlock,
323
+ locales: translated.locales,
324
+ overflows: translated.overflows,
325
+ failures: translated.failures
326
+ };
327
+ console.log(JSON.stringify(payload, null, 2));
328
+ } else if (playStoreFormat === "prompt") {
329
+ console.log(renderPlayStorePrompt(translated, generated));
330
+ } else {
331
+ console.log(renderPlayStoreMd(translated));
332
+ }
333
+ for (const lang of translated.overflows) {
334
+ process.stderr.write(
335
+ `${yellow("warn:")} ${lang} exceeds ${translated.limit} chars (truncated)
336
+ `
337
+ );
338
+ }
339
+ if (translated.failures.length > 0) {
340
+ process.stderr.write(
341
+ `${dim(`(${translated.failures.length} locale${translated.failures.length === 1 ? "" : "s"} failed \u2014 see placeholders in output)`)}
342
+ `
343
+ );
344
+ }
345
+ if (typeof costUsd === "number") {
346
+ process.stderr.write(`${dim(`(run cost: $${costUsd.toFixed(4)})`)}
347
+ `);
348
+ }
349
+ if (opts.apply) {
350
+ const ok = await performApply({ bundle: translated, program, track: opts.track, dryRun, aiBlock });
351
+ if (!ok) return;
352
+ }
353
+ const hasOverflow = translated.overflows.length > 0;
354
+ const hasWarnings = generated.warnings.length > 0;
355
+ const hasFailures = translated.failures.length > 0;
356
+ if (opts.strict && (hasWarnings || hasOverflow || hasFailures)) {
357
+ process.exitCode = 1;
358
+ }
359
+ }
360
+ );
361
+ }
362
+ export {
363
+ registerChangelogCommand
364
+ };
365
+ //# sourceMappingURL=changelog-EHQYZP22.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/changelog.ts"],"sourcesContent":["import type { Command } from \"commander\";\nimport {\n fetchChangelog,\n formatChangelogEntry,\n formatOutput,\n generateChangelog,\n RENDERERS,\n renderPlayStore,\n renderPlayStoreMd,\n renderPlayStorePrompt,\n buildLocaleBundle,\n translateBundle,\n resolveAiConfig,\n createTranslator,\n fetchAggregateCost,\n formatPathLabel,\n PROVIDER_WHITELIST,\n resolveLocales,\n validateBundleForApply,\n bundleToReleaseNotes,\n applyReleaseNotes,\n GpcError,\n type OutputMode,\n type PlayStoreFormat,\n} from \"@gpc-cli/core\";\nimport { loadConfig } from \"@gpc-cli/config\";\nimport { getOutputFormat } from \"../format.js\";\nimport { yellow, dim } from \"../colors.js\";\nimport { resolvePackageName, getClient } from \"../resolve.js\";\n\nconst VALID_OUTPUT_MODES: OutputMode[] = [\"md\", \"json\", \"prompt\"];\nconst VALID_TARGETS = [\"github\", \"play-store\"] as const;\ntype ChangelogTarget = (typeof VALID_TARGETS)[number];\nconst REPO_RE = /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/;\n\ninterface ApplyContext {\n bundle: Parameters<typeof validateBundleForApply>[0];\n program: Command;\n track: string;\n dryRun: boolean;\n aiBlock?: Record<string, unknown>;\n}\n\nasync function performApply(ctx: ApplyContext): Promise<boolean> {\n const blocked = validateBundleForApply(ctx.bundle);\n if (blocked.length > 0) {\n process.stderr.write(\n `Cannot --apply: ${blocked.length} locale(s) blocked:\\n` +\n blocked.map((b) => ` ${b}`).join(\"\\n\") +\n \"\\n\",\n );\n process.exitCode = 1;\n return false;\n }\n const notes = bundleToReleaseNotes(ctx.bundle);\n const config = await loadConfig();\n const packageName = resolvePackageName(ctx.program.opts()[\"app\"], config);\n if (ctx.dryRun) {\n const payload: Record<string, unknown> = {\n dryRun: true, action: \"apply release notes\", track: ctx.track,\n packageName, localeCount: notes.length, releaseNotes: notes,\n };\n if (ctx.aiBlock) payload[\"ai\"] = ctx.aiBlock;\n console.log(JSON.stringify(payload, null, 2));\n return false;\n }\n const client = await getClient(config);\n const result = await applyReleaseNotes(client, packageName, ctx.track, notes);\n process.stderr.write(\n `${dim(`→ Applied ${result.localeCount} locale(s) to draft on ${result.track} (${packageName})`)}\\n`,\n );\n return true;\n}\n\nexport function registerChangelogCommand(program: Command): void {\n const changelog = program\n .command(\"changelog\")\n .description(\"Show release history\")\n .option(\"-n, --limit <count>\", \"Number of releases to show\", parseInt, 5)\n .option(\"--tag <tag>\", \"Show a specific release (e.g., v0.9.43)\")\n .option(\"--all\", \"Show all releases\")\n .action(async (opts: { limit: number; tag?: string; all?: boolean }) => {\n const config = await loadConfig();\n const format = getOutputFormat(program, config);\n\n const entries = await fetchChangelog({\n limit: opts.all ? 100 : opts.limit,\n version: opts.tag,\n });\n\n if (entries.length === 0) {\n console.log(\"No releases found.\");\n return;\n }\n\n if (format === \"json\") {\n console.log(formatOutput(entries, \"json\"));\n return;\n }\n\n if (opts.tag || entries.length === 1) {\n console.log(formatChangelogEntry(entries[0]!));\n return;\n }\n\n const header = \"VERSION DATE TITLE\";\n const separator = \"─\".repeat(header.length);\n console.log(header);\n console.log(separator);\n for (const entry of entries) {\n const version = entry.version.padEnd(12);\n const date = entry.date.padEnd(12);\n console.log(`${version} ${date} ${entry.title}`);\n }\n console.log(\"\");\n console.log(\n `Showing ${entries.length} releases. Use --tag <tag> for details, or --all for full history.`,\n );\n });\n\n changelog\n .command(\"generate\")\n .description(\"Generate release notes from local git commits\")\n .option(\"--from <ref>\", \"Starting ref (default: latest v* tag)\")\n .option(\"--to <ref>\", \"Ending ref (default: HEAD)\")\n .option(\"--format <mode>\", \"Renderer: md, json, or prompt\", \"md\")\n .option(\"--repo <owner/name>\", \"Override auto-detected repo (e.g., yasserstudio/gpc)\")\n .option(\"--target <mode>\", \"Output target: github or play-store\", \"github\")\n .option(\n \"--locales <csv|auto>\",\n \"Comma-separated BCP 47 locales, or 'auto' (play-store target only)\",\n )\n .option(\"--ai\", \"Translate non-source locales via LLM (play-store target only, BYO key)\")\n .option(\n \"--provider <name>\",\n `AI provider (${PROVIDER_WHITELIST.join(\"|\")}). Defaults to first env key detected`,\n )\n .option(\"--model <id>\", \"Override default model for the chosen provider\")\n .option(\"--strict\", \"Exit non-zero if warnings, overflows, or translation failures occur\")\n .option(\"--apply\", \"Write notes into the draft release on --track (play-store target only)\")\n .option(\"--track <name>\", \"Play Store track for --apply (default: production)\", \"production\")\n .action(\n async (opts: {\n from?: string;\n to?: string;\n format: string;\n repo?: string;\n target: string;\n locales?: string;\n strict?: boolean;\n ai?: boolean;\n provider?: string;\n model?: string;\n apply?: boolean;\n track: string;\n }) => {\n const dryRun = !!program.opts()[\"dryRun\"];\n const mode = opts.format as OutputMode;\n if (!VALID_OUTPUT_MODES.includes(mode)) {\n process.stderr.write(\n `Invalid --format \"${opts.format}\". Valid: ${VALID_OUTPUT_MODES.join(\", \")}\\n`,\n );\n process.exitCode = 2;\n return;\n }\n if (!VALID_TARGETS.includes(opts.target as ChangelogTarget)) {\n process.stderr.write(\n `Invalid --target \"${opts.target}\". Valid: ${VALID_TARGETS.join(\", \")}\\n`,\n );\n process.exitCode = 2;\n return;\n }\n const target = opts.target as ChangelogTarget;\n if (opts.repo && !REPO_RE.test(opts.repo)) {\n process.stderr.write(\n `Invalid --repo \"${opts.repo}\". Expected \"owner/name\" (e.g., yasserstudio/gpc).\\n`,\n );\n process.exitCode = 2;\n return;\n }\n if (target === \"github\" && opts.locales) {\n process.stderr.write(\n `--locales only applies to --target play-store (current target: github)\\n`,\n );\n process.exitCode = 2;\n return;\n }\n // Only block when the AI-adjacent flags are explicitly set. The root\n // program has its own `--dry-run` flag that may already be set\n // globally by the user for unrelated reasons; we silently ignore it\n // on non-AI code paths.\n if (target === \"github\" && (opts.ai || opts.provider || opts.model)) {\n process.stderr.write(\"--ai / --provider / --model only apply to --target play-store\\n\");\n process.exitCode = 2;\n return;\n }\n // --format prompt + --ai is nonsensical outside --dry-run: it would\n // render a \"please translate this\" prompt from already-translated\n // text. Either inspect the prompt via --dry-run, or pick md/json.\n if (opts.ai && opts.format === \"prompt\" && !dryRun) {\n process.stderr.write(\n \"--ai with --format prompt only makes sense with --dry-run\\n\" +\n \" (otherwise it would re-wrap translated text in a translation prompt).\\n\" +\n \" Hint: use --format md or --format json for live translation, or add --dry-run to inspect the prompt.\\n\",\n );\n process.exitCode = 2;\n return;\n }\n if (opts.apply && target !== \"play-store\") {\n process.stderr.write(\"--apply only applies to --target play-store\\n\");\n process.exitCode = 2;\n return;\n }\n if (opts.apply && mode === \"prompt\") {\n process.stderr.write(\n \"--apply cannot be combined with --format prompt\\n\" +\n \" Hint: use --format md or --format json.\\n\",\n );\n process.exitCode = 2;\n return;\n }\n if (target === \"play-store\" && !opts.locales) {\n process.stderr.write(\n \"--target play-store requires --locales <csv|auto>\\n\" +\n \" Example: --locales en-US,fr-FR,de-DE\\n\" +\n \" Example: --locales auto (reads current Play Store listing — requires --app)\\n\",\n );\n process.exitCode = 2;\n return;\n }\n\n const generated = await generateChangelog({\n from: opts.from,\n to: opts.to,\n repo: opts.repo,\n });\n\n for (const w of generated.warnings) {\n process.stderr.write(`${yellow(\"warn:\")} ${w}\\n`);\n }\n if (generated.warnings.length > 0) {\n process.stderr.write(\n `${dim(`(${generated.warnings.length} warning${generated.warnings.length === 1 ? \"\" : \"s\"} — review before publishing)`)}\\n`,\n );\n }\n\n if (target === \"github\") {\n const output = RENDERERS[mode](generated);\n console.log(output);\n if (opts.strict && generated.warnings.length > 0) {\n process.exitCode = 1;\n }\n return;\n }\n\n // target === \"play-store\"\n let locales: string[];\n try {\n if (opts.locales === \"auto\") {\n const config = await loadConfig();\n const packageName = resolvePackageName(program.opts()[\"app\"], config);\n const client = await getClient(config);\n locales = await resolveLocales(\"auto\", { client, packageName });\n } else {\n locales = await resolveLocales(opts.locales!);\n }\n } catch (error) {\n if (error instanceof GpcError) {\n process.stderr.write(`${error.message}\\n`);\n if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}\\n`);\n process.exitCode = error.exitCode;\n return;\n }\n throw error;\n }\n\n const playStoreFormat = mode as PlayStoreFormat;\n\n // Non-AI path: existing v0.9.62 behavior\n if (!opts.ai) {\n const { output, bundle } = renderPlayStore(generated, {\n locales,\n format: playStoreFormat,\n });\n console.log(output);\n\n for (const lang of bundle.overflows) {\n process.stderr.write(\n `${yellow(\"warn:\")} ${lang} exceeds ${bundle.limit} chars (truncated)\\n`,\n );\n }\n\n if (opts.apply) {\n const ok = await performApply({ bundle, program, track: opts.track, dryRun });\n if (!ok) return;\n }\n\n const hasOverflow = bundle.overflows.length > 0;\n const hasWarnings = generated.warnings.length > 0;\n if (opts.strict && (hasWarnings || hasOverflow)) {\n process.exitCode = 1;\n }\n return;\n }\n\n // --ai path: resolve config, translate, render with ai block\n let aiConfig;\n try {\n aiConfig = resolveAiConfig({ provider: opts.provider, model: opts.model });\n } catch (error) {\n if (error instanceof GpcError) {\n process.stderr.write(`${error.message}\\n`);\n if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}\\n`);\n process.exitCode = error.exitCode;\n return;\n }\n throw error;\n }\n\n process.stderr.write(`${dim(`→ ${formatPathLabel(aiConfig)}`)}\\n`);\n\n const baseBundle = buildLocaleBundle(generated, {\n locales,\n format: playStoreFormat,\n });\n\n if (dryRun) {\n const preview = renderPlayStorePrompt(baseBundle, generated);\n console.log(preview);\n process.stderr.write(\n `${dim(\"(--dry-run: no API call was made; the prompt above is what would be sent per locale)\")}\\n`,\n );\n return;\n }\n\n const translator = await createTranslator(aiConfig);\n let translated;\n try {\n translated = await translateBundle(baseBundle, {\n translator,\n strict: opts.strict,\n onError: ({ language, reason }) => {\n process.stderr.write(\n `${yellow(\"warn:\")} ${language} translation failed: ${reason}\\n`,\n );\n },\n });\n } catch (error) {\n if (error instanceof GpcError) {\n process.stderr.write(`${error.message}\\n`);\n if (error.suggestion) process.stderr.write(`${dim(error.suggestion)}\\n`);\n process.exitCode = error.exitCode;\n return;\n }\n throw error;\n }\n\n const costUsd =\n aiConfig.path === \"gateway\" ? await fetchAggregateCost(aiConfig.runId) : undefined;\n\n const aiBlock: Record<string, unknown> = {\n path: aiConfig.path,\n provider: aiConfig.provider,\n model: aiConfig.model,\n tokensIn: translated.tokensIn,\n tokensOut: translated.tokensOut,\n };\n if (aiConfig.path === \"gateway\") {\n aiBlock[\"runId\"] = aiConfig.runId;\n if (typeof costUsd === \"number\") aiBlock[\"costUsd\"] = costUsd;\n }\n\n if (playStoreFormat === \"json\") {\n const payload = {\n from: translated.from,\n to: translated.to,\n limit: translated.limit,\n sourceLanguage: translated.sourceLanguage,\n ai: aiBlock,\n locales: translated.locales,\n overflows: translated.overflows,\n failures: translated.failures,\n };\n console.log(JSON.stringify(payload, null, 2));\n } else if (playStoreFormat === \"prompt\") {\n console.log(renderPlayStorePrompt(translated, generated));\n } else {\n console.log(renderPlayStoreMd(translated));\n }\n\n for (const lang of translated.overflows) {\n process.stderr.write(\n `${yellow(\"warn:\")} ${lang} exceeds ${translated.limit} chars (truncated)\\n`,\n );\n }\n\n if (translated.failures.length > 0) {\n process.stderr.write(\n `${dim(`(${translated.failures.length} locale${translated.failures.length === 1 ? \"\" : \"s\"} failed — see placeholders in output)`)}\\n`,\n );\n }\n\n if (typeof costUsd === \"number\") {\n process.stderr.write(`${dim(`(run cost: $${costUsd.toFixed(4)})`)}\\n`);\n }\n\n if (opts.apply) {\n const ok = await performApply({ bundle: translated, program, track: opts.track, dryRun, aiBlock });\n if (!ok) return;\n }\n\n const hasOverflow = translated.overflows.length > 0;\n const hasWarnings = generated.warnings.length > 0;\n const hasFailures = translated.failures.length > 0;\n if (opts.strict && (hasWarnings || hasOverflow || hasFailures)) {\n process.exitCode = 1;\n }\n },\n );\n}\n"],"mappings":"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","names":["hasOverflow","hasWarnings"]}